diff options
author | Mauro Carvalho Chehab <m.chehab@samsung.com> | 2014-05-21 16:40:25 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <m.chehab@samsung.com> | 2014-05-25 16:44:19 -0400 |
commit | c4018fa2e4c0b669944c2e5cb9eda96fe786d0a1 (patch) | |
tree | f18dc56fc829d19f5bf1ac84649ccb0f4b08d778 /drivers/media | |
parent | 444f8bda81a35ae7b1e7558e971b2dbc397d3ca9 (diff) |
[media] dib0700: fix RC support on Hauppauge Nova-TD
The RC support o Nova-TD is broken, as the RC endpoint there
is an interrupt endpoint.
That produces an ugly calltrace at the Kernel logs:
WARNING: CPU: 2 PID: 56 at drivers/usb/core/urb.c:450 usb_submit_urb+0x1fd/0x5c0()
usb 1-1.2: BOGUS urb xfer, pipe 3 != type 1
Modules linked in: rc_dib0700_rc5(OF) dvb_usb_dib0700(OF) dib9000(OF) dib8000(OF) dib7000m(OF) dib0090(OF) dib0070(OF) dib7000p(OF) dib3000mc(OF) dibx000_common(OF) dvb_usb(OF) rc_core(OF) snd_usb_audio snd_usbmidi_lib snd_hwdep snd_rawmidi snd_seq snd_seq_device snd_pcm snd_timer snd soundcore bnep bluetooth 6lowpan_iphc rfkill au0828(OF) xc5000(OF) au8522_dig(OF) au8522_common(OF) tveeprom(OF) dvb_core(OF) nouveau i915 mxm_wmi ttm i2c_algo_bit drm_kms_helper drm r8169 mii i2c_core video wmi [last unloaded: au0828]
CPU: 2 PID: 56 Comm: khubd Tainted: GF O 3.14.2-200.fc20.x86_64 #1
Hardware name: SAMSUNG ELECTRONICS CO., LTD. 550P5C/550P7C/SAMSUNG_NP1234567890, BIOS P05ABI.016.130917.dg 09/17/2013
0000000000000000 00000000610866bc ffff880223703860 ffffffff816eec92
ffff8802237038a8 ffff880223703898 ffffffff8108a1bd ffff8800916a2180
ffff8801d5b16000 0000000000000003 0000000000000003 0000000000000020
Call Trace:
[<ffffffff816eec92>] dump_stack+0x45/0x56
[<ffffffff8108a1bd>] warn_slowpath_common+0x7d/0xa0
[<ffffffff8108a23c>] warn_slowpath_fmt+0x5c/0x80
[<ffffffff814e3ebd>] usb_submit_urb+0x1fd/0x5c0
[<ffffffffa0445925>] dib0700_rc_setup+0xb5/0x120 [dvb_usb_dib0700]
[<ffffffffa0445a58>] dib0700_probe+0xc8/0x130 [dvb_usb_dib0700]
...
Fix it by detecting if the endpoint is bulk or interrupt.
Tested with both Hauppauge Nova-TD model 52009 (interrupt) and with a
Prolink Pixelview SBTVD model PV-D231U (bulk).
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
Diffstat (limited to 'drivers/media')
-rw-r--r-- | drivers/media/usb/dvb-usb/dib0700.h | 2 | ||||
-rw-r--r-- | drivers/media/usb/dvb-usb/dib0700_core.c | 43 | ||||
-rw-r--r-- | drivers/media/usb/dvb-usb/dib0700_devices.c | 2 |
3 files changed, 38 insertions, 9 deletions
diff --git a/drivers/media/usb/dvb-usb/dib0700.h b/drivers/media/usb/dvb-usb/dib0700.h index 637b6123f391..927617d95616 100644 --- a/drivers/media/usb/dvb-usb/dib0700.h +++ b/drivers/media/usb/dvb-usb/dib0700.h | |||
@@ -59,7 +59,7 @@ extern int dib0700_set_gpio(struct dvb_usb_device *, enum dib07x0_gpios gpio, u8 | |||
59 | extern int dib0700_ctrl_clock(struct dvb_usb_device *d, u32 clk_MHz, u8 clock_out_gp3); | 59 | extern int dib0700_ctrl_clock(struct dvb_usb_device *d, u32 clk_MHz, u8 clock_out_gp3); |
60 | extern int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen); | 60 | extern int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen); |
61 | extern int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw); | 61 | extern int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw); |
62 | extern int dib0700_rc_setup(struct dvb_usb_device *d); | 62 | extern int dib0700_rc_setup(struct dvb_usb_device *d, struct usb_interface *intf); |
63 | extern int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff); | 63 | extern int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff); |
64 | extern struct i2c_algorithm dib0700_i2c_algo; | 64 | extern struct i2c_algorithm dib0700_i2c_algo; |
65 | extern int dib0700_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props, | 65 | extern int dib0700_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props, |
diff --git a/drivers/media/usb/dvb-usb/dib0700_core.c b/drivers/media/usb/dvb-usb/dib0700_core.c index bf2a908d74cf..c14285fa8271 100644 --- a/drivers/media/usb/dvb-usb/dib0700_core.c +++ b/drivers/media/usb/dvb-usb/dib0700_core.c | |||
@@ -754,17 +754,20 @@ resubmit: | |||
754 | usb_submit_urb(purb, GFP_ATOMIC); | 754 | usb_submit_urb(purb, GFP_ATOMIC); |
755 | } | 755 | } |
756 | 756 | ||
757 | int dib0700_rc_setup(struct dvb_usb_device *d) | 757 | int dib0700_rc_setup(struct dvb_usb_device *d, struct usb_interface *intf) |
758 | { | 758 | { |
759 | struct dib0700_state *st = d->priv; | 759 | struct dib0700_state *st = d->priv; |
760 | struct urb *purb; | 760 | struct urb *purb; |
761 | int ret; | 761 | const struct usb_endpoint_descriptor *e; |
762 | int ret, rc_ep = 1; | ||
763 | unsigned int pipe = 0; | ||
762 | 764 | ||
763 | /* Poll-based. Don't initialize bulk mode */ | 765 | /* Poll-based. Don't initialize bulk mode */ |
764 | if (st->fw_version < 0x10200) | 766 | if (st->fw_version < 0x10200 || !intf) |
765 | return 0; | 767 | return 0; |
766 | 768 | ||
767 | /* Starting in firmware 1.20, the RC info is provided on a bulk pipe */ | 769 | /* Starting in firmware 1.20, the RC info is provided on a bulk pipe */ |
770 | |||
768 | purb = usb_alloc_urb(0, GFP_KERNEL); | 771 | purb = usb_alloc_urb(0, GFP_KERNEL); |
769 | if (purb == NULL) { | 772 | if (purb == NULL) { |
770 | err("rc usb alloc urb failed"); | 773 | err("rc usb alloc urb failed"); |
@@ -779,9 +782,35 @@ int dib0700_rc_setup(struct dvb_usb_device *d) | |||
779 | } | 782 | } |
780 | 783 | ||
781 | purb->status = -EINPROGRESS; | 784 | purb->status = -EINPROGRESS; |
782 | usb_fill_bulk_urb(purb, d->udev, usb_rcvbulkpipe(d->udev, 1), | 785 | |
783 | purb->transfer_buffer, RC_MSG_SIZE_V1_20, | 786 | /* |
784 | dib0700_rc_urb_completion, d); | 787 | * Some devices like the Hauppauge NovaTD model 52009 use an interrupt |
788 | * endpoint, while others use a bulk one. | ||
789 | */ | ||
790 | e = &intf->altsetting[0].endpoint[rc_ep].desc; | ||
791 | if (usb_endpoint_dir_in(e)) { | ||
792 | if (usb_endpoint_xfer_bulk(e)) { | ||
793 | pipe = usb_rcvbulkpipe(d->udev, rc_ep); | ||
794 | usb_fill_bulk_urb(purb, d->udev, pipe, | ||
795 | purb->transfer_buffer, | ||
796 | RC_MSG_SIZE_V1_20, | ||
797 | dib0700_rc_urb_completion, d); | ||
798 | |||
799 | } else if (usb_endpoint_xfer_int(e)) { | ||
800 | pipe = usb_rcvintpipe(d->udev, rc_ep); | ||
801 | usb_fill_int_urb(purb, d->udev, pipe, | ||
802 | purb->transfer_buffer, | ||
803 | RC_MSG_SIZE_V1_20, | ||
804 | dib0700_rc_urb_completion, d, 1); | ||
805 | } | ||
806 | } | ||
807 | |||
808 | if (!pipe) { | ||
809 | err("There's no endpoint for remote controller"); | ||
810 | kfree(purb->transfer_buffer); | ||
811 | usb_free_urb(purb); | ||
812 | return 0; | ||
813 | } | ||
785 | 814 | ||
786 | ret = usb_submit_urb(purb, GFP_ATOMIC); | 815 | ret = usb_submit_urb(purb, GFP_ATOMIC); |
787 | if (ret) { | 816 | if (ret) { |
@@ -820,7 +849,7 @@ static int dib0700_probe(struct usb_interface *intf, | |||
820 | else | 849 | else |
821 | dev->props.rc.core.bulk_mode = false; | 850 | dev->props.rc.core.bulk_mode = false; |
822 | 851 | ||
823 | dib0700_rc_setup(dev); | 852 | dib0700_rc_setup(dev, intf); |
824 | 853 | ||
825 | return 0; | 854 | return 0; |
826 | } | 855 | } |
diff --git a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c index 829323e42ca0..10e0db8d1850 100644 --- a/drivers/media/usb/dvb-usb/dib0700_devices.c +++ b/drivers/media/usb/dvb-usb/dib0700_devices.c | |||
@@ -514,7 +514,7 @@ static int dib0700_rc_query_old_firmware(struct dvb_usb_device *d) | |||
514 | 514 | ||
515 | /* info("%d: %2X %2X %2X %2X",dvb_usb_dib0700_ir_proto,(int)key[3-2],(int)key[3-3],(int)key[3-1],(int)key[3]); */ | 515 | /* info("%d: %2X %2X %2X %2X",dvb_usb_dib0700_ir_proto,(int)key[3-2],(int)key[3-3],(int)key[3-1],(int)key[3]); */ |
516 | 516 | ||
517 | dib0700_rc_setup(d); /* reset ir sensor data to prevent false events */ | 517 | dib0700_rc_setup(d, NULL); /* reset ir sensor data to prevent false events */ |
518 | 518 | ||
519 | d->last_event = 0; | 519 | d->last_event = 0; |
520 | switch (d->props.rc.core.protocol) { | 520 | switch (d->props.rc.core.protocol) { |