Mailing List archive

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

[linux-dvb] Re: Proposal for new frontend architecture



Hi,

On 23.09.2004 16:40, Gerd Knorr wrote:
To throw some real code into the discussion:  I've implemented that as
proof-of-concept for cx88-dvb adapter with cx22702 frontent.  The code
can be found in the latest video4linux cvs snapshot

	=> http://dl.bytesex.org/cvs-snapshots/

FE_REGISTER is gone, no autoprobing, uses kernel i2c everythere,
registeres the clients so it is nicely visible in sysfs.  I've also
reworked the driver in general.
I was just about to finish my proof-of-concept on the stv0299 driver. Grrr... ;-)

Havn't tried to split away the pll code yet.  The functions to program
the pll are pretty generic now through, they can likely moved to some
pll library module (and then shared with other fe drivers) without much
trouble.
I still dislike the idea of a functional dependency between the dvb driver and the demod driver, so I tried to merge my stv0299 approach with your patch. It's only compile-tested, so no guarantee. Please have a look at the attached patches.

cx88-dvb.c does an explicit request_module("cx22702") to make sure the frontend is there. Next, it uses the new i2c_connect_client() function.

int i2c_connect_client(struct i2c_adapter *adap, int id, void *interface, struct i2c_client **client)

It specifies the i2c id it wants to connect to, in this case the cx22702 id. The i2c core then walks the list of registered drivers and calls driver->connect() on the right driver and provides an "interface" pointer. This pointer holds a driver-specific structure with additional informations or function pointers (for example for the pll stuff). I simply put the function arguments from your create function for now. If that succeeds, cx88-dvb holds a valid struct i2c_client * to the newly created i2c client.

There is currently no i2c_disconnect_client(), cx88-dvb simply calls the disconnect function of the driver directly.

I added a I2C_NOPROBE flag to the struct i2c_adapter, so auto-probing drivers are kept away from this bus.

(I just noticed that the ioctl for the struct i2c_adapter is there, too, please ignore that one.)

  Gerd
CU
Michael.


diff -ura xx-linux-2.6.9-rc2-mm2/drivers/i2c/i2c-core.c linux-2.6.9-rc2-mm2/drivers/i2c/i2c-core.c
--- xx-linux-2.6.9-rc2-mm2/drivers/i2c/i2c-core.c	2004-09-23 14:36:54.000000000 +0200
+++ linux-2.6.9-rc2-mm2/drivers/i2c/i2c-core.c	2004-09-23 18:09:27.000000000 +0200
@@ -102,6 +102,33 @@
 	.show	= &show_client_name,
 };
 
+int i2c_connect_client(struct i2c_adapter *adap, int id, void *interface, struct i2c_client **client)
+{
+	struct list_head   *item;
+	struct i2c_driver  *driver;
+	int res = 0;
+	
+	down(&core_lists);
+
+	list_for_each(item,&drivers) {
+		driver = list_entry(item, struct i2c_driver, list);
+		if (driver->id == id) {
+			if (!driver->connect)
+				return -ENODEV;
+			res = driver->connect(adap, interface, client);
+			if (res)
+				goto out_unlock;
+			printk("%s(): successfully attached!\n", __FUNCTION__);
+			break;
+		}
+	}
+
+out_unlock:
+	up(&core_lists);
+	return res;
+}
+
+EXPORT_SYMBOL(i2c_connect_client);
 
 /* ---------------------------------------------------
  * registering functions 
@@ -159,13 +186,15 @@
 	class_device_register(&adap->class_dev);
 
 	/* inform drivers of new adapters */
+	if (0 == (adap->flags & I2C_NO_PROBE)) {
 	list_for_each(item,&drivers) {
 		driver = list_entry(item, struct i2c_driver, list);
 		if (driver->flags & I2C_DF_NOTIFY)
 			/* We ignore the return code; if it fails, too bad */
 			driver->attach_adapter(adap);
 	}
-
+	}
+	
 	dev_dbg(&adap->dev, "registered as adapter #%d\n", adap->nr);
 
 out_unlock:
diff -ura xx-linux-2.6.9-rc2-mm2/include/linux/i2c.h linux-2.6.9-rc2-mm2/include/linux/i2c.h
--- xx-linux-2.6.9-rc2-mm2/include/linux/i2c.h	2004-09-23 14:38:39.000000000 +0200
+++ linux-2.6.9-rc2-mm2/include/linux/i2c.h	2004-09-23 18:05:48.000000000 +0200
@@ -137,6 +137,9 @@
 	 */
 	int (*command)(struct i2c_client *client,unsigned int cmd, void *arg);
 
