Mailing List archive

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

[linux-dvb] Re: [PATCHES] Frontend kernel i2c conversion.



On Tuesday 20 July 2004 19:46, Ralph Metzler wrote:
> That only gives access to the already registered i2c_adapter (but
> a lot cleaner than the present method used to do this).
> What one needs for properly registering the frontend is access to the
> dvb_adapter and the i2c_client pointers at the same time.
> The only place where this happens is in the attach_inform
> function of the bttv driver. Currently, only the analog tuners and audio
> controllers are initialized there. So, that's the natural place to
> also initialize DVB frontends. Of course the dvb_adapter pointer would
> also have to be part of the bttv structure.
>
> Alternative: get the i2c_adapter pointer via sub_device,
> lock it, (in case of linuxtv driver, change i2c adapter name),
> scan it for already present clients, init them,
> somehow add a callback for sub_devices in attach_inform
> for future attachments, do the same for detachments (if one
> allows it at all), unlock i2c_adapter.

Actually with the current CVS code, we'll need access to the command i2c 
function before the i2c bus is registered or when the frontends register on 
the i2c adapter, and as far as I can see it the i2c adapter registered as 
soon as the bttv module is loaded, and then it's too late.

Sounds to me like a driver management layer is needed for this purpose. I've 
attached an early try to make this work with the current CVS on my budget-ci 
+ stv0299. It's by no means perfect, but is easily integrated into current 
CVS. This should rid us of this problem, and also provide easy expansion to 
other bus types. It will block the frontends from registering with an 
i2c_adapter that a dvb driver does not know about, but who cares, right?

What do you think?

Kenneth
Index: budget-ci.c
===================================================================
RCS file: /cvs/linuxtv/dvb-kernel/linux/drivers/media/dvb/ttpci/budget-ci.c,v
retrieving revision 1.19
diff -u -r1.19 budget-ci.c
--- budget-ci.c	24 May 2004 17:54:43 -0000	1.19
+++ budget-ci.c	20 Jul 2004 18:30:48 -0000
@@ -40,6 +40,7 @@
 
 #include "dvb_functions.h"
 #include "dvb_ca_en50221.h"
+#include "dvb_reg.h"
 
 #define DEBIADDR_IR		0x1234
 #define DEBIADDR_CICONTROL	0x0000
@@ -501,6 +502,41 @@
 }
 
 
+static int budget_ci_frontend_probe(struct dvb_adapter_driver *adapter,
+				    struct dvb_frontend_driver *frontend)
+{
+	struct i2c_adapter *i2c_adapter = adapter->priv;
+
+	if (frontend->probe_i2c) {
+		if (frontend->probe_i2c(i2c_adapter) == 0) {
+			printk("budget-ci: frontend %s found on i2c bus.\n",
+				frontend->name);
+			return 0;
+		}
+	}
+
+/*
+	if (frontend->probe_xbus) {
+		if (frontend->probe_xbus(xbus_adapter) == 0) {
+			printk("budget-ci: frontend %s found on xbus.\n",
+				frontend->name);
+			return 0;
+		}
+	}
+*/
+
+	printk("budget-ci: could not find device on %s.\n",
+		frontend->name);
+
+	return -ENODEV;
+}
+
+static struct dvb_adapter_driver adapter_driver = {
+	.owner		= THIS_MODULE,
+	.name		= "budget-ci",
+	.id		= 1,
+	.probe_frontend = budget_ci_frontend_probe,
+};
 
 static int budget_ci_attach (struct saa7146_dev* dev,
 		      struct saa7146_pci_extension_data *info)
@@ -530,6 +566,9 @@
 
 	ciintf_init(budget_ci);
 
+	adapter_driver.priv = &budget_ci->budget.i2c_adap;
+	dvb_add_adapter_driver(&adapter_driver);
+
 	return 0;
 }
 
@@ -563,11 +602,13 @@
 
 MAKE_BUDGET_INFO(ttbci,	"TT-Budget/WinTV-NOVA-CI PCI",	BUDGET_TT_HW_DISEQC);
 MAKE_BUDGET_INFO(ttbt2,	"TT-Budget/WinTV-NOVA-T	 PCI",	BUDGET_TT);
+MAKE_BUDGET_INFO(knc1,	"KNC1 DVB-S",			BUDGET_KNC1);
 
 static struct pci_device_id pci_tbl[] = {
 	MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c),
 	MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100f),
 	MAKE_EXTENSION_PCI(ttbt2, 0x13c2, 0x1011),
