Mailing List archive

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

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



Hi,

please have a look at the attached patch, it implements the basic ideas how to make the dvb adapter of the frontends.

If you want to try it out, you need to apply my patch that adds a command function to the i2c adapter and recompile your kernel. ;-)

Ok, the patch adds some generic stuff to dvb_frontend.h:
------------------------------------schnipp------------------------
* generic */
struct dvb_fe_identifier {
int id; /* should be i2c_driver->id, must be first */
};
/* stv0299 specific stuff */
#define PHILIPS_SU1278_TSA 0 // SU1278 with TSA5059 synth and datasheet recommended settings
#define ALPS_BSRU6 1
#define LG_TDQF_S001F 2
#define PHILIPS_SU1278_TUA 3 // SU1278 with TUA6100 synth
#define SAMSUNG_TBMU24112IMB 4
#define PHILIPS_SU1278_TSA_TT 5 // SU1278 with TSA5059 synth and TechnoTrend settings
#define PHILIPS_SU1278_TSA_TY 6 // SU1278 with TUA5059 synth and Typhoon wiring
#define PHILIPS_SU1278_TSA_CI 7 // SU1278 with TUA5059 synth and TerraTec Cinergy wiring

struct dvb_stv0299 {
struct dvb_fe_identifier id; /* must be first */
int tuner_type;
};
[...]
#define DVB_IDENTIFY_FE _IO ('v', 90)
------------------------------------schnipp------------------------

Currently, the tuner_type is queried from the dvb adapter before actually probing the frontend using the DVB_IDENTIFY_FE ioctl through the new i2c adapter command in the stv0299 driver.

The dvb adapter knows everything about the underlying hardware and can decide if this frontend can exist and what configuration is best. So the command function in av7110.c looks like this:

------------------------------------schnipp------------------------
+static int command(struct i2c_adapter *adapter, unsigned int cmd, void *arg)
+{
+ struct dvb_fe_identifier *id = arg;
+
+ if (id->id == I2C_DRIVERID_DVBFE_STV0299) {
+ struct dvb_stv0299 *identify = arg;
+ printk("dvb-ttpci: %s(): type set to ALPS_BSRU6.\n", __FUNCTION__);
+ identify->tuner_type = ALPS_BSRU6;
+ return 0;
+ } else if (id->id == I2C_DRIVERID_DVBFE_VES1X93) {
+ printk("dvb-ttpci: %s(): accepted VES1x93.\n", __FUNCTION__);
+ return 0;
+ }
+
+ printk("dvb-ttpci: %s(): unknown frontend\n", __FUNCTION__);
+ return -1;
+}
------------------------------------schnipp------------------------

Of course some more fancy detection (for example with PCI ids) is necessary here.

The stv0299 falls back to probing when the adapter doesn't support the command function or the ioctl fails.

Of course more sophisticated stuff can be exported via struct dvb_stv0299, for example the pll functions.

What do you think?

CU
Michael.
? drivers/media/dvb/frontends/a
Index: drivers/media/dvb/dvb-core/dvb_frontend.h
===================================================================
RCS file: /cvs/linuxtv/dvb-kernel/linux/drivers/media/dvb/dvb-core/dvb_frontend.h,v
retrieving revision 1.18
diff -u -u -r1.18 dvb_frontend.h
--- drivers/media/dvb/dvb-core/dvb_frontend.h	6 Sep 2004 10:42:32 -0000	1.18
+++ drivers/media/dvb/dvb-core/dvb_frontend.h	21 Sep 2004 11:49:03 -0000
@@ -60,6 +60,31 @@
 #define I2C_DRIVERID_DVBFE_VES1820	I2C_DRIVERID_EXP2
 #define I2C_DRIVERID_DVBFE_VES1X93	I2C_DRIVERID_EXP2
 
