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 | |
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')
-rw-r--r-- | drivers/media/video/em28xx/em28xx-cards.c | 198 | ||||
-rw-r--r-- | drivers/media/video/em28xx/em28xx-i2c.c | 74 | ||||
-rw-r--r-- | drivers/media/video/em28xx/em28xx-video.c | 120 | ||||
-rw-r--r-- | drivers/media/video/em28xx/em28xx.h | 2 |
4 files changed, 229 insertions, 165 deletions
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 05264c655b5e..4cd49415eef2 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c | |||
@@ -37,6 +37,16 @@ | |||
37 | #include "em28xx.h" | 37 | #include "em28xx.h" |
38 | #include "tuner-xc2028.h" | 38 | #include "tuner-xc2028.h" |
39 | 39 | ||
40 | static int tuner = -1; | ||
41 | module_param(tuner, int, 0444); | ||
42 | MODULE_PARM_DESC(tuner, "tuner type"); | ||
43 | |||
44 | struct em28xx_hash_table { | ||
45 | unsigned long hash; | ||
46 | unsigned int model; | ||
47 | unsigned int tuner; | ||
48 | }; | ||
49 | |||
40 | struct em28xx_board em28xx_boards[] = { | 50 | struct em28xx_board em28xx_boards[] = { |
41 | [EM2800_BOARD_UNKNOWN] = { | 51 | [EM2800_BOARD_UNKNOWN] = { |
42 | .name = "Unknown EM2800 video grabber", | 52 | .name = "Unknown EM2800 video grabber", |
@@ -342,70 +352,178 @@ struct usb_device_id em28xx_id_table [] = { | |||
342 | { USB_DEVICE(0x0ccd, 0x0047), .driver_info = EM2880_BOARD_TERRATEC_PRODIGY_XS }, | 352 | { USB_DEVICE(0x0ccd, 0x0047), .driver_info = EM2880_BOARD_TERRATEC_PRODIGY_XS }, |
343 | { }, | 353 | { }, |
344 | }; | 354 | }; |
355 | MODULE_DEVICE_TABLE (usb, em28xx_id_table); | ||
356 | |||
357 | static struct em28xx_hash_table em28xx_hash [] = { | ||
358 | { 0, 0, 0 }, | ||
359 | }; | ||
345 | 360 | ||
361 | /* Since em28xx_pre_card_setup() requires a proper dev->model, | ||
362 | * this won't work for boards with generic PCI IDs | ||
363 | */ | ||
346 | void em28xx_pre_card_setup(struct em28xx *dev) | 364 | void em28xx_pre_card_setup(struct em28xx *dev) |
347 | { | 365 | { |
348 | /* request some modules */ | 366 | /* request some modules */ |
349 | switch(dev->model){ | 367 | switch(dev->model){ |
350 | case EM2880_BOARD_TERRATEC_PRODIGY_XS: | 368 | case EM2880_BOARD_TERRATEC_PRODIGY_XS: |
351 | case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: | 369 | case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: |
352 | case EM2880_BOARD_TERRATEC_HYBRID_XS: | 370 | case EM2880_BOARD_TERRATEC_HYBRID_XS: |
353 | { | 371 | /* reset through GPIO? */ |
354 | em28xx_write_regs_req(dev, 0x00, 0x08, "\x7d", 1); // reset through GPIO? | 372 | em28xx_write_regs_req(dev, 0x00, 0x08, "\x7d", 1); |
355 | break; | 373 | break; |
356 | } | 374 | } |
375 | } | ||
376 | |||
377 | static int em28xx_tuner_callback(void *ptr, int command, int arg) | ||
378 | { | ||
379 | int rc = 0; | ||
380 | struct em28xx *dev = ptr; | ||
381 | |||
382 | if (dev->tuner_type != TUNER_XC2028) | ||
383 | return 0; | ||
384 | |||
385 | switch (command) { | ||
386 | case XC2028_TUNER_RESET: | ||
387 | /* FIXME: This is device-dependent */ | ||
388 | dev->em28xx_write_regs_req(dev, 0x00, 0x48, "\x00", 1); | ||
389 | dev->em28xx_write_regs_req(dev, 0x00, 0x12, "\x67", 1); | ||
390 | |||
391 | msleep(140); | ||
392 | break; | ||
357 | } | 393 | } |
394 | return rc; | ||
358 | } | 395 | } |
359 | 396 | ||
360 | static void em28xx_config_tuner (struct em28xx *dev) | 397 | static void em28xx_config_tuner (struct em28xx *dev) |
361 | { | 398 | { |
362 | struct v4l2_priv_tun_config xc2028_cfg; | 399 | struct v4l2_priv_tun_config xc2028_cfg; |
363 | struct xc2028_ctrl ctl; | 400 | struct xc2028_ctrl ctl; |
401 | struct tuner_setup tun_setup; | ||
402 | struct v4l2_frequency f; | ||
403 | |||
404 | if (!dev->has_tuner) | ||
405 | return; | ||
406 | |||
407 | tun_setup.mode_mask = T_ANALOG_TV | T_RADIO; | ||
408 | tun_setup.type = dev->tuner_type; | ||
409 | tun_setup.addr = dev->tuner_addr; | ||
410 | tun_setup.tuner_callback = em28xx_tuner_callback; | ||
411 | |||
412 | em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup); | ||
413 | |||
414 | if (dev->tuner_type == TUNER_XC2028) { | ||
415 | memset (&ctl, 0, sizeof(ctl)); | ||
416 | |||
417 | ctl.fname = XC2028_DEFAULT_FIRMWARE; | ||
418 | ctl.max_len = 64; | ||
419 | |||
420 | xc2028_cfg.tuner = TUNER_XC2028; | ||
421 | xc2028_cfg.priv = &ctl; | ||
364 | 422 | ||
365 | memset (&ctl,0,sizeof(ctl)); | 423 | em28xx_i2c_call_clients(dev, TUNER_SET_CONFIG, &xc2028_cfg); |
424 | } | ||
425 | |||
426 | /* configure tuner */ | ||
427 | f.tuner = 0; | ||
428 | f.type = V4L2_TUNER_ANALOG_TV; | ||
429 | f.frequency = 9076; /* just a magic number */ | ||
430 | dev->ctl_freq = f.frequency; | ||
431 | em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, &f); | ||
432 | } | ||
433 | |||
434 | static int em28xx_hint_board(struct em28xx *dev) | ||
435 | { | ||
436 | int i; | ||
366 | 437 | ||
367 | ctl.fname = XC2028_DEFAULT_FIRMWARE; | 438 | for (i = 0; i < ARRAY_SIZE(em28xx_hash); i++) { |
368 | ctl.max_len = 64; | 439 | if (dev->hash == em28xx_hash[i].hash) { |
440 | dev->model = em28xx_hash[i].model; | ||
441 | dev->tuner_type = em28xx_hash[i].tuner; | ||
369 | 442 | ||
370 | xc2028_cfg.tuner = TUNER_XC2028; | 443 | em28xx_errdev("Your board has no unique USB ID.\n"); |
371 | xc2028_cfg.priv = &ctl; | 444 | em28xx_errdev("A hint were successfully done, " |
445 | "based on eeprom hash.\n"); | ||
446 | em28xx_errdev("This method is not 100%% failproof.\n"); | ||
447 | em28xx_errdev("If the board were missdetected, " | ||
448 | "please email this log to:\n"); | ||
449 | em28xx_errdev("\tV4L Mailing List " | ||
450 | " <video4linux-list@redhat.com>\n"); | ||
451 | em28xx_errdev("Board detected as %s\n", | ||
452 | em28xx_boards[dev->model].name); | ||
372 | 453 | ||
373 | em28xx_i2c_call_clients(dev, TUNER_SET_CONFIG, &xc2028_cfg); | 454 | return 0; |
455 | } | ||
456 | } | ||
457 | em28xx_errdev("Your board has no unique USB ID and thus need a " | ||
458 | "hint to be detected.\n"); | ||
459 | em28xx_errdev("You may try to use card=<n> insmod option to " | ||
460 | "workaround that.\n"); | ||
461 | em28xx_errdev("Please send an email with this log to:\n"); | ||
462 | em28xx_errdev("\tV4L Mailing List <video4linux-list@redhat.com>\n"); | ||
463 | em28xx_errdev("Board eeprom hash is 0x%08lx\n", dev->hash); | ||
464 | |||
465 | em28xx_errdev("Here is a list of valid choices for the card=<n>" | ||
466 | " insmod option:\n"); | ||
467 | for (i = 0; i < em28xx_bcount; i++) { | ||
468 | em28xx_errdev(" card=%d -> %s\n", | ||
469 | i, em28xx_boards[i].name); | ||
470 | } | ||
471 | return -1; | ||
374 | } | 472 | } |
375 | 473 | ||
376 | void em28xx_card_setup(struct em28xx *dev) | 474 | void em28xx_card_setup(struct em28xx *dev) |
377 | { | 475 | { |
378 | /* request some modules */ | 476 | /* request some modules */ |
379 | switch(dev->model){ | 477 | switch (dev->model) { |
380 | case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2: | 478 | case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2: |
381 | { | 479 | { |
382 | struct tveeprom tv; | 480 | struct tveeprom tv; |
383 | #ifdef CONFIG_MODULES | 481 | #ifdef CONFIG_MODULES |
384 | request_module("tveeprom"); | 482 | request_module("tveeprom"); |
385 | request_module("ir-kbd-i2c"); | 483 | request_module("ir-kbd-i2c"); |
386 | request_module("msp3400"); | ||
387 | #endif | 484 | #endif |
388 | /* Call first TVeeprom */ | 485 | /* Call first TVeeprom */ |
389 | 486 | ||
390 | dev->i2c_client.addr = 0xa0 >> 1; | 487 | dev->i2c_client.addr = 0xa0 >> 1; |
391 | tveeprom_hauppauge_analog(&dev->i2c_client, &tv, dev->eedata); | 488 | tveeprom_hauppauge_analog(&dev->i2c_client, &tv, dev->eedata); |
392 | |||
393 | dev->tuner_type= tv.tuner_type; | ||
394 | if (tv.audio_processor == AUDIO_CHIP_MSP34XX) { | ||
395 | dev->i2s_speed=2048000; | ||
396 | dev->has_msp34xx=1; | ||
397 | } else | ||
398 | dev->has_msp34xx=0; | ||
399 | break; | ||
400 | } | ||
401 | case EM2820_BOARD_KWORLD_PVRTV2800RF: | ||
402 | { | ||
403 | em28xx_write_regs_req(dev,0x00,0x08, "\xf9", 1); // GPIO enables sound on KWORLD PVR TV 2800RF | ||
404 | break; | ||
405 | } | ||
406 | 489 | ||
490 | dev->tuner_type = tv.tuner_type; | ||
491 | if (tv.audio_processor == AUDIO_CHIP_MSP34XX) { | ||
492 | dev->i2s_speed = 2048000; | ||
493 | dev->has_msp34xx = 1; | ||
494 | } | ||
495 | break; | ||
407 | } | 496 | } |
497 | case EM2820_BOARD_KWORLD_PVRTV2800RF: | ||
498 | /* GPIO enables sound on KWORLD PVR TV 2800RF */ | ||
499 | em28xx_write_regs_req(dev, 0x00, 0x08, "\xf9", 1); | ||
500 | break; | ||
501 | case EM2820_BOARD_UNKNOWN: | ||
502 | case EM2800_BOARD_UNKNOWN: | ||
503 | em28xx_hint_board(dev); | ||
504 | } | ||
505 | |||
506 | dev->is_em2800 = em28xx_boards[dev->model].is_em2800; | ||
507 | dev->has_tuner = em28xx_boards[dev->model].has_tuner; | ||
508 | dev->has_msp34xx = em28xx_boards[dev->model].has_msp34xx; | ||
509 | dev->tda9887_conf = em28xx_boards[dev->model].tda9887_conf; | ||
510 | dev->decoder = em28xx_boards[dev->model].decoder; | ||
511 | dev->video_inputs = em28xx_boards[dev->model].vchannels; | ||
512 | |||
513 | if (tuner >= 0) | ||
514 | dev->tuner_type = tuner; | ||
515 | |||
516 | #ifdef CONFIG_MODULES | ||
517 | /* request some modules */ | ||
518 | if (dev->has_msp34xx) | ||
519 | request_module("msp3400"); | ||
520 | if (dev->decoder == EM28XX_SAA7113 || dev->decoder == EM28XX_SAA7114) | ||
521 | request_module("saa7115"); | ||
522 | if (dev->decoder == EM28XX_TVP5150) | ||
523 | request_module("tvp5150"); | ||
524 | if (dev->has_tuner) | ||
525 | request_module("tuner"); | ||
526 | #endif | ||
527 | |||
408 | em28xx_config_tuner (dev); | 528 | em28xx_config_tuner (dev); |
409 | } | 529 | } |
410 | |||
411 | MODULE_DEVICE_TABLE (usb, em28xx_id_table); | ||
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; |
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index fb0fa57dec92..18b8568c634c 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c | |||
@@ -37,7 +37,6 @@ | |||
37 | #include <linux/mutex.h> | 37 | #include <linux/mutex.h> |
38 | 38 | ||
39 | #include "em28xx.h" | 39 | #include "em28xx.h" |
40 | #include <media/tuner.h> | ||
41 | #include <media/v4l2-common.h> | 40 | #include <media/v4l2-common.h> |
42 | #include <media/msp3400.h> | 41 | #include <media/msp3400.h> |
43 | 42 | ||
@@ -71,10 +70,6 @@ MODULE_PARM_DESC(card,"card type"); | |||
71 | MODULE_PARM_DESC(video_nr,"video device numbers"); | 70 | MODULE_PARM_DESC(video_nr,"video device numbers"); |
72 | MODULE_PARM_DESC(vbi_nr,"vbi device numbers"); | 71 | MODULE_PARM_DESC(vbi_nr,"vbi device numbers"); |
73 | 72 | ||
74 | static int tuner = -1; | ||
75 | module_param(tuner, int, 0444); | ||
76 | MODULE_PARM_DESC(tuner, "tuner type"); | ||
77 | |||
78 | static unsigned int video_debug = 0; | 73 | static unsigned int video_debug = 0; |
79 | module_param(video_debug,int,0644); | 74 | module_param(video_debug,int,0644); |
80 | MODULE_PARM_DESC(video_debug,"enable debug messages [video]"); | 75 | MODULE_PARM_DESC(video_debug,"enable debug messages [video]"); |
@@ -171,7 +166,6 @@ static int em28xx_config(struct em28xx *dev) | |||
171 | */ | 166 | */ |
172 | static void em28xx_config_i2c(struct em28xx *dev) | 167 | static void em28xx_config_i2c(struct em28xx *dev) |
173 | { | 168 | { |
174 | struct v4l2_frequency f; | ||
175 | struct v4l2_routing route; | 169 | struct v4l2_routing route; |
176 | 170 | ||
177 | route.input = INPUT(dev->ctl_input)->vmux; | 171 | route.input = INPUT(dev->ctl_input)->vmux; |
@@ -179,13 +173,6 @@ static void em28xx_config_i2c(struct em28xx *dev) | |||
179 | em28xx_i2c_call_clients(dev, VIDIOC_INT_RESET, NULL); | 173 | em28xx_i2c_call_clients(dev, VIDIOC_INT_RESET, NULL); |
180 | em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route); | 174 | em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route); |
181 | em28xx_i2c_call_clients(dev, VIDIOC_STREAMON, NULL); | 175 | em28xx_i2c_call_clients(dev, VIDIOC_STREAMON, NULL); |
182 | |||
183 | /* configure tuner */ | ||
184 | f.tuner = 0; | ||
185 | f.type = V4L2_TUNER_ANALOG_TV; | ||
186 | f.frequency = 9076; /* FIXME:remove magic number */ | ||
187 | dev->ctl_freq = f.frequency; | ||
188 | em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, &f); | ||
189 | } | 176 | } |
190 | 177 | ||
191 | /* | 178 | /* |
@@ -1495,7 +1482,7 @@ static const struct file_operations em28xx_v4l_fops = { | |||
1495 | * allocates and inits the device structs, registers i2c bus and v4l device | 1482 | * allocates and inits the device structs, registers i2c bus and v4l device |
1496 | */ | 1483 | */ |
1497 | static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, | 1484 | static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, |
1498 | int minor, int model) | 1485 | int minor) |
1499 | { | 1486 | { |
1500 | struct em28xx *dev = *devhandle; | 1487 | struct em28xx *dev = *devhandle; |
1501 | int retval = -ENOMEM; | 1488 | int retval = -ENOMEM; |
@@ -1503,7 +1490,6 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, | |||
1503 | unsigned int maxh, maxw; | 1490 | unsigned int maxh, maxw; |
1504 | 1491 | ||
1505 | dev->udev = udev; | 1492 | dev->udev = udev; |
1506 | dev->model = model; | ||
1507 | mutex_init(&dev->lock); | 1493 | mutex_init(&dev->lock); |
1508 | init_waitqueue_head(&dev->open); | 1494 | init_waitqueue_head(&dev->open); |
1509 | 1495 | ||
@@ -1512,43 +1498,6 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, | |||
1512 | dev->em28xx_read_reg_req_len = em28xx_read_reg_req_len; | 1498 | dev->em28xx_read_reg_req_len = em28xx_read_reg_req_len; |
1513 | dev->em28xx_write_regs_req = em28xx_write_regs_req; | 1499 | dev->em28xx_write_regs_req = em28xx_write_regs_req; |
1514 | dev->em28xx_read_reg_req = em28xx_read_reg_req; | 1500 | dev->em28xx_read_reg_req = em28xx_read_reg_req; |
1515 | dev->is_em2800 = em28xx_boards[model].is_em2800; | ||
1516 | dev->has_tuner = em28xx_boards[model].has_tuner; | ||
1517 | dev->has_msp34xx = em28xx_boards[model].has_msp34xx; | ||
1518 | dev->tda9887_conf = em28xx_boards[model].tda9887_conf; | ||
1519 | dev->decoder = em28xx_boards[model].decoder; | ||
1520 | |||
1521 | if (tuner >= 0) | ||
1522 | dev->tuner_type = tuner; | ||
1523 | else | ||
1524 | dev->tuner_type = em28xx_boards[model].tuner_type; | ||
1525 | |||
1526 | dev->video_inputs = em28xx_boards[model].vchannels; | ||
1527 | |||
1528 | for (i = 0; i < TVNORMS; i++) | ||
1529 | if (em28xx_boards[model].norm == tvnorms[i].mode) | ||
1530 | break; | ||
1531 | if (i == TVNORMS) | ||
1532 | i = 0; | ||
1533 | |||
1534 | dev->tvnorm = &tvnorms[i]; /* set default norm */ | ||
1535 | |||
1536 | em28xx_videodbg("tvnorm=%s\n", dev->tvnorm->name); | ||
1537 | |||
1538 | maxw = norm_maxw(dev); | ||
1539 | maxh = norm_maxh(dev); | ||
1540 | |||
1541 | /* set default image size */ | ||
1542 | dev->width = maxw; | ||
1543 | dev->height = maxh; | ||
1544 | dev->interlaced = EM28XX_INTERLACED_DEFAULT; | ||
1545 | dev->field_size = dev->width * dev->height; | ||
1546 | dev->frame_size = | ||
1547 | dev->interlaced ? dev->field_size << 1 : dev->field_size; | ||
1548 | dev->bytesperline = dev->width * 2; | ||
1549 | dev->hscale = 0; | ||
1550 | dev->vscale = 0; | ||
1551 | dev->ctl_input = 2; | ||
1552 | 1501 | ||
1553 | /* setup video picture settings for saa7113h */ | 1502 | /* setup video picture settings for saa7113h */ |
1554 | memset(&dev->vpic, 0, sizeof(dev->vpic)); | 1503 | memset(&dev->vpic, 0, sizeof(dev->vpic)); |
@@ -1561,24 +1510,17 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, | |||
1561 | dev->vpic.palette = VIDEO_PALETTE_YUV422; | 1510 | dev->vpic.palette = VIDEO_PALETTE_YUV422; |
1562 | 1511 | ||
1563 | em28xx_pre_card_setup(dev); | 1512 | em28xx_pre_card_setup(dev); |
1564 | #ifdef CONFIG_MODULES | 1513 | |
1565 | /* request some modules */ | ||
1566 | if (dev->decoder == EM28XX_SAA7113 || dev->decoder == EM28XX_SAA7114) | ||
1567 | request_module("saa7115"); | ||
1568 | if (dev->decoder == EM28XX_TVP5150) | ||
1569 | request_module("tvp5150"); | ||
1570 | if (dev->has_tuner) | ||
1571 | request_module("tuner"); | ||
1572 | #endif | ||
1573 | errCode = em28xx_config(dev); | 1514 | errCode = em28xx_config(dev); |
1574 | if (errCode) { | 1515 | if (errCode) { |
1575 | em28xx_errdev("error configuring device\n"); | 1516 | em28xx_errdev("error configuring device\n"); |
1576 | em28xx_devused&=~(1<<dev->devno); | 1517 | em28xx_devused &= ~(1<<dev->devno); |
1577 | kfree(dev); | 1518 | kfree(dev); |
1578 | return -ENOMEM; | 1519 | return -ENOMEM; |
1579 | } | 1520 | } |
1580 | 1521 | ||
1581 | mutex_lock(&dev->lock); | 1522 | mutex_lock(&dev->lock); |
1523 | |||
1582 | /* register i2c bus */ | 1524 | /* register i2c bus */ |
1583 | em28xx_i2c_register(dev); | 1525 | em28xx_i2c_register(dev); |
1584 | 1526 | ||
@@ -1590,12 +1532,33 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, | |||
1590 | 1532 | ||
1591 | mutex_unlock(&dev->lock); | 1533 | mutex_unlock(&dev->lock); |
1592 | 1534 | ||
1535 | for (i = 0; i < TVNORMS; i++) | ||
1536 | if (em28xx_boards[dev->model].norm == tvnorms[i].mode) | ||
1537 | break; | ||
1538 | if (i == TVNORMS) | ||
1539 | i = 0; | ||
1540 | |||
1541 | dev->tvnorm = &tvnorms[i]; /* set default norm */ | ||
1542 | |||
1543 | em28xx_videodbg("tvnorm=%s\n", dev->tvnorm->name); | ||
1544 | |||
1545 | maxw = norm_maxw(dev); | ||
1546 | maxh = norm_maxh(dev); | ||
1547 | |||
1548 | /* set default image size */ | ||
1549 | dev->width = maxw; | ||
1550 | dev->height = maxh; | ||
1551 | dev->interlaced = EM28XX_INTERLACED_DEFAULT; | ||
1552 | dev->field_size = dev->width * dev->height; | ||
1553 | dev->frame_size = | ||
1554 | dev->interlaced ? dev->field_size << 1 : dev->field_size; | ||
1555 | dev->bytesperline = dev->width * 2; | ||
1556 | dev->hscale = 0; | ||
1557 | dev->vscale = 0; | ||
1558 | dev->ctl_input = 2; | ||
1559 | |||
1593 | errCode = em28xx_config(dev); | 1560 | errCode = em28xx_config(dev); |
1594 | 1561 | ||
1595 | #ifdef CONFIG_MODULES | ||
1596 | if (dev->has_msp34xx) | ||
1597 | request_module("msp3400"); | ||
1598 | #endif | ||
1599 | /* allocate and fill v4l2 device struct */ | 1562 | /* allocate and fill v4l2 device struct */ |
1600 | dev->vdev = video_device_alloc(); | 1563 | dev->vdev = video_device_alloc(); |
1601 | if (NULL == dev->vdev) { | 1564 | if (NULL == dev->vdev) { |
@@ -1695,7 +1658,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, | |||
1695 | struct usb_interface *uif; | 1658 | struct usb_interface *uif; |
1696 | struct em28xx *dev = NULL; | 1659 | struct em28xx *dev = NULL; |
1697 | int retval = -ENODEV; | 1660 | int retval = -ENODEV; |
1698 | int model,i,nr,ifnum; | 1661 | int i, nr, ifnum; |
1699 | 1662 | ||
1700 | udev = usb_get_dev(interface_to_usbdev(interface)); | 1663 | udev = usb_get_dev(interface_to_usbdev(interface)); |
1701 | ifnum = interface->altsetting[0].desc.bInterfaceNumber; | 1664 | ifnum = interface->altsetting[0].desc.bInterfaceNumber; |
@@ -1735,8 +1698,6 @@ static int em28xx_usb_probe(struct usb_interface *interface, | |||
1735 | return -ENODEV; | 1698 | return -ENODEV; |
1736 | } | 1699 | } |
1737 | 1700 | ||
1738 | model=id->driver_info; | ||
1739 | |||
1740 | if (nr >= EM28XX_MAXBOARDS) { | 1701 | if (nr >= EM28XX_MAXBOARDS) { |
1741 | printk (DRIVER_NAME ": Supports only %i em28xx boards.\n",EM28XX_MAXBOARDS); | 1702 | printk (DRIVER_NAME ": Supports only %i em28xx boards.\n",EM28XX_MAXBOARDS); |
1742 | em28xx_devused&=~(1<<nr); | 1703 | em28xx_devused&=~(1<<nr); |
@@ -1752,7 +1713,8 @@ static int em28xx_usb_probe(struct usb_interface *interface, | |||
1752 | } | 1713 | } |
1753 | 1714 | ||
1754 | snprintf(dev->name, 29, "em28xx #%d", nr); | 1715 | snprintf(dev->name, 29, "em28xx #%d", nr); |
1755 | dev->devno=nr; | 1716 | dev->devno = nr; |
1717 | dev->model = id->driver_info; | ||
1756 | 1718 | ||
1757 | /* compute alternate max packet sizes */ | 1719 | /* compute alternate max packet sizes */ |
1758 | uif = udev->actconfig->interface[0]; | 1720 | uif = udev->actconfig->interface[0]; |
@@ -1779,26 +1741,14 @@ static int em28xx_usb_probe(struct usb_interface *interface, | |||
1779 | } | 1741 | } |
1780 | 1742 | ||
1781 | if ((card[nr]>=0)&&(card[nr]<em28xx_bcount)) | 1743 | if ((card[nr]>=0)&&(card[nr]<em28xx_bcount)) |
1782 | model=card[nr]; | 1744 | dev->model = card[nr]; |
1783 | |||
1784 | if ((model==EM2800_BOARD_UNKNOWN)||(model==EM2820_BOARD_UNKNOWN)) { | ||
1785 | em28xx_errdev("Your board has no unique USB ID and thus can't be autodetected.\n"); | ||
1786 | em28xx_errdev("Please pass card=<n> insmod option to workaround that.\n"); | ||
1787 | em28xx_errdev("If there isn't any card number for you, please send an email to:\n"); | ||
1788 | em28xx_errdev("\tV4L Mailing List <video4linux-list@redhat.com>\n"); | ||
1789 | em28xx_errdev("Here is a list of valid choices for the card=<n> insmod option:\n"); | ||
1790 | for (i = 0; i < em28xx_bcount; i++) { | ||
1791 | em28xx_errdev(" card=%d -> %s\n", i, | ||
1792 | em28xx_boards[i].name); | ||
1793 | } | ||
1794 | } | ||
1795 | 1745 | ||
1796 | /* allocate device struct */ | 1746 | /* allocate device struct */ |
1797 | retval = em28xx_init_dev(&dev, udev, nr, model); | 1747 | retval = em28xx_init_dev(&dev, udev, nr); |
1798 | if (retval) | 1748 | if (retval) |
1799 | return retval; | 1749 | return retval; |
1800 | 1750 | ||
1801 | em28xx_info("Found %s\n", em28xx_boards[model].name); | 1751 | em28xx_info("Found %s\n", em28xx_boards[dev->model].name); |
1802 | 1752 | ||
1803 | /* save our data pointer in this interface device */ | 1753 | /* save our data pointer in this interface device */ |
1804 | usb_set_intfdata(interface, dev); | 1754 | usb_set_intfdata(interface, dev); |
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index d8fcc9e17ac0..e98dac7fc05b 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h | |||
@@ -257,6 +257,8 @@ struct em28xx { | |||
257 | int interlaced; /* 1=interlace fileds, 0=just top fileds */ | 257 | int interlaced; /* 1=interlace fileds, 0=just top fileds */ |
258 | int type; | 258 | int type; |
259 | 259 | ||
260 | unsigned long hash; /* eeprom hash - for boards with generic ID */ | ||
261 | |||
260 | /* states */ | 262 | /* states */ |
261 | enum em28xx_dev_state state; | 263 | enum em28xx_dev_state state; |
262 | enum em28xx_stream_state stream; | 264 | enum em28xx_stream_state stream; |