+	int (*connect)(struct i2c_adapter *adapter, void *interface, struct i2c_client **client);
+	int (*disconnect)(struct i2c_client *client);
+
 	struct device_driver driver;
 	struct list_head list;
 };
@@ -231,6 +234,13 @@
 	struct i2c_algorithm *algo;/* the algorithm to access the bus	*/
 	void *algo_data;
 
+	unsigned int flags;
+
+	/* a ioctl like command that can be used to perform specific functions
+	 * with the adapter.
+	 */
+	int (*command)(struct i2c_adapter *adapter, unsigned int cmd, void *arg);
+
 	/* --- administration stuff. */
 	int (*client_register)(struct i2c_client *);
 	int (*client_unregister)(struct i2c_client *);
@@ -259,6 +269,8 @@
 #define dev_to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev)
 #define class_dev_to_i2c_adapter(d) container_of(d, struct i2c_adapter, class_dev)
 
+int i2c_connect_client(struct i2c_adapter *adap, int id, void *interface, struct i2c_client **client);
+
 static inline void *i2c_get_adapdata (struct i2c_adapter *dev)
 {
 	return dev_get_drvdata (&dev->dev);
@@ -269,6 +281,10 @@
 	dev_set_drvdata (&dev->dev, data);
 }
 
+/* flags for the driver struct: */
+#define I2C_NO_PROBE	0x01		/* no probes on this bus */
+
+
 /*flags for the driver struct: */
 #define I2C_DF_NOTIFY	0x01		/* notify on bus (de/a)ttaches 	*/
 #if 0
diff -ura video4linux-orig/cx22702.c video4linux/cx22702.c
--- video4linux-orig/cx22702.c	2004-09-23 15:58:19.000000000 +0200
+++ video4linux/cx22702.c	2004-09-23 18:08:30.000000000 +0200
@@ -623,28 +623,29 @@
 
 /* ------------------------------------------------------------------ */
 
-void* cx22702_create(struct i2c_adapter *i2c,
-		     struct dvb_adapter *dvb,
-		     int pll_addr, int pll_type,
-		     int demod_addr)
+static int connect(struct i2c_adapter *i2c, void *interface, struct i2c_client **client)
 {
+	struct cx22702_demod *demod = interface;
 	struct cx22702_state *state;
 	int ret;
 
 	state = kmalloc(sizeof(*state), GFP_KERNEL);
 	if (NULL == state)
-		return NULL;
+		return -ENODEV;
+		
 	memset(state, 0, sizeof(*state));
 	memcpy(&state->cx22702_info, &cx22702_info, sizeof(struct dvb_frontend_info));
-	state->dvb           = dvb;
+	state->dvb           = demod->dvb;
 	state->demod         = demod_template;
 	state->demod.adapter = i2c;
-	state->demod.addr    = demod_addr;
+	state->demod.addr    = demod->demod_addr;
 	state->pll           = pll_template;
 	state->pll.adapter   = i2c;
-	state->pll.addr      = pll_addr;
+	state->pll.addr      = demod->pll_addr;
 
-	switch (pll_type) {
+	*client = &state->demod;
+
+	switch (demod->pll_type) {
 	case PLLTYPE_DTT7579:
 		state->set_pll = pll_dtt7579_set_tv_freq;
 		state->cx22702_info.frequency_min = 177000000;
@@ -673,6 +674,8 @@
 		printk("cx22702: i2c demod register failed (%d)\n", ret);
 		goto fail_free;
 	}
+	
+	/* arg, pll code should go somewhere else! */
 	ret = i2c_attach_client(&state->pll);
 	if (0 != ret) {
 		printk("cx22702: i2c pll register failed (%d)\n", ret);
@@ -685,8 +688,16 @@
 		goto fail_unreg2;
 	}
 
+	i2c_set_clientdata(&state->demod, (void *)state);
+
+	ret = try_module_get(THIS_MODULE);
+	if (!ret) {
+		printk("cx22702: cannot lock module. (%d)\n",ret);
+		goto fail_unreg2;
+	}
+
 	/* all fine ;) */
-	return state;
+	return 0;
 
 fail_unreg2:
 	i2c_detach_client(&state->pll);
@@ -694,39 +705,40 @@
 	i2c_detach_client(&state->demod);
 fail_free:
 	kfree(state);
-	return NULL;
+	return -ENODEV;
 }
 
-int cx22702_destroy(void *handle)
+static int disconnect(struct i2c_client *client)
 {
-	struct cx22702_state *state = handle;
+	struct cx22702_state *state = (struct cx22702_state *)i2c_get_clientdata(client);
 
 	dvb_unregister_frontend(cx22702_ioctl, state->dvb);
 	i2c_detach_client(&state->demod);
 	i2c_detach_client(&state->pll);
 	kfree(state);
+	module_put(THIS_MODULE);
 	return 0;
 }
 
-EXPORT_SYMBOL(cx22702_create);
-EXPORT_SYMBOL(cx22702_destroy);
-
 /* ------------------------------------------------------------------ */
 
 static struct i2c_driver driver = {
 	.owner = THIS_MODULE,
 	.name  = FRONTEND_NAME,
 	.id    = I2C_DRIVERID_DVBFE_CX22702,
+/*	.flags = I2C_NO_PROBE, */
+	.connect    = connect,
+	.disconnect = disconnect,
 };
 
 static struct i2c_client demod_template = {
 	.name   = "cx22702",
-	.flags  = I2C_CLIENT_ALLOW_USE,
+	.flags  = 0, /* I2C_CLIENT_ALLOW_USE, */
 	.driver = &driver,
 };
 static struct i2c_client pll_template = {
 	.name   = "Thomson DTT 75xx",
-	.flags  = I2C_CLIENT_ALLOW_USE,
+	.flags  = 0, /* I2C_CLIENT_ALLOW_USE, */
 	.driver = &driver,
 };
 
diff -ura video4linux-orig/cx22702.h video4linux/cx22702.h
--- video4linux-orig/cx22702.h	2004-09-23 15:58:19.000000000 +0200
+++ video4linux/cx22702.h	2004-09-23 18:13:16.000000000 +0200
@@ -2,8 +2,11 @@
 #define PLLTYPE_DTT7595 2
 #define PLLTYPE_DTT7579 3
 
-void* cx22702_create(struct i2c_adapter *i2c,
-		     struct dvb_adapter *dvb,
-		     int pll_addr, int pll_type,
-		     int demod_addr);
-int cx22702_destroy(void*);
+struct cx22702_demod
+{
+	struct dvb_adapter *dvb;
+	/* todo: probably some function pointers to program the pll */
+	int pll_addr;
+	int pll_type;
+	int demod_addr;
+};
diff -ura video4linux-orig/cx88-dvb.c video4linux/cx88-dvb.c
--- video4linux-orig/cx88-dvb.c	2004-09-23 16:07:00.000000000 +0200
+++ video4linux/cx88-dvb.c	2004-09-23 18:05:02.000000000 +0200
@@ -210,7 +210,7 @@
 	dvb_dmxdev_release(&dev->dmxdev);
 	dvb_dmx_release(&dev->demux);
 	if (dev->fe_handle)
-		dev->fe_release(dev->fe_handle);
+		dev->fe_handle->driver->disconnect(dev->fe_handle);
 	dvb_unregister_adapter(dev->dvb_adapter);
 	return;
 }