+/* generic */
+struct dvb_fe_identifier {
+	int id; /* should be i2c_driver->id, must be first */
+};
+
+/* ves1x93 specific stuff */
+struct dvb_ves1x93 {
+	struct dvb_fe_identifier id; /* must be first */
+};
+
+/* stv0299 specific stuff */
+#define PHILIPS_SU1278_TSA	0 // SU1278 with TSA5059 synth and datasheet recommended settings
+#define ALPS_BSRU6		1
+#define LG_TDQF_S001F		2
+#define PHILIPS_SU1278_TUA	3 // SU1278 with TUA6100 synth
+#define SAMSUNG_TBMU24112IMB	4
+#define PHILIPS_SU1278_TSA_TT	5 // SU1278 with TSA5059 synth and TechnoTrend settings
+#define PHILIPS_SU1278_TSA_TY	6 // SU1278 with TUA5059 synth and Typhoon wiring
+#define PHILIPS_SU1278_TSA_CI	7 // SU1278 with TUA5059 synth and TerraTec Cinergy wiring
+
+struct dvb_stv0299 {
+	struct dvb_fe_identifier id; /* must be first */
+	int tuner_type;
+};
+
 /**
  *   when before_ioctl is registered and returns value 0, ioctl and after_ioctl
  *   are not executed.
@@ -98,6 +123,8 @@
 #define FE_REGISTER	      _IO  ('v', 84)
 #define FE_UNREGISTER	      _IO  ('v', 85)
 
+#define DVB_IDENTIFY_FE	      _IO  ('v', 90)
+
 extern int
 dvb_register_frontend (int (*ioctl) (struct dvb_frontend *frontend,
 				     unsigned int cmd, void *arg),
Index: drivers/media/dvb/frontends/stv0299.c
===================================================================
RCS file: /cvs/linuxtv/dvb-kernel/linux/drivers/media/dvb/frontends/stv0299.c,v
retrieving revision 1.58
diff -u -u -r1.58 stv0299.c
--- drivers/media/dvb/frontends/stv0299.c	18 Sep 2004 17:18:54 -0000	1.58
+++ drivers/media/dvb/frontends/stv0299.c	21 Sep 2004 11:49:08 -0000
@@ -62,6 +62,8 @@
 		if (debug) printk(KERN_DEBUG FRONTEND_NAME ": " args); \
 	} while (0)
 
+#define UNKNOWN_FRONTEND -1
+
 static int debug;
 static int stv0299_status;
 
@@ -74,18 +76,6 @@
 #define STATUS_BER 0
 #define STATUS_UCBLOCKS 1
 
-
-/* frontend types */
-#define UNKNOWN_FRONTEND       -1
-#define PHILIPS_SU1278_TSA	0 // SU1278 with TSA5059 synth and datasheet recommended settings
-#define ALPS_BSRU6		1
-#define LG_TDQF_S001F		2
-#define PHILIPS_SU1278_TUA	3 // SU1278 with TUA6100 synth
-#define SAMSUNG_TBMU24112IMB	4
-#define PHILIPS_SU1278_TSA_TT	5 // SU1278 with TSA5059 synth and TechnoTrend settings
-#define PHILIPS_SU1278_TSA_TY	6 // SU1278 with TUA5059 synth and Typhoon wiring
-#define PHILIPS_SU1278_TSA_CI	7 // SU1278 with TUA5059 synth and TerraTec Cinergy wiring
-
 /* Master Clock = 88 MHz */
 #define M_CLK (88000000UL)
 
@@ -1347,15 +1337,31 @@
 }
 
 static struct i2c_client client_template;
+static struct i2c_driver driver;
 
 static int attach_adapter(struct i2c_adapter *adapter)
 {
 	struct i2c_client *client;
 	struct stv0299_state* state;
-	int tuner_type;
+	struct dvb_stv0299 identify;
 	int ret;
 	u8 id;
 
+	if (!adapter->command) {
+		identify.tuner_type = probe_tuner(adapter);
+		if (identify.tuner_type < 0)
+			return -ENODEV;
+	} else {
+		memset(&identify, 0, sizeof(identify));
+		identify.id.id = driver.id;
+		ret = adapter->command(adapter, DVB_IDENTIFY_FE, &identify);
+		if (ret) {
+			identify.tuner_type = probe_tuner(adapter);
+			if (identify.tuner_type < 0)
+				return -ENODEV;
+		}
+	}
+	
 	stv0299_writereg(adapter, 0x02, 0x34); /* standby off */
 	msleep(200);
 	id = stv0299_readreg(adapter, 0x00);
@@ -1367,8 +1373,26 @@
 	if (id != 0xa1 && id != 0x80)
 		return -ENODEV;
 
-	if ((tuner_type = probe_tuner(adapter)) < 0)
-		return -ENODEV;
+	stv0299_writereg(adapter, 0x01, 0x15);
+	stv0299_writereg(adapter, 0x02, 0x30);
+	stv0299_writereg(adapter, 0x03, 0x00);
+
+	switch (identify.tuner_type) {
+		case PHILIPS_SU1278_TSA:
+		case ALPS_BSRU6:
+		case LG_TDQF_S001F:
+		case SAMSUNG_TBMU24112IMB:
+		case PHILIPS_SU1278_TSA_TT:
+		case PHILIPS_SU1278_TSA_TY:
+		case PHILIPS_SU1278_TSA_CI:
+			break;
+		/* setup i2c timing for SU1278... */
+		case PHILIPS_SU1278_TUA:
+			stv0299_writereg(adapter, 0x02, 0x00);
+			break;
+		default:
+			return -ENODEV;
+	}
 
 	if ((state = kmalloc(sizeof(struct stv0299_state), GFP_KERNEL)) == NULL) {
 		return -ENOMEM;
@@ -1379,7 +1403,7 @@
 		return -ENOMEM;
 	}
 
-	state->tuner_type = tuner_type;
+	state->tuner_type = identify.tuner_type;
 	state->tuner_frequency = 0;
 	state->initialised = 0;
 	state->i2c = adapter;
@@ -1395,18 +1419,7 @@
 		kfree(state);
 		return -EFAULT;
 	}
