Mailing List archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[linux-dvb] [patch] kernel i2c - alps_tdmb7



Hi!

Here is another one, it's pretty straight forward, and should work ok. Would 
still be nice if someone with this frontend could test it though.

I'm wondering about this case though, it's highly unlikly to happen, but if 
the i2c_attach_client succeds and dvb_register_frontend_new fails, I belive 
that state and client will be double free'd. Something like this is used in 
most of the converted frontends (exceptions: stv0299/ves1x93, which looks 
like they'll leak state on detach_client).

Kenneth

static int attach_adapter(struct i2c_adapter *i2c)
{
	.....blah....
       ret = i2c_attach_client(client);
       if (ret) {
               kfree(state);
               kfree(client);
               return ret;
       }

       BUG_ON(!state->dvb);

       ret = dvb_register_frontend_new (tdmb7_ioctl, state->dvb, state, 
&tdmb7_info);
       if (ret) {
               i2c_detach_client(client);
               kfree(state);
               kfree(client);
               return ret;
      	}
}

static int detach_client (struct i2c_client *client)
 {
       struct tdmb7_state *state = i2c_get_clientdata(client);
       dvb_unregister_frontend_new (tdmb7_ioctl, state->dvb);
       i2c_detach_client(client);
       BUG_ON(state->dvb);
       kfree(client);
       kfree(state);
       return 0;
}
Index: linux/drivers/media/dvb/frontends/alps_tdmb7.c
===================================================================
RCS file: /cvs/linuxtv/dvb-kernel/linux/drivers/media/dvb/frontends/alps_tdmb7.c,v
retrieving revision 1.25
diff -u -r1.25 alps_tdmb7.c
--- linux/drivers/media/dvb/frontends/alps_tdmb7.c	25 Mar 2004 19:07:25 -0000	1.25
+++ linux/drivers/media/dvb/frontends/alps_tdmb7.c	22 Jun 2004 10:52:16 -0000
@@ -33,6 +33,8 @@
 static int debug = 0;
 #define dprintk	if (debug) printk
 
+// FIXME: Move to i2c-id.h
+#define I2C_DRIVERID_DVBFE_TDMB7 I2C_DRIVERID_EXP0
 
 static struct dvb_frontend_info tdmb7_info = {
 	.name 			= "Alps TDMB7",
@@ -53,6 +55,10 @@
               FE_CAN_RECOVER
 };
 
+struct tdmb7_state {
+	struct i2c_adapter *i2c;
+	struct dvb_adapter *dvb;
+};
 
 static u8 init_tab [] = {
 	0x04, 0x10,
@@ -76,7 +82,7 @@
 };
 
 
-static int cx22700_writereg (struct dvb_i2c_bus *i2c, u8 reg, u8 data)
+static int cx22700_writereg (struct i2c_adapter *i2c, u8 reg, u8 data)
 {
 	int ret;
 	u8 buf [] = { reg, data };
@@ -84,7 +90,7 @@
 
 	dprintk ("%s\n", __FUNCTION__);
 
-	ret = i2c->xfer (i2c, &msg, 1);
+	ret = i2c_transfer (i2c, &msg, 1);
 
 	if (ret != 1)
 		printk("%s: writereg error (reg == 0x%02x, val == 0x%02x, ret == %i)\n",
@@ -94,7 +100,7 @@
 }
 
 
-static u8 cx22700_readreg (struct dvb_i2c_bus *i2c, u8 reg)
+static u8 cx22700_readreg (struct i2c_adapter *i2c, u8 reg)
 {
 	int ret;
 	u8 b0 [] = { reg };
@@ -104,7 +110,7 @@
 
 	dprintk ("%s\n", __FUNCTION__);
 
-	ret = i2c->xfer (i2c, msg, 2);
+	ret = i2c_transfer (i2c, msg, 2);
 
 	if (ret != 2)
 		printk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
@@ -113,13 +119,13 @@
 }
 
 
-static int pll_write (struct dvb_i2c_bus *i2c, u8 data [4])
+static int pll_write (struct i2c_adapter *i2c, u8 data [4])
 {
 	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = 4 };
 	int ret;
 
 	cx22700_writereg (i2c, 0x0a, 0x00);  /* open i2c bus switch */
-	ret = i2c->xfer (i2c, &msg, 1);
+	ret = i2c_transfer (i2c, &msg, 1);
 	cx22700_writereg (i2c, 0x0a, 0x01);  /* close i2c bus switch */
 
 	if (ret != 1)
@@ -133,7 +139,7 @@
  *   set up the downconverter frequency divisor for a
  *   reference clock comparision frequency of 125 kHz.
  */
-static int pll_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq)
+static int pll_set_tv_freq (struct i2c_adapter *i2c, u32 freq)
 {
 	u32 div = (freq + 36166667) / 166667;
 #if 1 //ALPS_SETTINGS
@@ -150,7 +156,7 @@
 }
 
 
-static int cx22700_init (struct dvb_i2c_bus *i2c)
+static int cx22700_init (struct i2c_adapter *i2c)
 {
 	int i;
 
@@ -170,7 +176,7 @@
 }
 
 
-static int cx22700_set_inversion (struct dvb_i2c_bus *i2c, int inversion)
+static int cx22700_set_inversion (struct i2c_adapter *i2c, int inversion)
 {
 	u8 val;
 
@@ -191,7 +197,7 @@
 }
 
 
-static int cx22700_set_tps (struct dvb_i2c_bus *i2c, struct dvb_ofdm_parameters *p)
+static int cx22700_set_tps (struct i2c_adapter *i2c, struct dvb_ofdm_parameters *p)
 {
 	static const u8 qam_tab [4] = { 0, 1, 0, 2 };
 	static const u8 fec_tab [6] = { 0, 1, 2, 0, 3, 4 };
@@ -254,7 +260,7 @@
 }
 
 
-static int cx22700_get_tps (struct dvb_i2c_bus *i2c, struct dvb_ofdm_parameters *p)
+static int cx22700_get_tps (struct i2c_adapter *i2c, struct dvb_ofdm_parameters *p)
 {
 	static const fe_modulation_t qam_tab [3] = { QPSK, QAM_16, QAM_64 };
 	static const fe_code_rate_t fec_tab [5] = { FEC_1_2, FEC_2_3, FEC_3_4,
@@ -303,7 +309,8 @@
 
 static int tdmb7_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
 {
-	struct dvb_i2c_bus *i2c = fe->i2c;
+	struct tdmb7_state *state = fe->data;
+	struct i2c_adapter *i2c = state->i2c;
 
 	dprintk ("%s\n", __FUNCTION__);
 
@@ -406,45 +413,123 @@
 	return 0;
 }
 
+static struct i2c_client client_template;
 
-
-static int tdmb7_attach (struct dvb_i2c_bus *i2c, void **data)
+static int attach_adapter (struct i2c_adapter *adapter)
 {
-        u8 b0 [] = { 0x7 };
-        u8 b1 [] = { 0 };
-        struct i2c_msg msg [] = { { .addr = 0x43, .flags = 0, .buf = b0, .len = 1 },
-                                  { .addr = 0x43, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
+	struct tdmb7_state *state;
+	struct i2c_client *client;
+	int ret;
+
+	u8 b0 [] = { 0x7 };
+	u8 b1 [] = { 0 };
+	struct i2c_msg msg [] = { { .addr = 0x43, .flags = 0, .buf = b0, .len = 1 },
+				  { .addr = 0x43, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
+
+	dprintk ("%s\n", __FUNCTION__);
+
+	if (i2c_transfer(adapter, msg, 2) != 2)
+		return -ENODEV;
 
-        dprintk ("%s\n", __FUNCTION__);
+	if (NULL == (state = kmalloc(sizeof(struct tdmb7_state), GFP_KERNEL)))
+		return -ENOMEM;
 
-        if (i2c->xfer (i2c, msg, 2) != 2)
-                      return -ENODEV;
+	state->i2c = adapter;
 
-        return dvb_register_frontend (tdmb7_ioctl, i2c, NULL, &tdmb7_info);
+	if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
+		kfree(state);
+		return -ENOMEM;
+	}
+
+	memcpy(client, &client_template, sizeof(struct i2c_client));
+	client->adapter = adapter;
+	i2c_set_clientdata(client, state);
+
+	ret = i2c_attach_client(client);
+	if (ret) {
+		kfree(state);
+		kfree(client);
+		return ret;
+	}
+
+	BUG_ON(!state->dvb);
+
+	ret = dvb_register_frontend_new (tdmb7_ioctl, state->dvb, state, &tdmb7_info);
+	if (ret) {
+		i2c_detach_client(client);
+		kfree(state);
+		kfree(client);
+		return ret;
+	}
+
+	return 0;
 }
 
 
-static void tdmb7_detach (struct dvb_i2c_bus *i2c, void *data)
+static int detach_client (struct i2c_client *client)
 {
+	struct tdmb7_state *state = i2c_get_clientdata(client);
+
 	dprintk ("%s\n", __FUNCTION__);
 
-	dvb_unregister_frontend (tdmb7_ioctl, i2c);
+	dvb_unregister_frontend_new (tdmb7_ioctl, state->dvb);
+	i2c_detach_client(client);
+	BUG_ON(state->dvb);
+	kfree(client);
+	kfree(state);
+	return 0;
+}
+
+static int command (struct i2c_client *client,
+		    unsigned int cmd, void *arg)
+{
+	struct tdmb7_state *state = i2c_get_clientdata(client);
+
+	dprintk("%s\n", __FUNCTION__);
+
+	switch (cmd) {
+	case FE_REGISTER:
+		state->dvb = arg;
+		break;
+	case FE_UNREGISTER:
+		state->dvb = NULL;
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
 }
 
+static struct i2c_driver driver = {
+	.owner		= THIS_MODULE,
+	.name		= "dvbfe-tdmb7",
+	.id		= I2C_DRIVERID_DVBFE_TDMB7,
+	.flags		= I2C_DF_NOTIFY,
+	.attach_adapter	= attach_adapter,
+	.detach_client	= detach_client,
+	.command	= command,
+};
+
+static struct i2c_client client_template = {
+	I2C_DEVNAME("dvbfe-tdmb7"),
+	.flags		= I2C_CLIENT_ALLOW_USE,
+	.driver		= &driver,
+};
 
 static int __init init_tdmb7 (void)
 {
 	dprintk ("%s\n", __FUNCTION__);
 
-	return dvb_register_i2c_device (THIS_MODULE, tdmb7_attach, tdmb7_detach);
+	return i2c_add_driver(&driver);
 }
 
-
 static void __exit exit_tdmb7 (void)
 {
 	dprintk ("%s\n", __FUNCTION__);
 
-	dvb_unregister_i2c_device (tdmb7_attach);
+	if (i2c_del_driver(&driver))
+		printk(KERN_ERR "alps_tdmb7: driver deregistration failed.\n");
 }
 
 module_init (init_tdmb7);

Home | Main Index | Thread Index