aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/em28xx/em28xx-i2c.c
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@infradead.org>2007-11-03 20:20:59 -0400
committerMauro Carvalho Chehab <mchehab@infradead.org>2008-01-25 16:01:55 -0500
commit03910cc39035d27f4c85c8ad2a236cc5c9456127 (patch)
tree04c852f7f52e9568cbc68cd6c489cc4d003958a9 /drivers/media/video/em28xx/em28xx-i2c.c
parent3dbd85ba36ff74af87550e76f5765a768b108409 (diff)
V4L/DVB (6536): Add a hint for boards without unique USB ID
This patch adds a function to allow trying to detect boards that shares the generic IDs. The current detection method is based at eeprom checksum. Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/video/em28xx/em28xx-i2c.c')
-rw-r--r--drivers/media/video/em28xx/em28xx-i2c.c74
1 files changed, 34 insertions, 40 deletions
diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c
index a33878e08799..e2003455f2b2 100644
--- a/drivers/media/video/em28xx/em28xx-i2c.c
+++ b/drivers/media/video/em28xx/em28xx-i2c.c
@@ -292,6 +292,31 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
292 return rc; 292 return rc;
293} 293}
294 294
295/* based on linux/sunrpc/svcauth.h and linux/hash.h
296 * The original hash function returns a different value, if arch is x86_64
297 * or i386.
298 */
299static inline unsigned long em28xx_hash_mem(char *buf, int length, int bits)
300{
301 unsigned long hash = 0;
302 unsigned long l = 0;
303 int len = 0;
304 unsigned char c;
305 do {
306 if (len == length) {
307 c = (char)len;
308 len = -1;
309 } else
310 c = *buf++;
311 l = (l << 8) | c;
312 len++;
313 if ((len & (32 / 8 - 1)) == 0)
314 hash = ((hash^l) * 0x9e370001UL);
315 } while (len);
316
317 return (hash >> (32 - bits)) & 0xffffffffUL;
318}
319
295static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len) 320static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
296{ 321{
297 unsigned char buf, *p = eedata; 322 unsigned char buf, *p = eedata;
@@ -335,7 +360,11 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
335 printk("\n"); 360 printk("\n");
336 } 361 }
337 362
338 printk(KERN_INFO "EEPROM ID= 0x%08x\n", em_eeprom->id); 363 if (em_eeprom->id == 0x9567eb1a)
364 dev->hash = em28xx_hash_mem(eedata, len, 32);
365
366 printk(KERN_INFO "EEPROM ID= 0x%08x, hash = 0x%08lx\n",
367 em_eeprom->id, dev->hash);
339 printk(KERN_INFO "Vendor/Product ID= %04x:%04x\n", em_eeprom->vendor_ID, 368 printk(KERN_INFO "Vendor/Product ID= %04x:%04x\n", em_eeprom->vendor_ID,
340 em_eeprom->product_ID); 369 em_eeprom->product_ID);
341 370
@@ -392,43 +421,6 @@ static u32 functionality(struct i2c_adapter *adap)
392} 421}
393 422
394 423
395static int em28xx_tuner_callback(void *ptr, int command, int arg)
396{
397 int rc = 0;
398 struct em28xx *dev = ptr;
399
400 if (dev->tuner_type != TUNER_XC2028)
401 return 0;
402
403 switch (command) {
404 case XC2028_TUNER_RESET:
405 /* FIXME: This is device-dependent */
406 dev->em28xx_write_regs_req(dev, 0x00, 0x48, "\x00", 1);
407 dev->em28xx_write_regs_req(dev, 0x00, 0x12, "\x67", 1);
408
409 msleep(140);
410 break;
411 }
412 return rc;
413}
414
415static int em28xx_set_tuner(int check_eeprom, struct i2c_client *client)
416{
417 struct em28xx *dev = client->adapter->algo_data;
418 struct tuner_setup tun_setup;
419
420 if (dev->has_tuner) {
421 tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
422 tun_setup.type = dev->tuner_type;
423 tun_setup.addr = dev->tuner_addr;
424 tun_setup.tuner_callback = em28xx_tuner_callback;
425
426 em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup);
427 }
428
429 return (0);
430}
431
432/* 424/*
433 * attach_inform() 425 * attach_inform()
434 * gets called when a device attaches to the i2c bus 426 * gets called when a device attaches to the i2c bus
@@ -487,9 +479,11 @@ static int attach_inform(struct i2c_client *client)
487 break; 479 break;
488 480
489 default: 481 default:
482 if (!dev->tuner_addr)
483 dev->tuner_addr = client->addr;
484
490 dprintk1(1,"attach inform: detected I2C address %x\n", client->addr << 1); 485 dprintk1(1,"attach inform: detected I2C address %x\n", client->addr << 1);
491 dev->tuner_addr = client->addr; 486
492 em28xx_set_tuner(-1, client);
493 } 487 }
494 488
495 return 0; 489 return 0;