+	MAKE_EXTENSION_PCI(knc1,  0x1131, 0x4f56),
 	{
 		.vendor	   = 0,
 	}
@@ -597,6 +638,8 @@
 
 static void __exit budget_ci_exit(void)
 {
+	dvb_del_adapter_driver(&adapter_driver);
+
 	DEB_EE((".\n"));
 	saa7146_unregister_extension(&budget_extension);
 }
Index: stv0299.c
===================================================================
RCS file: /cvs/linuxtv/dvb-kernel/linux/drivers/media/dvb/frontends/stv0299.c,v
retrieving revision 1.53
diff -u -r1.53 stv0299.c
--- stv0299.c	17 Jul 2004 14:51:41 -0000	1.53
+++ stv0299.c	20 Jul 2004 18:33:26 -0000
@@ -45,6 +45,7 @@
 
 */
 
+
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -53,6 +54,7 @@
 #include <linux/slab.h>
 #include <asm/div64.h>
 
+#include "dvb_reg.h"
 #include "dvb_frontend.h"
 #include "dvb_functions.h"
 
@@ -1353,6 +1355,24 @@
 
 static int attach_adapter(struct i2c_adapter *adapter)
 {
+	// dummy...
+	return -ENODEV;
+}
+
+static int stv0299_attach_dvb_adapter(struct dvb_adapter2 *adapter)
+{
+	printk("%s: attaching to adapter.\n", __FUNCTION__);
+	return 0;
+}
+
+static int stv0299_detach_frontend(void)
+{
+	printk("%s: detaching from adapter.\n", __FUNCTION__);
+	return 0;
+}
+
+static int stv0299_probe_i2c(struct i2c_adapter *adapter)
+{
 	struct i2c_client *client;
 	struct stv0299_state* state;
 	int tuner_type;
@@ -1409,10 +1429,20 @@
 		kfree(state);
 		return -EFAULT;
 	}
-	
+
 	return 0;
 }
 
