diff mbox

tm6000: add detection based on eeprom name

Message ID 4DAF537C.1000108@redhat.com (mailing list archive)
State Accepted
Headers show

Commit Message

Mauro Carvalho Chehab April 20, 2011, 9:43 p.m. UTC
On some situations, it is desired to use eeprom data to detect
the board type. This patch adds a logic for it and fixes 2 detection
issues:
	1) 10Moons UT-821 uses a generic Trident ID. Other boards
also share the same ID. So, better to use an alternative way for
it;
	2) Sometimes, HVR-900H is loaded with the default Trident
ID. This seems to be some hardware bug or race condition.

The new logic will only be enabled if the device is detected as
having a generic ID.

Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/staging/tm6000/tm6000-cards.c b/drivers/staging/tm6000/tm6000-cards.c
index 146c7e8..6e51486 100644
--- a/drivers/staging/tm6000/tm6000-cards.c
+++ b/drivers/staging/tm6000/tm6000-cards.c
@@ -54,6 +54,11 @@ 
 #define TM6010_BOARD_BEHOLD_VOYAGER_LITE	15
 #define TM5600_BOARD_TERRATEC_GRABSTER		16
 
+#define is_generic(model) ((model == TM6000_BOARD_UNKNOWN) || \
+			   (model == TM5600_BOARD_GENERIC) || \
+			   (model == TM6000_BOARD_GENERIC) || \
+			   (model == TM6010_BOARD_GENERIC))
+
 #define TM6000_MAXBOARDS        16
 static unsigned int card[]     = {[0 ... (TM6000_MAXBOARDS - 1)] = UNSET };
 
