diff options
author | Antti Palosaari <crope@iki.fi> | 2011-04-07 14:51:52 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2011-05-20 08:30:07 -0400 |
commit | f71095be6645aee0828623701e35e7e7d52910d8 (patch) | |
tree | c8e0f073d203d0a4c8c8525a12d8e0a3b166a57d | |
parent | f9d0bc1c08d205008e9414a0853e4aca8b07168a (diff) |
[media] em28xx: Multi Frontend (MFE) support
Register multiple FEs for same adapter. After that it is
possible to register two FEs for same adapter. For example
one for DVB-T and one for DVB-C.
Signed-off-by: Antti Palosaari <crope@iki.fi>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r-- | drivers/media/video/em28xx/em28xx-dvb.c | 91 |
1 files changed, 56 insertions, 35 deletions
diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c index 84120596d0e3..0766bc6be14b 100644 --- a/drivers/media/video/em28xx/em28xx-dvb.c +++ b/drivers/media/video/em28xx/em28xx-dvb.c | |||
@@ -59,7 +59,7 @@ if (debug >= level) \ | |||
59 | #define EM28XX_DVB_MAX_PACKETS 64 | 59 | #define EM28XX_DVB_MAX_PACKETS 64 |
60 | 60 | ||
61 | struct em28xx_dvb { | 61 | struct em28xx_dvb { |
62 | struct dvb_frontend *frontend; | 62 | struct dvb_frontend *fe[2]; |
63 | 63 | ||
64 | /* feed count management */ | 64 | /* feed count management */ |
65 | struct mutex lock; | 65 | struct mutex lock; |
@@ -345,17 +345,17 @@ static int attach_xc3028(u8 addr, struct em28xx *dev) | |||
345 | cfg.i2c_adap = &dev->i2c_adap; | 345 | cfg.i2c_adap = &dev->i2c_adap; |
346 | cfg.i2c_addr = addr; | 346 | cfg.i2c_addr = addr; |
347 | 347 | ||
348 | if (!dev->dvb->frontend) { | 348 | if (!dev->dvb->fe[0]) { |
349 | em28xx_errdev("/2: dvb frontend not attached. " | 349 | em28xx_errdev("/2: dvb frontend not attached. " |
350 | "Can't attach xc3028\n"); | 350 | "Can't attach xc3028\n"); |
351 | return -EINVAL; | 351 | return -EINVAL; |
352 | } | 352 | } |
353 | 353 | ||
354 | fe = dvb_attach(xc2028_attach, dev->dvb->frontend, &cfg); | 354 | fe = dvb_attach(xc2028_attach, dev->dvb->fe[0], &cfg); |
355 | if (!fe) { | 355 | if (!fe) { |
356 | em28xx_errdev("/2: xc3028 attach failed\n"); | 356 | em28xx_errdev("/2: xc3028 attach failed\n"); |
357 | dvb_frontend_detach(dev->dvb->frontend); | 357 | dvb_frontend_detach(dev->dvb->fe[0]); |
358 | dev->dvb->frontend = NULL; | 358 | dev->dvb->fe[0] = NULL; |
359 | return -EINVAL; | 359 | return -EINVAL; |
360 | } | 360 | } |
361 | 361 | ||
@@ -385,16 +385,28 @@ static int register_dvb(struct em28xx_dvb *dvb, | |||
385 | } | 385 | } |
386 | 386 | ||
387 | /* Ensure all frontends negotiate bus access */ | 387 | /* Ensure all frontends negotiate bus access */ |
388 | dvb->frontend->ops.ts_bus_ctrl = em28xx_dvb_bus_ctrl; | 388 | dvb->fe[0]->ops.ts_bus_ctrl = em28xx_dvb_bus_ctrl; |
389 | if (dvb->fe[1]) | ||
390 | dvb->fe[1]->ops.ts_bus_ctrl = em28xx_dvb_bus_ctrl; | ||
389 | 391 | ||
390 | dvb->adapter.priv = dev; | 392 | dvb->adapter.priv = dev; |
391 | 393 | ||
392 | /* register frontend */ | 394 | /* register frontend */ |
393 | result = dvb_register_frontend(&dvb->adapter, dvb->frontend); | 395 | result = dvb_register_frontend(&dvb->adapter, dvb->fe[0]); |
394 | if (result < 0) { | 396 | if (result < 0) { |
395 | printk(KERN_WARNING "%s: dvb_register_frontend failed (errno = %d)\n", | 397 | printk(KERN_WARNING "%s: dvb_register_frontend failed (errno = %d)\n", |
396 | dev->name, result); | 398 | dev->name, result); |
397 | goto fail_frontend; | 399 | goto fail_frontend0; |
400 | } | ||
401 | |||
402 | /* register 2nd frontend */ | ||
403 | if (dvb->fe[1]) { | ||
404 | result = dvb_register_frontend(&dvb->adapter, dvb->fe[1]); | ||
405 | if (result < 0) { | ||
406 | printk(KERN_WARNING "%s: 2nd dvb_register_frontend failed (errno = %d)\n", | ||
407 | dev->name, result); | ||
408 | goto fail_frontend1; | ||
409 | } | ||
398 | } | 410 | } |
399 | 411 | ||
400 | /* register demux stuff */ | 412 | /* register demux stuff */ |
@@ -460,9 +472,14 @@ fail_fe_hw: | |||
460 | fail_dmxdev: | 472 | fail_dmxdev: |
461 | dvb_dmx_release(&dvb->demux); | 473 | dvb_dmx_release(&dvb->demux); |
462 | fail_dmx: | 474 | fail_dmx: |
463 | dvb_unregister_frontend(dvb->frontend); | 475 | if (dvb->fe[1]) |
464 | fail_frontend: | 476 | dvb_unregister_frontend(dvb->fe[1]); |
465 | dvb_frontend_detach(dvb->frontend); | 477 | dvb_unregister_frontend(dvb->fe[0]); |
478 | fail_frontend1: | ||
479 | if (dvb->fe[1]) | ||
480 | dvb_frontend_detach(dvb->fe[1]); | ||
481 | fail_frontend0: | ||
482 | dvb_frontend_detach(dvb->fe[0]); | ||
466 | dvb_unregister_adapter(&dvb->adapter); | 483 | dvb_unregister_adapter(&dvb->adapter); |
467 | fail_adapter: | 484 | fail_adapter: |
468 | return result; | 485 | return result; |
@@ -475,12 +492,15 @@ static void unregister_dvb(struct em28xx_dvb *dvb) | |||
475 | dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); | 492 | dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); |
476 | dvb_dmxdev_release(&dvb->dmxdev); | 493 | dvb_dmxdev_release(&dvb->dmxdev); |
477 | dvb_dmx_release(&dvb->demux); | 494 | dvb_dmx_release(&dvb->demux); |
478 | dvb_unregister_frontend(dvb->frontend); | 495 | if (dvb->fe[1]) |
479 | dvb_frontend_detach(dvb->frontend); | 496 | dvb_unregister_frontend(dvb->fe[1]); |
497 | dvb_unregister_frontend(dvb->fe[0]); | ||
498 | if (dvb->fe[1]) | ||
499 | dvb_frontend_detach(dvb->fe[1]); | ||
500 | dvb_frontend_detach(dvb->fe[0]); | ||
480 | dvb_unregister_adapter(&dvb->adapter); | 501 | dvb_unregister_adapter(&dvb->adapter); |
481 | } | 502 | } |
482 | 503 | ||
483 | |||
484 | static int dvb_init(struct em28xx *dev) | 504 | static int dvb_init(struct em28xx *dev) |
485 | { | 505 | { |
486 | int result = 0; | 506 | int result = 0; |
@@ -499,16 +519,17 @@ static int dvb_init(struct em28xx *dev) | |||
499 | return -ENOMEM; | 519 | return -ENOMEM; |
500 | } | 520 | } |
501 | dev->dvb = dvb; | 521 | dev->dvb = dvb; |
522 | dvb->fe[0] = dvb->fe[1] = NULL; | ||
502 | 523 | ||
503 | mutex_lock(&dev->lock); | 524 | mutex_lock(&dev->lock); |
504 | em28xx_set_mode(dev, EM28XX_DIGITAL_MODE); | 525 | em28xx_set_mode(dev, EM28XX_DIGITAL_MODE); |
505 | /* init frontend */ | 526 | /* init frontend */ |
506 | switch (dev->model) { | 527 | switch (dev->model) { |
507 | case EM2874_LEADERSHIP_ISDBT: | 528 | case EM2874_LEADERSHIP_ISDBT: |
508 | dvb->frontend = dvb_attach(s921_attach, | 529 | dvb->fe[0] = dvb_attach(s921_attach, |
509 | &sharp_isdbt, &dev->i2c_adap); | 530 | &sharp_isdbt, &dev->i2c_adap); |
510 | 531 | ||
511 | if (!dvb->frontend) { | 532 | if (!dvb->fe[0]) { |
512 | result = -EINVAL; | 533 | result = -EINVAL; |
513 | goto out_free; | 534 | goto out_free; |
514 | } | 535 | } |
@@ -518,7 +539,7 @@ static int dvb_init(struct em28xx *dev) | |||
518 | case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950: | 539 | case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950: |
519 | case EM2880_BOARD_PINNACLE_PCTV_HD_PRO: | 540 | case EM2880_BOARD_PINNACLE_PCTV_HD_PRO: |
520 | case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600: | 541 | case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600: |
521 | dvb->frontend = dvb_attach(lgdt330x_attach, | 542 | dvb->fe[0] = dvb_attach(lgdt330x_attach, |
522 | &em2880_lgdt3303_dev, | 543 | &em2880_lgdt3303_dev, |
523 | &dev->i2c_adap); | 544 | &dev->i2c_adap); |
524 | if (attach_xc3028(0x61, dev) < 0) { | 545 | if (attach_xc3028(0x61, dev) < 0) { |
@@ -527,7 +548,7 @@ static int dvb_init(struct em28xx *dev) | |||
527 | } | 548 | } |
528 | break; | 549 | break; |
529 | case EM2880_BOARD_KWORLD_DVB_310U: | 550 | case EM2880_BOARD_KWORLD_DVB_310U: |
530 | dvb->frontend = dvb_attach(zl10353_attach, | 551 | dvb->fe[0] = dvb_attach(zl10353_attach, |
531 | &em28xx_zl10353_with_xc3028, | 552 | &em28xx_zl10353_with_xc3028, |
532 | &dev->i2c_adap); | 553 | &dev->i2c_adap); |
533 | if (attach_xc3028(0x61, dev) < 0) { | 554 | if (attach_xc3028(0x61, dev) < 0) { |
@@ -538,7 +559,7 @@ static int dvb_init(struct em28xx *dev) | |||
538 | case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: | 559 | case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: |
539 | case EM2882_BOARD_TERRATEC_HYBRID_XS: | 560 | case EM2882_BOARD_TERRATEC_HYBRID_XS: |
540 | case EM2880_BOARD_EMPIRE_DUAL_TV: | 561 | case EM2880_BOARD_EMPIRE_DUAL_TV: |
541 | dvb->frontend = dvb_attach(zl10353_attach, | 562 | dvb->fe[0] = dvb_attach(zl10353_attach, |
542 | &em28xx_zl10353_xc3028_no_i2c_gate, | 563 | &em28xx_zl10353_xc3028_no_i2c_gate, |
543 | &dev->i2c_adap); | 564 | &dev->i2c_adap); |
544 | if (attach_xc3028(0x61, dev) < 0) { | 565 | if (attach_xc3028(0x61, dev) < 0) { |
@@ -551,13 +572,13 @@ static int dvb_init(struct em28xx *dev) | |||
551 | case EM2881_BOARD_PINNACLE_HYBRID_PRO: | 572 | case EM2881_BOARD_PINNACLE_HYBRID_PRO: |
552 | case EM2882_BOARD_DIKOM_DK300: | 573 | case EM2882_BOARD_DIKOM_DK300: |
553 | case EM2882_BOARD_KWORLD_VS_DVBT: | 574 | case EM2882_BOARD_KWORLD_VS_DVBT: |
554 | dvb->frontend = dvb_attach(zl10353_attach, | 575 | dvb->fe[0] = dvb_attach(zl10353_attach, |
555 | &em28xx_zl10353_xc3028_no_i2c_gate, | 576 | &em28xx_zl10353_xc3028_no_i2c_gate, |
556 | &dev->i2c_adap); | 577 | &dev->i2c_adap); |
557 | if (dvb->frontend == NULL) { | 578 | if (dvb->fe[0] == NULL) { |
558 | /* This board could have either a zl10353 or a mt352. | 579 | /* This board could have either a zl10353 or a mt352. |
559 | If the chip id isn't for zl10353, try mt352 */ | 580 | If the chip id isn't for zl10353, try mt352 */ |
560 | dvb->frontend = dvb_attach(mt352_attach, | 581 | dvb->fe[0] = dvb_attach(mt352_attach, |
561 | &terratec_xs_mt352_cfg, | 582 | &terratec_xs_mt352_cfg, |
562 | &dev->i2c_adap); | 583 | &dev->i2c_adap); |
563 | } | 584 | } |
@@ -569,7 +590,7 @@ static int dvb_init(struct em28xx *dev) | |||
569 | break; | 590 | break; |
570 | case EM2883_BOARD_KWORLD_HYBRID_330U: | 591 | case EM2883_BOARD_KWORLD_HYBRID_330U: |
571 | case EM2882_BOARD_EVGA_INDTUBE: | 592 | case EM2882_BOARD_EVGA_INDTUBE: |
572 | dvb->frontend = dvb_attach(s5h1409_attach, | 593 | dvb->fe[0] = dvb_attach(s5h1409_attach, |
573 | &em28xx_s5h1409_with_xc3028, | 594 | &em28xx_s5h1409_with_xc3028, |
574 | &dev->i2c_adap); | 595 | &dev->i2c_adap); |
575 | if (attach_xc3028(0x61, dev) < 0) { | 596 | if (attach_xc3028(0x61, dev) < 0) { |
@@ -578,11 +599,11 @@ static int dvb_init(struct em28xx *dev) | |||
578 | } | 599 | } |
579 | break; | 600 | break; |
580 | case EM2882_BOARD_KWORLD_ATSC_315U: | 601 | case EM2882_BOARD_KWORLD_ATSC_315U: |
581 | dvb->frontend = dvb_attach(lgdt330x_attach, | 602 | dvb->fe[0] = dvb_attach(lgdt330x_attach, |
582 | &em2880_lgdt3303_dev, | 603 | &em2880_lgdt3303_dev, |
583 | &dev->i2c_adap); | 604 | &dev->i2c_adap); |
584 | if (dvb->frontend != NULL) { | 605 | if (dvb->fe[0] != NULL) { |
585 | if (!dvb_attach(simple_tuner_attach, dvb->frontend, | 606 | if (!dvb_attach(simple_tuner_attach, dvb->fe[0], |
586 | &dev->i2c_adap, 0x61, TUNER_THOMSON_DTT761X)) { | 607 | &dev->i2c_adap, 0x61, TUNER_THOMSON_DTT761X)) { |
587 | result = -EINVAL; | 608 | result = -EINVAL; |
588 | goto out_free; | 609 | goto out_free; |
@@ -591,7 +612,7 @@ static int dvb_init(struct em28xx *dev) | |||
591 | break; | 612 | break; |
592 | case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2: | 613 | case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2: |
593 | case EM2882_BOARD_PINNACLE_HYBRID_PRO_330E: | 614 | case EM2882_BOARD_PINNACLE_HYBRID_PRO_330E: |
594 | dvb->frontend = dvb_attach(drxd_attach, &em28xx_drxd, NULL, | 615 | dvb->fe[0] = dvb_attach(drxd_attach, &em28xx_drxd, NULL, |
595 | &dev->i2c_adap, &dev->udev->dev); | 616 | &dev->i2c_adap, &dev->udev->dev); |
596 | if (attach_xc3028(0x61, dev) < 0) { | 617 | if (attach_xc3028(0x61, dev) < 0) { |
597 | result = -EINVAL; | 618 | result = -EINVAL; |
@@ -600,11 +621,11 @@ static int dvb_init(struct em28xx *dev) | |||
600 | break; | 621 | break; |
601 | case EM2870_BOARD_REDDO_DVB_C_USB_BOX: | 622 | case EM2870_BOARD_REDDO_DVB_C_USB_BOX: |
602 | /* Philips CU1216L NIM (Philips TDA10023 + Infineon TUA6034) */ | 623 | /* Philips CU1216L NIM (Philips TDA10023 + Infineon TUA6034) */ |
603 | dvb->frontend = dvb_attach(tda10023_attach, | 624 | dvb->fe[0] = dvb_attach(tda10023_attach, |
604 | &em28xx_tda10023_config, | 625 | &em28xx_tda10023_config, |
605 | &dev->i2c_adap, 0x48); | 626 | &dev->i2c_adap, 0x48); |
606 | if (dvb->frontend) { | 627 | if (dvb->fe[0]) { |
607 | if (!dvb_attach(simple_tuner_attach, dvb->frontend, | 628 | if (!dvb_attach(simple_tuner_attach, dvb->fe[0], |
608 | &dev->i2c_adap, 0x60, TUNER_PHILIPS_CU1216L)) { | 629 | &dev->i2c_adap, 0x60, TUNER_PHILIPS_CU1216L)) { |
609 | result = -EINVAL; | 630 | result = -EINVAL; |
610 | goto out_free; | 631 | goto out_free; |
@@ -612,11 +633,11 @@ static int dvb_init(struct em28xx *dev) | |||
612 | } | 633 | } |
613 | break; | 634 | break; |
614 | case EM2870_BOARD_KWORLD_A340: | 635 | case EM2870_BOARD_KWORLD_A340: |
615 | dvb->frontend = dvb_attach(lgdt3305_attach, | 636 | dvb->fe[0] = dvb_attach(lgdt3305_attach, |
616 | &em2870_lgdt3304_dev, | 637 | &em2870_lgdt3304_dev, |
617 | &dev->i2c_adap); | 638 | &dev->i2c_adap); |
618 | if (dvb->frontend != NULL) | 639 | if (dvb->fe[0] != NULL) |
619 | dvb_attach(tda18271_attach, dvb->frontend, 0x60, | 640 | dvb_attach(tda18271_attach, dvb->fe[0], 0x60, |
620 | &dev->i2c_adap, &kworld_a340_config); | 641 | &dev->i2c_adap, &kworld_a340_config); |
621 | break; | 642 | break; |
622 | default: | 643 | default: |
@@ -624,13 +645,13 @@ static int dvb_init(struct em28xx *dev) | |||
624 | " isn't supported yet\n"); | 645 | " isn't supported yet\n"); |
625 | break; | 646 | break; |
626 | } | 647 | } |
627 | if (NULL == dvb->frontend) { | 648 | if (NULL == dvb->fe[0]) { |
628 | em28xx_errdev("/2: frontend initialization failed\n"); | 649 | em28xx_errdev("/2: frontend initialization failed\n"); |
629 | result = -EINVAL; | 650 | result = -EINVAL; |
630 | goto out_free; | 651 | goto out_free; |
631 | } | 652 | } |
632 | /* define general-purpose callback pointer */ | 653 | /* define general-purpose callback pointer */ |
633 | dvb->frontend->callback = em28xx_tuner_callback; | 654 | dvb->fe[0]->callback = em28xx_tuner_callback; |
634 | 655 | ||
635 | /* register everything */ | 656 | /* register everything */ |
636 | result = register_dvb(dvb, THIS_MODULE, dev, &dev->udev->dev); | 657 | result = register_dvb(dvb, THIS_MODULE, dev, &dev->udev->dev); |