diff options
author | Mauro Carvalho Chehab <mchehab@infradead.org> | 2007-11-03 20:20:59 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2008-01-25 16:01:55 -0500 |
commit | 03910cc39035d27f4c85c8ad2a236cc5c9456127 (patch) | |
tree | 04c852f7f52e9568cbc68cd6c489cc4d003958a9 /drivers/media/video/em28xx/em28xx-i2c.c | |
parent | 3dbd85ba36ff74af87550e76f5765a768b108409 (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.c | 74 |
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 | */ | ||
299 | static 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 | |||
295 | static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len) | 320 | static 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 | ||
395 | static 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 | |||
415 | static 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; |