[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>
This commit is contained in:
		
							parent
							
								
									444f8bda81
								
							
						
					
					
						commit
						c4018fa2e4
					
				| @ -59,7 +59,7 @@ extern int dib0700_set_gpio(struct dvb_usb_device *, enum dib07x0_gpios gpio, u8 | |||||||
| extern int dib0700_ctrl_clock(struct dvb_usb_device *d, u32 clk_MHz, u8 clock_out_gp3); | extern int dib0700_ctrl_clock(struct dvb_usb_device *d, u32 clk_MHz, u8 clock_out_gp3); | ||||||
| extern int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen); | extern int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen); | ||||||
| extern int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw); | extern int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw); | ||||||
| extern int dib0700_rc_setup(struct dvb_usb_device *d); | extern int dib0700_rc_setup(struct dvb_usb_device *d, struct usb_interface *intf); | ||||||
| extern int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff); | extern int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff); | ||||||
| extern struct i2c_algorithm dib0700_i2c_algo; | extern struct i2c_algorithm dib0700_i2c_algo; | ||||||
| extern int dib0700_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props, | extern int dib0700_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props, | ||||||
|  | |||||||
| @ -754,17 +754,20 @@ resubmit: | |||||||
| 	usb_submit_urb(purb, GFP_ATOMIC); | 	usb_submit_urb(purb, GFP_ATOMIC); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int dib0700_rc_setup(struct dvb_usb_device *d) | int dib0700_rc_setup(struct dvb_usb_device *d, struct usb_interface *intf) | ||||||
| { | { | ||||||
| 	struct dib0700_state *st = d->priv; | 	struct dib0700_state *st = d->priv; | ||||||
| 	struct urb *purb; | 	struct urb *purb; | ||||||
| 	int ret; | 	const struct usb_endpoint_descriptor *e; | ||||||
|  | 	int ret, rc_ep = 1; | ||||||
|  | 	unsigned int pipe = 0; | ||||||
| 
 | 
 | ||||||
| 	/* Poll-based. Don't initialize bulk mode */ | 	/* Poll-based. Don't initialize bulk mode */ | ||||||
| 	if (st->fw_version < 0x10200) | 	if (st->fw_version < 0x10200 || !intf) | ||||||
| 		return 0; | 		return 0; | ||||||
| 
 | 
 | ||||||
| 	/* Starting in firmware 1.20, the RC info is provided on a bulk pipe */ | 	/* Starting in firmware 1.20, the RC info is provided on a bulk pipe */ | ||||||
|  | 
 | ||||||
| 	purb = usb_alloc_urb(0, GFP_KERNEL); | 	purb = usb_alloc_urb(0, GFP_KERNEL); | ||||||
| 	if (purb == NULL) { | 	if (purb == NULL) { | ||||||
| 		err("rc usb alloc urb failed"); | 		err("rc usb alloc urb failed"); | ||||||
| @ -779,9 +782,35 @@ int dib0700_rc_setup(struct dvb_usb_device *d) | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	purb->status = -EINPROGRESS; | 	purb->status = -EINPROGRESS; | ||||||
| 	usb_fill_bulk_urb(purb, d->udev, usb_rcvbulkpipe(d->udev, 1), | 
 | ||||||
| 			  purb->transfer_buffer, RC_MSG_SIZE_V1_20, | 	/*
 | ||||||
| 			  dib0700_rc_urb_completion, d); | 	 * Some devices like the Hauppauge NovaTD model 52009 use an interrupt | ||||||
|  | 	 * endpoint, while others use a bulk one. | ||||||
|  | 	 */ | ||||||
|  | 	e = &intf->altsetting[0].endpoint[rc_ep].desc; | ||||||
|  | 	if (usb_endpoint_dir_in(e)) { | ||||||
|  | 		if (usb_endpoint_xfer_bulk(e)) { | ||||||
|  | 			pipe = usb_rcvbulkpipe(d->udev, rc_ep); | ||||||
|  | 			usb_fill_bulk_urb(purb, d->udev, pipe, | ||||||
|  | 					  purb->transfer_buffer, | ||||||
|  | 					  RC_MSG_SIZE_V1_20, | ||||||
|  | 					  dib0700_rc_urb_completion, d); | ||||||
|  | 
 | ||||||
|  | 		} else if (usb_endpoint_xfer_int(e)) { | ||||||
|  | 			pipe = usb_rcvintpipe(d->udev, rc_ep); | ||||||
|  | 			usb_fill_int_urb(purb, d->udev, pipe, | ||||||
|  | 					  purb->transfer_buffer, | ||||||
|  | 					  RC_MSG_SIZE_V1_20, | ||||||
|  | 					  dib0700_rc_urb_completion, d, 1); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (!pipe) { | ||||||
|  | 		err("There's no endpoint for remote controller"); | ||||||
|  | 		kfree(purb->transfer_buffer); | ||||||
|  | 		usb_free_urb(purb); | ||||||
|  | 		return 0; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	ret = usb_submit_urb(purb, GFP_ATOMIC); | 	ret = usb_submit_urb(purb, GFP_ATOMIC); | ||||||
| 	if (ret) { | 	if (ret) { | ||||||
| @ -820,7 +849,7 @@ static int dib0700_probe(struct usb_interface *intf, | |||||||
| 			else | 			else | ||||||
| 				dev->props.rc.core.bulk_mode = false; | 				dev->props.rc.core.bulk_mode = false; | ||||||
| 
 | 
 | ||||||
| 			dib0700_rc_setup(dev); | 			dib0700_rc_setup(dev, intf); | ||||||
| 
 | 
 | ||||||
| 			return 0; | 			return 0; | ||||||
| 		} | 		} | ||||||
|  | |||||||
| @ -514,7 +514,7 @@ static int dib0700_rc_query_old_firmware(struct dvb_usb_device *d) | |||||||
| 
 | 
 | ||||||
| 	/* 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]);  */ | 	/* 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]);  */ | ||||||
| 
 | 
 | ||||||
| 	dib0700_rc_setup(d); /* reset ir sensor data to prevent false events */ | 	dib0700_rc_setup(d, NULL); /* reset ir sensor data to prevent false events */ | ||||||
| 
 | 
 | ||||||
| 	d->last_event = 0; | 	d->last_event = 0; | ||||||
| 	switch (d->props.rc.core.protocol) { | 	switch (d->props.rc.core.protocol) { | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user