diff --git a/drivers/media/dvb-frontends/cx24117.c b/drivers/media/dvb-frontends/cx24117.c index 3b6391352918..908730959e38 100644 --- a/drivers/media/dvb-frontends/cx24117.c +++ b/drivers/media/dvb-frontends/cx24117.c @@ -31,6 +31,7 @@ #include #include +#include "tuner-i2c.h" #include "dvb_frontend.h" #include "cx24117.h" @@ -145,6 +146,9 @@ enum cmds { CMD_TUNERSLEEP = 0x36, }; +static LIST_HEAD(hybrid_tuner_instance_list); +static DEFINE_MUTEX(cx24117_list_mutex); + /* The Demod/Tuner can't easily provide these, we cache them */ struct cx24117_tuning { u32 frequency; @@ -176,9 +180,11 @@ struct cx24117_priv { u8 demod_address; struct i2c_adapter *i2c; u8 skip_fw_load; - struct mutex fe_lock; - atomic_t fe_nr; + + /* Used for sharing this struct between demods */ + struct tuner_i2c_props i2c_props; + struct list_head hybrid_tuner_instance_list; }; /* one per each fe */ @@ -536,7 +542,7 @@ static int cx24117_load_firmware(struct dvb_frontend *fe, dev_dbg(&state->priv->i2c->dev, "%s() demod%d FW is %zu bytes (%02x %02x .. %02x %02x)\n", __func__, state->demod, fw->size, fw->data[0], fw->data[1], - fw->data[fw->size-2], fw->data[fw->size-1]); + fw->data[fw->size - 2], fw->data[fw->size - 1]); cx24117_writereg(state, 0xea, 0x00); cx24117_writereg(state, 0xea, 0x01); @@ -1116,37 +1122,64 @@ static int cx24117_diseqc_send_burst(struct dvb_frontend *fe, return 0; } +static int cx24117_get_priv(struct cx24117_priv **priv, + struct i2c_adapter *i2c, u8 client_address) +{ + int ret; + + mutex_lock(&cx24117_list_mutex); + ret = hybrid_tuner_request_state(struct cx24117_priv, (*priv), + hybrid_tuner_instance_list, i2c, client_address, "cx24117"); + mutex_unlock(&cx24117_list_mutex); + + return ret; +} + +static void cx24117_release_priv(struct cx24117_priv *priv) +{ + mutex_lock(&cx24117_list_mutex); + if (priv != NULL) + hybrid_tuner_release_state(priv); + mutex_unlock(&cx24117_list_mutex); +} + static void cx24117_release(struct dvb_frontend *fe) { struct cx24117_state *state = fe->demodulator_priv; dev_dbg(&state->priv->i2c->dev, "%s demod%d\n", __func__, state->demod); - if (!atomic_dec_and_test(&state->priv->fe_nr)) - kfree(state->priv); + cx24117_release_priv(state->priv); kfree(state); } static struct dvb_frontend_ops cx24117_ops; struct dvb_frontend *cx24117_attach(const struct cx24117_config *config, - struct i2c_adapter *i2c, struct dvb_frontend *fe) + struct i2c_adapter *i2c) { struct cx24117_state *state = NULL; struct cx24117_priv *priv = NULL; int demod = 0; - /* first frontend attaching */ - /* allocate shared priv struct */ - if (fe == NULL) { - priv = kzalloc(sizeof(struct cx24117_priv), GFP_KERNEL); - if (priv == NULL) - goto error1; + /* get the common data struct for both demods */ + demod = cx24117_get_priv(&priv, i2c, config->demod_address); + + switch (demod) { + case 0: + dev_err(&state->priv->i2c->dev, + "%s: Error attaching frontend %d\n", + KBUILD_MODNAME, demod); + goto error1; + break; + case 1: + /* new priv instance */ priv->i2c = i2c; priv->demod_address = config->demod_address; mutex_init(&priv->fe_lock); - } else { - demod = 1; - priv = ((struct cx24117_state *) fe->demodulator_priv)->priv; + break; + default: + /* existing priv instance */ + break; } /* allocate memory for the internal state */ @@ -1154,7 +1187,7 @@ struct dvb_frontend *cx24117_attach(const struct cx24117_config *config, if (state == NULL) goto error2; - state->demod = demod; + state->demod = demod - 1; state->priv = priv; /* test i2c bus for ack */ @@ -1163,12 +1196,9 @@ struct dvb_frontend *cx24117_attach(const struct cx24117_config *config, goto error3; } - /* nr of frontends using the module */ - atomic_inc(&priv->fe_nr); - dev_info(&state->priv->i2c->dev, "%s: Attaching frontend %d\n", - KBUILD_MODNAME, demod); + KBUILD_MODNAME, state->demod); /* create dvb_frontend */ memcpy(&state->frontend.ops, &cx24117_ops, @@ -1179,7 +1209,7 @@ struct dvb_frontend *cx24117_attach(const struct cx24117_config *config, error3: kfree(state); error2: - kfree(priv); + cx24117_release_priv(priv); error1: return NULL; } diff --git a/drivers/media/dvb-frontends/cx24117.h b/drivers/media/dvb-frontends/cx24117.h index 5bc8f1119275..4e59e9574fa7 100644 --- a/drivers/media/dvb-frontends/cx24117.h +++ b/drivers/media/dvb-frontends/cx24117.h @@ -33,11 +33,11 @@ struct cx24117_config { #if IS_ENABLED(CONFIG_DVB_CX24117) extern struct dvb_frontend *cx24117_attach( const struct cx24117_config *config, - struct i2c_adapter *i2c, struct dvb_frontend *fe); + struct i2c_adapter *i2c); #else static inline struct dvb_frontend *cx24117_attach( const struct cx24117_config *config, - struct i2c_adapter *i2c, struct dvb_frontend *fe) + struct i2c_adapter *i2c) { dev_warn(&i2c->dev, "%s: driver disabled by Kconfig\n", __func__); return NULL; diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c index 34120db1f51f..05492053b473 100644 --- a/drivers/media/pci/cx23885/cx23885-dvb.c +++ b/drivers/media/pci/cx23885/cx23885-dvb.c @@ -1058,20 +1058,13 @@ static int dvb_register(struct cx23885_tsport *port) case 1: fe0->dvb.frontend = dvb_attach(cx24117_attach, &tbs_cx24117_config, - &i2c_bus->i2c_adap, NULL); + &i2c_bus->i2c_adap); break; /* PORT C */ case 2: - /* use fe1 pointer as temporary holder */ - /* for the first frontend */ - fe1 = videobuf_dvb_get_frontend( - &port->dev->ts1.frontends, 1); - fe0->dvb.frontend = dvb_attach(cx24117_attach, &tbs_cx24117_config, - &i2c_bus->i2c_adap, fe1->dvb.frontend); - /* we're done, so clear fe1 pointer */ - fe1 = NULL; + &i2c_bus->i2c_adap); break; } break;