@@ -231,14 +231,28 @@
 	/* frontend */
 	switch (dev->core->board) {
 	case CX88_BOARD_HAUPPAUGE_DVB_T1:
-	case CX88_BOARD_CONEXANT_DVB_T1:
-		dev->fe_handle = cx22702_create(&dev->core->i2c_adap,
-						dev->dvb_adapter,
-						dev->core->pll_addr,
-						dev->core->pll_type,
-						dev->core->demod_addr);
-		dev->fe_release = cx22702_destroy;
+	case CX88_BOARD_CONEXANT_DVB_T1: {
+		struct cx22702_demod dif;
+		int ret;
+
+		dif.dvb = dev->dvb_adapter;
+		dif.pll_addr = dev->core->pll_addr,
+		dif.pll_type = dev->core->pll_type,
+		dif.demod_addr = dev->core->demod_addr;
+		
+		ret = request_module("cx22702");
+		if (ret < 0) {
+			/* fixme: error & out */
+			BUG();
+		}
+
+		ret = i2c_connect_client(&dev->core->i2c_adap, I2C_DRIVERID_DVBFE_CX22702, &dif, &dev->fe_handle);
+		if (ret) {
+			/* fixme: error & out */
+			BUG();
+		}
 		break;
+	}
 	default:
 		printk("%s: FIXME: frontend handing not here yet ...\n",
 		       dev->core->name);
diff -ura video4linux-orig/cx88.h video4linux/cx88.h
--- video4linux-orig/cx88.h	2004-09-23 16:07:00.000000000 +0200
+++ video4linux/cx88.h	2004-09-23 18:04:16.000000000 +0200
@@ -393,8 +393,7 @@
 	struct dmx_frontend        fe_mem;
 	struct dvb_net             dvbnet;
 	int                        nfeeds;
-	void*                      fe_handle;
-	int                        (*fe_release)(void *handle);
+	struct i2c_client          *fe_handle;
 };
 
 /* ----------------------------------------------------------- */

Home | Main Index | Thread Index