@@ -64,6 +69,9 @@  static unsigned long tm6000_devused;
 
 struct tm6000_board {
 	char            *name;
+	char		eename[16];		/* EEPROM name */
+	unsigned	eename_size;		/* size of EEPROM name */
+	unsigned	eename_pos;		/* Position where it appears at ROM */
 
 	struct tm6000_capabilities caps;
 	enum            tm6000_inaudio aradio;
@@ -139,6 +147,9 @@  struct tm6000_board tm6000_boards[] = {
 	[TM5600_BOARD_10MOONS_UT821] = {
 		.name         = "10Moons UT 821",
 		.tuner_type   = TUNER_XC2028,
+		.eename       = { '1', '0', 'M', 'O', 'O', 'N', 'S', '5', '6', '0', '0', 0xff, 0x45, 0x5b},
+		.eename_size  = 14,
+		.eename_pos   = 0x14,
 		.type         = TM5600,
 		.tuner_addr   = 0xc2 >> 1,
 		.caps = {
@@ -205,6 +216,9 @@  struct tm6000_board tm6000_boards[] = {
 	},
 	[TM6010_BOARD_HAUPPAUGE_900H] = {
 		.name         = "Hauppauge WinTV HVR-900H / WinTV USB2-Stick",
+		.eename       = { 'H', 0, 'V', 0, 'R', 0, '9', 0, '0', 0, '0', 0, 'H', 0 },
+		.eename_size  = 14,
+		.eename_pos   = 0x42,
 		.tuner_type   = TUNER_XC2028, /* has a XC3028 */
 		.tuner_addr   = 0xc2 >> 1,
 		.demod_addr   = 0x1e >> 1,
@@ -370,7 +384,7 @@  struct tm6000_board tm6000_boards[] = {
 
 /* table of devices that work with this driver */
 struct usb_device_id tm6000_id_table[] = {
-	{ USB_DEVICE(0x6000, 0x0001), .driver_info = TM5600_BOARD_10MOONS_UT821 },
+	{ USB_DEVICE(0x6000, 0x0001), .driver_info = TM5600_BOARD_GENERIC },
 	{ USB_DEVICE(0x6000, 0x0002), .driver_info = TM6010_BOARD_GENERIC },
 	{ USB_DEVICE(0x06e1, 0xf332), .driver_info = TM6000_BOARD_ADSTECH_DUAL_TV },
 	{ USB_DEVICE(0x14aa, 0x0620), .driver_info = TM6000_BOARD_FREECOM_AND_SIMILAR },
@@ -729,16 +743,10 @@  static void tm6000_config_tuner(struct tm6000_core *dev)
 	}
 }
 
-static int tm6000_init_dev(struct tm6000_core *dev)
+static int fill_board_specific_data(struct tm6000_core *dev)
 {
-	struct v4l2_frequency f;
-	int rc = 0;
-
-	mutex_init(&dev->lock);
+	int rc;
 
-	mutex_lock(&dev->lock);
-
-	/* Initializa board-specific data */
 	dev->dev_type   = tm6000_boards[dev->model].type;
 	dev->tuner_type = tm6000_boards[dev->model].tuner_type;
 	dev->tuner_addr = tm6000_boards[dev->model].tuner_addr;
@@ -756,16 +764,80 @@  static int tm6000_init_dev(struct tm6000_core *dev)
 	/* initialize hardware */
 	rc = tm6000_init(dev);
 	if (rc < 0)
-		goto err;
+		return rc;
 
 	rc = v4l2_device_register(&dev->udev->dev, &dev->v4l2_dev);
 	if (rc < 0)
-		goto err;
+		return rc;
 
-	/* register i2c bus */
-	rc = tm6000_i2c_register(dev);
-	if (rc < 0)
-		goto err;
+	/* initialize hardware */
+	rc = tm6000_init(dev);
+
+	return rc;
+}
+
+
+static void use_alternative_detection_method(struct tm6000_core *dev)
+{
+	int i, model = -1;
+
+	if (!dev->eedata_size)
+		return;
+
+	for (i = 0; i < ARRAY_SIZE(tm6000_boards); i++) {
+		if (!tm6000_boards[i].eename_size)
+			continue;
+		if (dev->eedata_size < tm6000_boards[i].eename_pos +
+				       tm6000_boards[i].eename_size)
+			continue;
+
+		if (!memcmp(&dev->eedata[tm6000_boards[i].eename_pos],
+			    tm6000_boards[i].eename,
+			    tm6000_boards[i].eename_size)) {
+			model = i;
+			break;
+		}
+	}
+	if (model < 0) {
+		printk(KERN_INFO "Device has eeprom but is currently unknown\n");
+		return;
+	}
+
+	dev->model = model;
+
+	printk(KERN_INFO "Device identified via eeprom as %s (type = %d)\n",
+	       tm6000_boards[model].name, model);
+}
+
+static int tm6000_init_dev(struct tm6000_core *dev)
+{
+	struct v4l2_frequency f;
+	int rc = 0;
+
+	mutex_init(&dev->lock);
+	mutex_lock(&dev->lock);
+
+	if (!is_generic(dev->model)) {
+		rc = fill_board_specific_data(dev);
+		if (rc < 0)
+			goto err;
+
+		/* register i2c bus */
+		rc = tm6000_i2c_register(dev);
+		if (rc < 0)
+			goto err;
+	} else {
+		/* register i2c bus */
+		rc = tm6000_i2c_register(dev);
+		if (rc < 0)
+			goto err;
+
+		use_alternative_detection_method(dev);
+
+		rc = fill_board_specific_data(dev);
+		if (rc < 0)
+			goto err;
+	}
 
 	/* Default values for STD and resolutions */
 	dev->width = 720;
diff --git a/drivers/staging/tm6000/tm6000-i2c.c b/drivers/staging/tm6000/tm6000-i2c.c
index 18de474..8828c12 100644
--- a/drivers/staging/tm6000/tm6000-i2c.c
+++ b/drivers/staging/tm6000/tm6000-i2c.c
@@ -237,35 +237,36 @@  err:
 	return rc;
 }
 
-static int tm6000_i2c_eeprom(struct tm6000_core *dev,
-			     unsigned char *eedata, int len)
+static int tm6000_i2c_eeprom(struct tm6000_core *dev)
 {
 	int i, rc;
-	unsigned char *p = eedata;
+	unsigned char *p = dev->eedata;
 	unsigned char bytes[17];
 
 	dev->i2c_client.addr = 0xa0 >> 1;
+	dev->eedata_size = 0;
 
 	bytes[16] = '\0';
-	for (i = 0; i < len; ) {
-	*p = i;
-	rc = tm6000_i2c_recv_regs(dev, 0xa0, i, p, 1);
+	for (i = 0; i < sizeof(dev->eedata); ) {
+		*p = i;
+		rc = tm6000_i2c_recv_regs(dev, 0xa0, i, p, 1);
 		if (rc < 1) {
-			if (p == eedata)
+			if (p == dev->eedata)
 				goto noeeprom;
 			else {
 				printk(KERN_WARNING
 				"%s: i2c eeprom read error (err=%d)\n",
 				dev->name, rc);
 			}
-			return -1;
+			return -EINVAL;
 		}
+		dev->eedata_size++;
 		p++;
 		if (0 == (i % 16))
 			printk(KERN_INFO "%s: i2c eeprom %02x:", dev->name, i);
-		printk(" %02x", eedata[i]);
-		if ((eedata[i] >= ' ') && (eedata[i] <= 'z'))
-			bytes[i%16] = eedata[i];
+		printk(" %02x", dev->eedata[i]);
+		if ((dev->eedata[i] >= ' ') && (dev->eedata[i] <= 'z'))
+			bytes[i%16] = dev->eedata[i];
 		else
 			bytes[i%16] = '.';
 
@@ -280,15 +281,15 @@  static int tm6000_i2c_eeprom(struct tm6000_core *dev,
 		bytes[i%16] = '\0';
 		for (i %= 16; i < 16; i++)
 			printk("   ");
+		printk("  %s\n", bytes);
 	}
-	printk("  %s\n", bytes);
 
 	return 0;
 
 noeeprom:
 	printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n",
-		       dev->name, rc);
-	return rc;
+	       dev->name, rc);
+	return -EINVAL;
 }
 
 /* ----------------------------------------------------------- */
@@ -314,7 +315,6 @@  static const struct i2c_algorithm tm6000_algo = {
  */
 int tm6000_i2c_register(struct tm6000_core *dev)
 {
-	unsigned char eedata[256];
 	int rc;
 
 	dev->i2c_adap.owner = THIS_MODULE;
@@ -329,8 +329,7 @@  int tm6000_i2c_register(struct tm6000_core *dev)
 
 	dev->i2c_client.adapter = &dev->i2c_adap;
 	strlcpy(dev->i2c_client.name, "tm6000 internal", I2C_NAME_SIZE);
-
-	tm6000_i2c_eeprom(dev, eedata, sizeof(eedata));
+	tm6000_i2c_eeprom(dev);
 
 	return 0;
 }
diff --git a/drivers/staging/tm6000/tm6000.h b/drivers/staging/tm6000/tm6000.h
index 99ae50e..fdd6d30 100644
--- a/drivers/staging/tm6000/tm6000.h
+++ b/drivers/staging/tm6000/tm6000.h
@@ -167,6 +167,8 @@  struct tm6000_core {
 	int				model;		/* index in the device_data struct */
 	int				devno;		/* marks the number of this device */
 	enum tm6000_devtype		dev_type;	/* type of device */
+	unsigned char			eedata[256];	/* Eeprom data */
+	unsigned			eedata_size;	/* Size of the eeprom info */
 
 	v4l2_std_id                     norm;           /* Current norm */
 	int				width, height;	/* Selected resolution */