diff options
author | Malcolm Priestley <tvboxspy@gmail.com> | 2010-10-27 18:50:36 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2010-12-29 05:16:29 -0500 |
commit | f23e6616ac2dc560db0ee8733024ebe90de9161a (patch) | |
tree | b6baf41a30063dd82e470fa872386feccfc4fe1e | |
parent | ea7c681e899bda3fceb37815d63d201c3b4be920 (diff) |
[media] lmed04: Improve frontend handling
Improved frontend handling.
Frontend now remains open at all times, with signal lock, snr & signal level
polled from Interupt.
Updated driver for DM04/QQBOX USB DVB-S BOXES to version 1.70.
Signed-off-by: Malcolm Priestley <tvboxspy@gmail.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r-- | drivers/media/dvb/dvb-usb/lmedm04.c | 153 |
1 files changed, 71 insertions, 82 deletions
diff --git a/drivers/media/dvb/dvb-usb/lmedm04.c b/drivers/media/dvb/dvb-usb/lmedm04.c index d939fbbf9fe6..3a32c65ee04c 100644 --- a/drivers/media/dvb/dvb-usb/lmedm04.c +++ b/drivers/media/dvb/dvb-usb/lmedm04.c | |||
@@ -112,7 +112,6 @@ struct lme2510_state { | |||
112 | u8 i2c_tuner_gate_r; | 112 | u8 i2c_tuner_gate_r; |
113 | u8 i2c_tuner_addr; | 113 | u8 i2c_tuner_addr; |
114 | u8 stream_on; | 114 | u8 stream_on; |
115 | u8 one_tune; | ||
116 | void *buffer; | 115 | void *buffer; |
117 | struct urb *lme_urb; | 116 | struct urb *lme_urb; |
118 | void *usb_buffer; | 117 | void *usb_buffer; |
@@ -182,15 +181,13 @@ static int lme2510_usb_talk(struct dvb_usb_device *d, | |||
182 | return (ret < 0) ? -ENODEV : 0; | 181 | return (ret < 0) ? -ENODEV : 0; |
183 | } | 182 | } |
184 | 183 | ||
185 | static int lme2510_usb_talk_restart(struct dvb_usb_device *d, | 184 | static int lme2510_stream_restart(struct dvb_usb_device *d) |
186 | u8 *wbuf, int wlen, u8 *rbuf, int rlen) { | 185 | { |
187 | static u8 stream_on[] = LME_ST_ON_W; | 186 | static u8 stream_on[] = LME_ST_ON_W; |
188 | int ret; | 187 | int ret; |
189 | u8 rbuff[10]; | 188 | u8 rbuff[10]; |
190 | /*Send Normal Command*/ | ||
191 | ret = lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen); | ||
192 | /*Restart Stream Command*/ | 189 | /*Restart Stream Command*/ |
193 | ret |= lme2510_usb_talk(d, stream_on, sizeof(stream_on), | 190 | ret = lme2510_usb_talk(d, stream_on, sizeof(stream_on), |
194 | rbuff, sizeof(rbuff)); | 191 | rbuff, sizeof(rbuff)); |
195 | return ret; | 192 | return ret; |
196 | } | 193 | } |
@@ -254,11 +251,16 @@ static void lme2510_int_response(struct urb *lme_urb) | |||
254 | case TUNER_S7395: | 251 | case TUNER_S7395: |
255 | /* Tweak for earlier firmware*/ | 252 | /* Tweak for earlier firmware*/ |
256 | if (ibuf[1] == 0x03) { | 253 | if (ibuf[1] == 0x03) { |
254 | if (ibuf[2] > 1) | ||
255 | st->signal_lock = ibuf[2]; | ||
257 | st->signal_level = ibuf[3]; | 256 | st->signal_level = ibuf[3]; |
258 | st->signal_sn = ibuf[4]; | 257 | st->signal_sn = ibuf[4]; |
259 | } else { | 258 | } else { |
260 | st->signal_level = ibuf[4]; | 259 | st->signal_level = ibuf[4]; |
261 | st->signal_sn = ibuf[5]; | 260 | st->signal_sn = ibuf[5]; |
261 | st->signal_lock = | ||
262 | (st->signal_lock & 0xf7) + | ||
263 | ((ibuf[2] & 0x01) << 0x03); | ||
262 | } | 264 | } |
263 | break; | 265 | break; |
264 | default: | 266 | default: |
@@ -341,11 +343,10 @@ static int lme2510_msg(struct dvb_usb_device *d, | |||
341 | st->signal_lock = rbuf[1]; | 343 | st->signal_lock = rbuf[1]; |
342 | if ((st->stream_on & 1) && | 344 | if ((st->stream_on & 1) && |
343 | (st->signal_lock & 0x10)) { | 345 | (st->signal_lock & 0x10)) { |
344 | lme2510_usb_talk_restart(d, | 346 | lme2510_stream_restart(d); |
345 | wbuf, wlen, rbuf, rlen); | ||
346 | st->i2c_talk_onoff = 0; | 347 | st->i2c_talk_onoff = 0; |
347 | } | 348 | } |
348 | msleep(80); | 349 | msleep(80); |
349 | } | 350 | } |
350 | } | 351 | } |
351 | break; | 352 | break; |
@@ -355,15 +356,12 @@ static int lme2510_msg(struct dvb_usb_device *d, | |||
355 | st->signal_lock = rbuf[1]; | 356 | st->signal_lock = rbuf[1]; |
356 | if ((st->stream_on & 1) && | 357 | if ((st->stream_on & 1) && |
357 | (st->signal_lock & 0x8)) { | 358 | (st->signal_lock & 0x8)) { |
358 | lme2510_usb_talk_restart(d, | 359 | lme2510_stream_restart(d); |
359 | wbuf, wlen, rbuf, rlen); | ||
360 | st->i2c_talk_onoff = 0; | 360 | st->i2c_talk_onoff = 0; |
361 | } | 361 | } |
362 | } | 362 | } |
363 | if ((wbuf[3] != 0x6) & (wbuf[3] != 0x5)) | 363 | if ((wbuf[3] != 0x6) & (wbuf[3] != 0x5)) |
364 | msleep(5); | 364 | msleep(5); |
365 | |||
366 | |||
367 | } | 365 | } |
368 | break; | 366 | break; |
369 | default: | 367 | default: |
@@ -385,18 +383,16 @@ static int lme2510_msg(struct dvb_usb_device *d, | |||
385 | rbuf[0] = 0x55; | 383 | rbuf[0] = 0x55; |
386 | rbuf[1] = st->signal_sn; | 384 | rbuf[1] = st->signal_sn; |
387 | break; | 385 | break; |
388 | /*DiSEqC functions as per TDA10086*/ | 386 | case 0x15: |
389 | case 0x36: | 387 | case 0x16: |
390 | case 0x48: | 388 | case 0x17: |
391 | case 0x49: | 389 | case 0x18: |
392 | case 0x4a: | 390 | rbuf[0] = 0x55; |
393 | case 0x4b: | 391 | rbuf[1] = 0x00; |
394 | case 0x4c: | 392 | break; |
395 | case 0x4d: | ||
396 | if (wbuf[2] == 0x1c) | ||
397 | lme2510_usb_talk_restart(d, | ||
398 | wbuf, wlen, rbuf, rlen); | ||
399 | default: | 393 | default: |
394 | lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen); | ||
395 | st->i2c_talk_onoff = 1; | ||
400 | break; | 396 | break; |
401 | } | 397 | } |
402 | break; | 398 | break; |
@@ -413,39 +409,22 @@ static int lme2510_msg(struct dvb_usb_device *d, | |||
413 | break; | 409 | break; |
414 | case 0x24: | 410 | case 0x24: |
415 | rbuf[0] = 0x55; | 411 | rbuf[0] = 0x55; |
416 | rbuf[1] = (st->signal_level & 0x80) | 412 | rbuf[1] = st->signal_lock; |
417 | ? 0 : st->signal_lock; | ||
418 | break; | ||
419 | case 0x6: | ||
420 | if (wbuf[2] == 0xd0) | ||
421 | lme2510_usb_talk(d, | ||
422 | wbuf, wlen, rbuf, rlen); | ||
423 | break; | ||
424 | case 0x1: | ||
425 | if (st->one_tune > 0) | ||
426 | break; | ||
427 | st->one_tune++; | ||
428 | st->i2c_talk_onoff = 1; | ||
429 | /*DiSEqC functions as per STV0288*/ | ||
430 | case 0x5: | ||
431 | case 0x7: | ||
432 | case 0x8: | ||
433 | case 0x9: | ||
434 | case 0xa: | ||
435 | case 0xb: | ||
436 | if (wbuf[2] == 0xd0) | ||
437 | lme2510_usb_talk_restart(d, | ||
438 | wbuf, wlen, rbuf, rlen); | ||
439 | break; | 413 | break; |
440 | default: | 414 | case 0x2e: |
415 | case 0x26: | ||
416 | case 0x27: | ||
441 | rbuf[0] = 0x55; | 417 | rbuf[0] = 0x55; |
442 | rbuf[1] = 0x00; | 418 | rbuf[1] = 0x00; |
443 | break; | 419 | break; |
420 | default: | ||
421 | lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen); | ||
422 | st->i2c_talk_onoff = 1; | ||
423 | break; | ||
444 | } | 424 | } |
445 | break; | 425 | break; |
446 | default: | 426 | default: |
447 | break; | 427 | break; |
448 | |||
449 | } | 428 | } |
450 | 429 | ||
451 | deb_info(4, "I2C From Interupt Message out(%02x) in(%02x)", | 430 | deb_info(4, "I2C From Interupt Message out(%02x) in(%02x)", |
@@ -548,35 +527,26 @@ static int lme2510_identify_state(struct usb_device *udev, | |||
548 | static int lme2510_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) | 527 | static int lme2510_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) |
549 | { | 528 | { |
550 | struct lme2510_state *st = adap->dev->priv; | 529 | struct lme2510_state *st = adap->dev->priv; |
551 | static u8 stream_on[] = LME_ST_ON_W; | ||
552 | static u8 clear_reg_3[] = LME_CLEAR_PID; | 530 | static u8 clear_reg_3[] = LME_CLEAR_PID; |
553 | static u8 rbuf[1]; | 531 | static u8 rbuf[1]; |
554 | static u8 timeout; | 532 | int ret = 0, rlen = sizeof(rbuf); |
555 | int ret = 0, len = 2, rlen = sizeof(rbuf); | ||
556 | 533 | ||
557 | deb_info(1, "STM (%02x)", onoff); | 534 | deb_info(1, "STM (%02x)", onoff); |
558 | 535 | ||
559 | if (onoff == 1) { | 536 | /* Streaming is started by FE_HAS_LOCK */ |
560 | st->i2c_talk_onoff = 0; | 537 | if (onoff == 1) |
561 | timeout = 0; | ||
562 | /* wait for i2C to be free */ | ||
563 | while (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0) { | ||
564 | timeout++; | ||
565 | if (timeout > 5) | ||
566 | return -ENODEV; | ||
567 | } | ||
568 | msleep(100); | ||
569 | ret |= lme2510_usb_talk(adap->dev, | ||
570 | stream_on, len, rbuf, rlen); | ||
571 | st->stream_on = 1; | 538 | st->stream_on = 1; |
572 | st->one_tune = 0; | 539 | else { |
573 | mutex_unlock(&adap->dev->i2c_mutex); | ||
574 | } else { | ||
575 | deb_info(1, "STM Steam Off"); | 540 | deb_info(1, "STM Steam Off"); |
541 | /* mutex is here only to avoid collision with I2C */ | ||
542 | ret = mutex_lock_interruptible(&adap->dev->i2c_mutex); | ||
543 | |||
576 | ret |= lme2510_usb_talk(adap->dev, clear_reg_3, | 544 | ret |= lme2510_usb_talk(adap->dev, clear_reg_3, |
577 | sizeof(clear_reg_3), rbuf, rlen); | 545 | sizeof(clear_reg_3), rbuf, rlen); |
578 | st->stream_on = 0; | 546 | st->stream_on = 0; |
579 | st->i2c_talk_onoff = 1; | 547 | st->i2c_talk_onoff = 1; |
548 | |||
549 | mutex_unlock(&adap->dev->i2c_mutex); | ||
580 | } | 550 | } |
581 | 551 | ||
582 | return (ret < 0) ? -ENODEV : 0; | 552 | return (ret < 0) ? -ENODEV : 0; |
@@ -619,6 +589,7 @@ static int lme2510_int_service(struct dvb_usb_adapter *adap) | |||
619 | ir_input_unregister(input_dev); | 589 | ir_input_unregister(input_dev); |
620 | input_free_device(input_dev); | 590 | input_free_device(input_dev); |
621 | } | 591 | } |
592 | |||
622 | return (ret < 0) ? -ENODEV : 0; | 593 | return (ret < 0) ? -ENODEV : 0; |
623 | } | 594 | } |
624 | 595 | ||
@@ -668,6 +639,7 @@ static int lme2510_download_firmware(struct usb_device *dev, | |||
668 | ret |= (data[0] == 0x88) ? 0 : -1; | 639 | ret |= (data[0] == 0x88) ? 0 : -1; |
669 | } | 640 | } |
670 | } | 641 | } |
642 | |||
671 | usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), | 643 | usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), |
672 | 0x06, 0x80, 0x0200, 0x00, data, 0x0109, 1000); | 644 | 0x06, 0x80, 0x0200, 0x00, data, 0x0109, 1000); |
673 | 645 | ||
@@ -701,6 +673,7 @@ static void lme_coldreset(struct usb_device *dev) | |||
701 | info("FRM Firmware Cold Reset"); | 673 | info("FRM Firmware Cold Reset"); |
702 | ret |= lme2510_bulk_write(dev, data , len_in, 1); /*Cold Resetting*/ | 674 | ret |= lme2510_bulk_write(dev, data , len_in, 1); /*Cold Resetting*/ |
703 | ret |= lme2510_bulk_read(dev, data, len_in, 1); | 675 | ret |= lme2510_bulk_read(dev, data, len_in, 1); |
676 | |||
704 | return; | 677 | return; |
705 | } | 678 | } |
706 | 679 | ||
@@ -712,6 +685,8 @@ static void lme_firmware_switch(struct usb_device *udev, int cold) | |||
712 | char *firm_msg[] = {"Loading", "Switching to"}; | 685 | char *firm_msg[] = {"Loading", "Switching to"}; |
713 | int ret; | 686 | int ret; |
714 | 687 | ||
688 | cold = (cold > 0) ? (cold & 1) : 0; | ||
689 | |||
715 | if (udev->descriptor.idProduct == 0x1122) | 690 | if (udev->descriptor.idProduct == 0x1122) |
716 | return; | 691 | return; |
717 | 692 | ||
@@ -740,22 +715,26 @@ static void lme_firmware_switch(struct usb_device *udev, int cold) | |||
740 | cold = 0; | 715 | cold = 0; |
741 | break; | 716 | break; |
742 | } | 717 | } |
718 | |||
743 | release_firmware(fw); | 719 | release_firmware(fw); |
720 | |||
744 | if (cold) | 721 | if (cold) |
745 | lme_coldreset(udev); | 722 | lme_coldreset(udev); |
723 | |||
746 | return; | 724 | return; |
747 | } | 725 | } |
748 | 726 | ||
749 | static int lme2510_kill_urb(struct usb_data_stream *stream) | 727 | static int lme2510_kill_urb(struct usb_data_stream *stream) |
750 | { | 728 | { |
751 | int i; | 729 | int i; |
730 | |||
752 | for (i = 0; i < stream->urbs_submitted; i++) { | 731 | for (i = 0; i < stream->urbs_submitted; i++) { |
753 | deb_info(3, "killing URB no. %d.", i); | 732 | deb_info(3, "killing URB no. %d.", i); |
754 | |||
755 | /* stop the URB */ | 733 | /* stop the URB */ |
756 | usb_kill_urb(stream->urb_list[i]); | 734 | usb_kill_urb(stream->urb_list[i]); |
757 | } | 735 | } |
758 | stream->urbs_submitted = 0; | 736 | stream->urbs_submitted = 0; |
737 | |||
759 | return 0; | 738 | return 0; |
760 | } | 739 | } |
761 | 740 | ||
@@ -783,18 +762,13 @@ static int dm04_lme2510_set_voltage(struct dvb_frontend *fe, | |||
783 | fe_sec_voltage_t voltage) | 762 | fe_sec_voltage_t voltage) |
784 | { | 763 | { |
785 | struct dvb_usb_adapter *adap = fe->dvb->priv; | 764 | struct dvb_usb_adapter *adap = fe->dvb->priv; |
786 | struct lme2510_state *st = adap->dev->priv; | ||
787 | static u8 voltage_low[] = LME_VOLTAGE_L; | 765 | static u8 voltage_low[] = LME_VOLTAGE_L; |
788 | static u8 voltage_high[] = LME_VOLTAGE_H; | 766 | static u8 voltage_high[] = LME_VOLTAGE_H; |
789 | static u8 lnb_on[] = LNB_ON; | ||
790 | static u8 lnb_off[] = LNB_OFF; | ||
791 | static u8 rbuf[1]; | 767 | static u8 rbuf[1]; |
792 | int ret = 0, len = 3, rlen = 1; | 768 | int ret = 0, len = 3, rlen = 1; |
793 | 769 | ||
794 | if (st->stream_on == 1) | 770 | if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0) |
795 | return 0; | 771 | return -EAGAIN; |
796 | |||
797 | ret |= lme2510_usb_talk(adap->dev, lnb_on, len, rbuf, rlen); | ||
798 | 772 | ||
799 | switch (voltage) { | 773 | switch (voltage) { |
800 | case SEC_VOLTAGE_18: | 774 | case SEC_VOLTAGE_18: |
@@ -803,17 +777,15 @@ static int dm04_lme2510_set_voltage(struct dvb_frontend *fe, | |||
803 | break; | 777 | break; |
804 | 778 | ||
805 | case SEC_VOLTAGE_OFF: | 779 | case SEC_VOLTAGE_OFF: |
806 | ret |= lme2510_usb_talk(adap->dev, | ||
807 | lnb_off, len, rbuf, rlen); | ||
808 | case SEC_VOLTAGE_13: | 780 | case SEC_VOLTAGE_13: |
809 | default: | 781 | default: |
810 | ret |= lme2510_usb_talk(adap->dev, | 782 | ret |= lme2510_usb_talk(adap->dev, |
811 | voltage_low, len, rbuf, rlen); | 783 | voltage_low, len, rbuf, rlen); |
812 | break; | 784 | break; |
785 | } | ||
813 | 786 | ||
787 | mutex_unlock(&adap->dev->i2c_mutex); | ||
814 | 788 | ||
815 | }; | ||
816 | st->i2c_talk_onoff = 1; | ||
817 | return (ret < 0) ? -ENODEV : 0; | 789 | return (ret < 0) ? -ENODEV : 0; |
818 | } | 790 | } |
819 | 791 | ||
@@ -850,12 +822,14 @@ static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap) | |||
850 | if (dvb_usb_lme2510_firmware != 1) { | 822 | if (dvb_usb_lme2510_firmware != 1) { |
851 | dvb_usb_lme2510_firmware = 1; | 823 | dvb_usb_lme2510_firmware = 1; |
852 | lme_firmware_switch(adap->dev->udev, 1); | 824 | lme_firmware_switch(adap->dev->udev, 1); |
853 | } | 825 | } else /*stops LG/Sharp multi tuner problems*/ |
826 | dvb_usb_lme2510_firmware = 0; | ||
854 | return 0; | 827 | return 0; |
855 | } | 828 | } |
856 | kfree(adap->fe); | 829 | kfree(adap->fe); |
857 | adap->fe = NULL; | 830 | adap->fe = NULL; |
858 | } | 831 | } |
832 | |||
859 | st->i2c_gate = 5; | 833 | st->i2c_gate = 5; |
860 | adap->fe = dvb_attach(stv0288_attach, &lme_config, | 834 | adap->fe = dvb_attach(stv0288_attach, &lme_config, |
861 | &adap->dev->i2c_adap); | 835 | &adap->dev->i2c_adap); |
@@ -889,8 +863,23 @@ static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap) | |||
889 | static int lme2510_powerup(struct dvb_usb_device *d, int onoff) | 863 | static int lme2510_powerup(struct dvb_usb_device *d, int onoff) |
890 | { | 864 | { |
891 | struct lme2510_state *st = d->priv; | 865 | struct lme2510_state *st = d->priv; |
866 | static u8 lnb_on[] = LNB_ON; | ||
867 | static u8 lnb_off[] = LNB_OFF; | ||
868 | static u8 rbuf[1]; | ||
869 | int ret, len = 3, rlen = 1; | ||
870 | |||
871 | ret = mutex_lock_interruptible(&d->i2c_mutex); | ||
872 | |||
873 | if (onoff) | ||
874 | ret |= lme2510_usb_talk(d, lnb_on, len, rbuf, rlen); | ||
875 | else | ||
876 | ret |= lme2510_usb_talk(d, lnb_off, len, rbuf, rlen); | ||
877 | |||
892 | st->i2c_talk_onoff = 1; | 878 | st->i2c_talk_onoff = 1; |
893 | return 0; | 879 | |
880 | mutex_unlock(&d->i2c_mutex); | ||
881 | |||
882 | return ret; | ||
894 | } | 883 | } |
895 | 884 | ||
896 | /* DVB USB Driver stuff */ | 885 | /* DVB USB Driver stuff */ |
@@ -1084,5 +1073,5 @@ module_exit(lme2510_module_exit); | |||
1084 | 1073 | ||
1085 | MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>"); | 1074 | MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>"); |
1086 | MODULE_DESCRIPTION("LM2510(C) DVB-S USB2.0"); | 1075 | MODULE_DESCRIPTION("LM2510(C) DVB-S USB2.0"); |
1087 | MODULE_VERSION("1.60"); | 1076 | MODULE_VERSION("1.70"); |
1088 | MODULE_LICENSE("GPL"); | 1077 | MODULE_LICENSE("GPL"); |