+static struct dvb_frontend_driver frontend_driver = {
+	.owner			= THIS_MODULE,
+	.name			= FRONTEND_NAME,
+	.id			= 10,
+	.ioctl			= uni0299_ioctl,
+	.attach_adapter		= stv0299_attach_dvb_adapter,
+	.detach_frontend	= stv0299_detach_frontend,
+	.probe_i2c		= stv0299_probe_i2c,
+};
+
 static int detach_client(struct i2c_client *client)
 {
 	struct stv0299_state *state = (struct stv0299_state*)i2c_get_clientdata(client);
@@ -1462,11 +1492,15 @@
 
 static int __init init_uni0299 (void)
 {
+	dvb_add_frontend_driver(&frontend_driver);
+
 	return i2c_add_driver(&driver);
 }
 
 static void __exit exit_uni0299 (void)
 {
+	dvb_del_frontend_driver(&frontend_driver);
+
 	if (i2c_del_driver(&driver))
 		printk("stv0299: driver deregistration failed\n");
 }
/*
 * LinuxTV DVB Core Driver Management Layer.
 *
 * Copyright (C) 2004 Kenneth Aafløy <kenneth nospam aafloy.net>
 *
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
 */

#include <linux/list.h>

#include "dvb_reg.h"

static int debug = 1;

#define dprintk(args...) \
	do { \
		if (debug) printk(KERN_DEBUG "dvb_reg: " args); \
	} while (0)

struct dvbadap_priv {
	struct list_head list_head;
	struct dvb_adapter_driver *driver;

	struct list_head frontends;
};

struct dvbfe_priv {
	struct list_head list_head;
	struct dvb_frontend_driver *driver;

	struct list_head adapters;
};

struct dvbfe_link {
	struct list_head list_head;
	struct dvbfe_priv *fe;
};

struct dvbadap_link {
	struct list_head list_head;
	struct dvbadap_priv *adap;
};

static LIST_HEAD(dvb_frontend_drivers);
static LIST_HEAD(dvb_adapter_drivers);
static DECLARE_MUTEX(driver_sem);

static void do_print_frontends_on_adapter(struct dvbadap_priv *adapter)
{
	struct list_head *entry;

	list_for_each(entry, &adapter->frontends) {
		struct dvbfe_link *fe_link;

		fe_link = list_entry(entry, struct dvbfe_link, list_head);

		if (fe_link && fe_link->fe && fe_link->fe->driver)
			dprintk("%s: attached to %i.\n", adapter->driver->name,
				fe_link->fe->driver->id);
	}
}

static int do_frontend_probe(struct dvbadap_priv *adapter,
			     struct dvbfe_priv *frontend)
{
	struct dvbfe_link *fe_link;
	struct dvbadap_link *adap_link;
	int ret;

	if (!adapter->driver->probe_frontend)
		return -EFAULT;

	if ( (ret = adapter->driver->probe_frontend(adapter->driver,
						    frontend->driver)) )
		return ret;

	if ( !(fe_link = kmalloc(sizeof(struct dvbfe_link), GFP_KERNEL)) )
		return -ENOMEM;

	if ( !(adap_link = kmalloc(sizeof(struct dvbadap_link), GFP_KERNEL)) )
		return -ENOMEM;

	fe_link->fe = frontend;
	adap_link->adap = adapter;

	list_add_tail(&fe_link->list_head, &adapter->frontends);
	list_add_tail(&adap_link->list_head, &frontend->adapters);

	return 0;
}

static int do_adapter_unlink_frontend(struct dvbadap_priv *adapter,
				      struct dvbfe_priv *frontend)
{
	struct list_head *entry;
	struct list_head *entry_tmp;

	list_for_each_safe(entry, entry_tmp, &adapter->frontends) {
		struct dvbfe_link *fe;

		fe = list_entry(entry, struct dvbfe_link, list_head);

		if (fe->fe == frontend) {
			dprintk("unlinking frontend %s from adapter %s.\n",
				fe->fe->driver->name,
				adapter->driver->name);

			list_del(entry);
			kfree(fe);
		}
	}

	return 0;
}

static int do_frontend_unlink_adapter(struct dvbfe_priv *frontend,
				      struct dvbadap_priv *adapter)
{
	struct list_head *entry;
	struct list_head *entry_tmp;

	list_for_each_safe(entry, entry_tmp, &frontend->adapters) {
		struct dvbadap_link *adap;

		adap = list_entry(entry, struct dvbadap_link, list_head);

		if (adap->adap == adapter) {
			dprintk("unlinking adapter %s from frontend %s.\n",
				adap->adap->driver->name,
				frontend->driver->name);

			list_del(entry);
			kfree(adap);
		}
	}

	return 0;
}

static int do_adapter_unlink_frontends(struct dvbadap_priv *adapter)
{
	struct list_head *entry;
	struct list_head *entry_tmp;

	list_for_each_safe(entry, entry_tmp, &adapter->frontends) {
		struct dvbfe_link *fe;

		fe = list_entry(entry, struct dvbfe_link, list_head);

		dprintk("unlinking frontend %s from adapter %s.\n",
			fe->fe->driver->name,
			adapter->driver->name);

		do_frontend_unlink_adapter(fe->fe, adapter);
		list_del(entry);
	}

	kfree(adapter);
	return 0;
}

static int do_frontend_unlink_adapters(struct dvbfe_priv *frontend)
{
	struct list_head *entry;
	struct list_head *entry_tmp;

	if ( list_empty(&frontend->adapters) ) {
		kfree(frontend);
		return 0;
	}

	list_for_each_safe(entry, entry_tmp, &frontend->adapters) {
		struct dvbadap_link *adap;

		adap = list_entry(entry, struct dvbadap_link, list_head);

		do_adapter_unlink_frontend(adap->adap, frontend);
		list_del(entry);
	}

	kfree(frontend);
	return 0;
}

int dvb_add_frontend_driver(struct dvb_frontend_driver *driver)
{
	struct dvbfe_priv *fe;
	struct list_head *entry;

	dprintk("%s: %s\n", __FUNCTION__, driver->name);

	if ( !(fe = kmalloc(sizeof(struct dvbfe_priv), GFP_KERNEL)) ) {
		return -ENOMEM;
	}

	if (down_interruptible(&driver_sem))
		return -ERESTARTSYS;

	INIT_LIST_HEAD(&fe->adapters);
	fe->driver = driver;

	list_add_tail(&fe->list_head, &dvb_frontend_drivers);

	list_for_each(entry, &dvb_adapter_drivers) {
		struct dvbadap_priv *adap;
		adap = list_entry(entry, struct dvbadap_priv, list_head);
		do_frontend_probe(adap, fe);
	}

	list_for_each(entry, &fe->adapters) {
		struct dvbadap_link *adap_link;

		adap_link = list_entry(entry, struct dvbadap_link, list_head);

		if (adap_link && adap_link->adap && adap_link->adap->driver)
			dprintk("%s: attached to %i.\n", driver->name,
				adap_link->adap->driver->id);
	}

	up(&driver_sem);

	return 0;
}

EXPORT_SYMBOL_GPL(dvb_add_frontend_driver);

int dvb_del_frontend_driver(struct dvb_frontend_driver *driver)
{
	struct dvbfe_priv *frontend;
	struct list_head *entry;
	struct list_head *entry_tmp;

	dprintk("%s: %s\n", __FUNCTION__, driver->name);

	if (down_interruptible(&driver_sem))
		return -ERESTARTSYS;

	list_for_each_safe(entry, entry_tmp, &dvb_frontend_drivers) {
		frontend = list_entry(entry, struct dvbfe_priv, list_head);

		if (frontend->driver == driver) {
			list_del(entry);
			do_frontend_unlink_adapters(frontend);
		}
	}

	up(&driver_sem);

	return 0;
}

EXPORT_SYMBOL_GPL(dvb_del_frontend_driver);

int dvb_add_adapter_driver(struct dvb_adapter_driver *driver)
{
	struct dvbadap_priv *adap;
	struct list_head *entry;

	dprintk("%s: %s\n", __FUNCTION__, driver->name);

	if ( !(adap = kmalloc(sizeof(struct dvbadap_priv), GFP_KERNEL)) ) {
		return -ENOMEM;
	}

	if (down_interruptible(&driver_sem))
		return -ERESTARTSYS;

	INIT_LIST_HEAD(&adap->frontends);
	adap->driver = driver;

	list_add_tail(&adap->list_head, &dvb_adapter_drivers);

	list_for_each(entry, &dvb_frontend_drivers) {
		struct dvbfe_priv *fe;
		fe = list_entry(entry, struct dvbfe_priv, list_head);

		do_frontend_probe(adap, fe);
	}

	do_print_frontends_on_adapter(adap);

	up(&driver_sem);

	return 0;
}

EXPORT_SYMBOL_GPL(dvb_add_adapter_driver);

int dvb_del_adapter_driver(struct dvb_adapter_driver *driver)
{
	struct dvbadap_priv *adap = NULL;
	struct list_head *entry;
	struct list_head *entry_tmp;

	dprintk("%s: %s\n", __FUNCTION__, driver->name);

	if (down_interruptible(&driver_sem))
		return -ERESTARTSYS;

	list_for_each_safe(entry, entry_tmp, &dvb_adapter_drivers) {
		adap = list_entry(entry, struct dvbadap_priv, list_head);

		if (adap->driver == driver) {
			list_del(entry);
			do_adapter_unlink_frontends(adap);
		}
	}

	up(&driver_sem);

	return 0;
}

EXPORT_SYMBOL_GPL(dvb_del_adapter_driver);

/*
 * LinuxTV DVB Core Driver Management Layer.
 *
 * Copyright (C) 2004 Kenneth Aafløy <kenneth nospam aafloy.net>
 *
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
 */


#ifndef _DVB_REG_H_
#define _DVB_REG_H_

#include <linux/module.h>

#include "dvb_frontend.h"

//#include "dvb_adapter.h"
struct dvb_adapter2 {
};

struct dvb_frontend_driver {
	struct module	*owner;
	char		 name[30];
	int		 id;

	int (*probe_i2c)(struct i2c_adapter *);
//	int (*probe_xbus)(struct xbus_adapter *);

	int (*ioctl)(struct dvb_frontend *fe,
		     unsigned int cmd, void *arg);

	int (*attach_adapter)(struct dvb_adapter2 *);
	int (*detach_frontend)(void);
};

struct dvb_adapter_driver {
	struct module	*owner;
	char		name[30];
	int		id;
	void		*priv;

	int (*probe_frontend)(struct dvb_adapter_driver *,
			      struct dvb_frontend_driver *);
};

extern int dvb_add_frontend_driver(struct dvb_frontend_driver *driver);
extern int dvb_del_frontend_driver(struct dvb_frontend_driver *driver);

extern int dvb_add_adapter_driver(struct dvb_adapter_driver *driver);
extern int dvb_del_adapter_driver(struct dvb_adapter_driver *driver);

#endif


Home | Main Index | Thread Index