-	
-	BUG_ON(!state->dvb);
 
-	ret = dvb_register_frontend(uni0299_ioctl, state->dvb, state,
-					&uni0299_info, THIS_MODULE);
-	if (ret) {
-		i2c_detach_client(client);
-		kfree(client);
-		kfree(state);
-		return -EFAULT;
-	}
-	
 	return 0;
 }
 
@@ -1414,7 +1427,6 @@
 {
 	struct stv0299_state *state = (struct stv0299_state*)i2c_get_clientdata(client);
 
-	dvb_unregister_frontend (uni0299_ioctl, state->dvb);
 	i2c_detach_client(client);
 	kfree(client);
 	kfree(state);
@@ -1424,14 +1436,20 @@
 static int command (struct i2c_client *client, unsigned int cmd, void *arg)
 {
 	struct stv0299_state *data = (struct stv0299_state*)i2c_get_clientdata(client);
+	int ret;
+	
 	dprintk ("%s\n", __FUNCTION__);
 
 	switch (cmd) {
 	case FE_REGISTER: {
 		data->dvb = (struct dvb_adapter*)arg;
+		ret = dvb_register_frontend(uni0299_ioctl, data->dvb, data, &uni0299_info, THIS_MODULE);
+		if (ret)
+			return ret;
 		break;
 	}
 	case FE_UNREGISTER: {
+		dvb_unregister_frontend (uni0299_ioctl, data->dvb);
 		data->dvb = NULL;
 		break;
 	}
Index: drivers/media/dvb/ttpci/av7110.c
===================================================================
RCS file: /cvs/linuxtv/dvb-kernel/linux/drivers/media/dvb/ttpci/av7110.c,v
retrieving revision 1.143
diff -u -u -r1.143 av7110.c
--- drivers/media/dvb/ttpci/av7110.c	20 Sep 2004 16:37:45 -0000	1.143
+++ drivers/media/dvb/ttpci/av7110.c	21 Sep 2004 11:49:09 -0000
@@ -1429,6 +1429,24 @@
 	return 0;
 }
 
+static int command(struct i2c_adapter *adapter, unsigned int cmd, void *arg)
+{
+	struct dvb_fe_identifier *id = arg;
+	
+	if (id->id == I2C_DRIVERID_DVBFE_STV0299) {
+		struct dvb_stv0299 *identify = arg;
+		printk("dvb-ttpci: %s(): type set to ALPS_BSRU6.\n", __FUNCTION__);
+		identify->tuner_type = ALPS_BSRU6;
+		return 0;
+	} else if (id->id == I2C_DRIVERID_DVBFE_VES1X93) {
+		printk("dvb-ttpci: %s(): accepted VES1x93.\n", __FUNCTION__);
+		return 0;
+	}
+	
+	printk("dvb-ttpci: %s(): unknown frontend\n", __FUNCTION__);
+	return -1;
+}
+
 static int av7110_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_data *pci_ext)
 {
 	struct av7110 *av7110 = NULL;
@@ -1462,6 +1480,7 @@
 	av7110->i2c_adap = (struct i2c_adapter) {
 		.client_register = client_register,
 		.client_unregister = client_unregister,
+		.command = command,
 #ifdef I2C_ADAP_CLASS_TV_DIGITAL
 		.class = I2C_ADAP_CLASS_TV_DIGITAL,
 #else

Home | Main Index | Thread Index