2005-06-23 22:02:35 -07:00
/* dvb-usb-urb.c is part of the DVB USB library.
*
2006-09-30 06:53:48 -03:00
* Copyright ( C ) 2004 - 6 Patrick Boettcher ( patrick . boettcher @ desy . de )
2005-06-23 22:02:35 -07:00
* see dvb - usb - init . c for copyright information .
*
2006-09-30 06:53:48 -03:00
* This file keeps functions for initializing and handling the
2005-06-23 22:02:35 -07:00
* USB and URB stuff .
*/
# include "dvb-usb-common.h"
int dvb_usb_generic_rw ( struct dvb_usb_device * d , u8 * wbuf , u16 wlen , u8 * rbuf ,
u16 rlen , int delay_ms )
{
int actlen , ret = - ENOMEM ;
V4L/DVB (9492): unplug oops from dvb_frontend_init...
When inadvertently hot-unplugging a WT-220U USB DVB-T receiver with
2.6.24, I was met with an oops [1]. The problem is relevant to
2.6.25/26-rc also.
dvb_frontend_init() was called either from re-creation of the kdvb-fe0
thread - seems unlikely, or someone called
dvb_frontend_reinitialise(), causing this path in the thread - really
unlikely, as I can't find any call-site for it.
Either way, quite a number of drivers call dvb_usb_generic_rw() [2]
without checking the validity of the relevant member in the
dvb_usb_device struct - which had changed. Having dvb_usb_generic_rw()
sanity-check and fail (rather than loading from 0x120) seems
reasonable defensive programming [3], in light of it being called in
this way.
The problem with this, is that drivers don't check the return code of
the init call [4]. Does it make sense to cook a patch which allows the
failure to be propagated back up, or am I missing something else?
Thanks,
Daniel
<whoops, hot unplug>
[83711.538485] dvb-usb: bulk message failed: -71 (1/0)
[83711.538875] dvb-usb: bulk message failed: -71 (1/0)
[83711.538899] usb 7-5: USB disconnect, address 3
[83711.538905] dvb-usb: bulk message failed: -22 (1/0)
[83711.538924] dvb-usb: bulk message failed: -22 (1/0)
[83711.538943] dvb-usb: bulk message failed: -22 (1/0)
[83711.588979] dvb-usb: bulk message failed: -22 (1/0)
[83711.589031] dvb-usb: bulk message failed: -22 (1/0)
[83711.589078] dvb-usb: bulk message failed: -22 (1/0)
[83711.589122] dvb-usb: bulk message failed: -22 (1/0)
[83711.589167] dvb-usb: bulk message failed: -22 (1/0)
[83711.639233] dvb-usb: bulk message failed: -22 (1/0)
[83711.639282] dvb-usb: bulk message failed: -22 (1/0)
[83711.639330] dvb-usb: bulk message failed: -22 (1/0)
[83711.639374] dvb-usb: bulk message failed: -22 (1/0)
[83711.639421] dvb-usb: bulk message failed: -22 (1/0)
[83711.658391] dvb-usb: bulk message failed: -22 (1/0)
[83768.174281] dvb-usb: bulk message failed: -22 (2/-32512)
[83768.174350] Unable to handle kernel NULL pointer
dereference<6>dvb-usb: WideView WT-220U PenType Receiver
(Typhoon/Freecom) successfully deinitialized and disconnected.
[83768.174459] at 0000000000000120 RIP:
[83768.174459] [<ffffffff88339b4f>] :dvb_usb:dvb_usb_generic_rw+0x2f/0x1a0
[83768.174580] PGD 0
[83768.174643] Oops: 0000 [1] SMP
[83768.174723] CPU 0
[83768.174782] Modules linked in: nfsd auth_rpcgss exportfs nfs lockd
nfs_acl sunrpc af_packet xt_length ipt_tos ipt_TOS xt_CLASSIFY sch_sfq
sch_htb ipt_MASQUERADE ipt_REDIRECT xt_limit xt_state xt_tcpudp
iptable_nat nf_nat nf_conntrack_ipv4 nf_conntrack iptable_mangle
iptable_filter ip_tables x_tables xfs sbp2 parport_pc lp parport loop
ftdi_sio usbserial evdev dvb_usb_dtt200u dvb_usb dvb_core i2c_core
sky2 iTCO_wdt iTCO_vendor_support snd_hda_intel shpchp snd_pcm
snd_timer snd_page_alloc snd_hwdep snd pci_hotplug soundcore ipv6
button intel_agp ext3 jbd mbcache sg sd_mod ata_generic pata_acpi ahci
ata_piix libata scsi_mod ohci1394 ieee1394 ehci_hcd uhci_hcd usbcore
e1000 thermal processor fan fbcon tileblit font bitblit softcursor
fuse
[83768.176968] Pid: 5732, comm: kdvb-fe-0 Not tainted 2.6.24-16-server #1
[83768.177009] RIP: 0010:[<ffffffff88339b4f>] [<ffffffff88339b4f>]
:dvb_usb:dvb_usb_generic_rw+0x2f/0x1a0
[83768.177096] RSP: 0018:ffff810021939df0 EFLAGS: 00010286
[83768.177138] RAX: ffff81003bc7cc00 RBX: 0000000000000001 RCX: 0000000000000000
[83768.177181] RDX: 0000000000000001 RSI: ffff810021939e67 RDI: 0000000000000000
[83768.177223] RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000000
[83768.177267] R10: ffff810001009880 R11: 0000000000000001 R12: ffff81003c10b400
[83768.177311] R13: ffff81003c10b5b0 R14: ffff810021939ec0 R15: 0000000000000000
[83768.177354] FS: 0000000000000000(0000) GS:ffffffff805c3000(0000)
knlGS:0000000000000000
[83768.177409] CS: 0010 DS: 0018 ES: 0018 CR0: 000000008005003b
[83768.177449] CR2: 0000000000000120 CR3: 0000000000201000 CR4: 00000000000006e0
[83768.177491] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[83768.177534] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
[83768.177576] Process kdvb-fe-0 (pid: 5732, threadinfo
ffff810021938000, task ffff81003bd1b7a0)
[83768.177629] Stack: ffff81003e9b6828 0000000000000000
ffff8100378369f8 0000000000000000
[83768.177800] ffff81003bd1b7a0 ffff810037836d48 ffff81003bc7cc30
ffff81003c10b400
[83768.177943] ffff81003c10b5b0 ffff810021939ec0 ffff81003c10b5e0
ffffffff88342452
[83768.178054] Call Trace:
[83768.178130] [<ffffffff88342452>] :dvb_usb_dtt200u:dtt200u_fe_init+0x22/0x30
[83768.178178] [<ffffffff88339f6a>] :dvb_usb:dvb_usb_fe_wakeup+0x3a/0x50
[83768.178229] [<ffffffff88325c41>] :dvb_core:dvb_frontend_init+0x21/0x70
[83768.178278] [<ffffffff8832746b>] :dvb_core:dvb_frontend_thread+0x8b/0x370
[83768.178329] [<ffffffff883273e0>] :dvb_core:dvb_frontend_thread+0x0/0x370
[83768.178382] [<ffffffff80253e3b>] kthread+0x4b/0x80
[83768.178427] [<ffffffff8020d198>] child_rip+0xa/0x12
[83768.178473] [<ffffffff80253df0>] kthread+0x0/0x80
[83768.178514] [<ffffffff8020d18e>] child_rip+0x0/0x12
[83768.178557]
[83768.178594]
[83768.178594] Code: 44 8b 87 20 01 00 00 49 89 f4 45 89 ce 45 85 c0
0f 84 ad 00
[83768.179167] RIP [<ffffffff88339b4f>] :dvb_usb:dvb_usb_generic_rw+0x2f/0x1a0
[83768.179234] RSP <ffff810021939df0>
[83768.179271] CR2: 0000000000000120
[83768.179419] ---[ end trace dba8483163cb1700 ]---
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
2008-06-02 20:05:14 -03:00
if ( ! d | | wbuf = = NULL | | wlen = = 0 )
return - EINVAL ;
2005-06-23 22:02:35 -07:00
if ( d - > props . generic_bulk_ctrl_endpoint = = 0 ) {
err ( " endpoint for generic control not specified. " ) ;
return - EINVAL ;
}
2006-02-07 06:49:14 -02:00
if ( ( ret = mutex_lock_interruptible ( & d - > usb_mutex ) ) )
2005-06-23 22:02:35 -07:00
return ret ;
2005-07-07 17:58:08 -07:00
deb_xfer ( " >>> " ) ;
2005-06-23 22:02:35 -07:00
debug_dump ( wbuf , wlen , deb_xfer ) ;
ret = usb_bulk_msg ( d - > udev , usb_sndbulkpipe ( d - > udev ,
d - > props . generic_bulk_ctrl_endpoint ) , wbuf , wlen , & actlen ,
2005-07-07 17:58:27 -07:00
2000 ) ;
2005-06-23 22:02:35 -07:00
if ( ret )
err ( " bulk message failed: %d (%d/%d) " , ret , wlen , actlen ) ;
else
ret = actlen ! = wlen ? - 1 : 0 ;
/* an answer is expected, and no error before */
if ( ! ret & & rbuf & & rlen ) {
if ( delay_ms )
msleep ( delay_ms ) ;
ret = usb_bulk_msg ( d - > udev , usb_rcvbulkpipe ( d - > udev ,
2010-01-31 21:06:10 -03:00
d - > props . generic_bulk_ctrl_endpoint_response ?
d - > props . generic_bulk_ctrl_endpoint_response :
2005-06-23 22:02:35 -07:00
d - > props . generic_bulk_ctrl_endpoint ) , rbuf , rlen , & actlen ,
2005-07-07 17:58:27 -07:00
2000 ) ;
2005-06-23 22:02:35 -07:00
if ( ret )
err ( " recv bulk message failed: %d " , ret ) ;
2005-07-07 17:58:08 -07:00
else {
deb_xfer ( " <<< " ) ;
2005-06-23 22:02:35 -07:00
debug_dump ( rbuf , actlen , deb_xfer ) ;
2005-07-07 17:58:08 -07:00
}
2005-06-23 22:02:35 -07:00
}
2006-02-07 06:49:14 -02:00
mutex_unlock ( & d - > usb_mutex ) ;
2005-06-23 22:02:35 -07:00
return ret ;
}
EXPORT_SYMBOL ( dvb_usb_generic_rw ) ;
int dvb_usb_generic_write ( struct dvb_usb_device * d , u8 * buf , u16 len )
{
return dvb_usb_generic_rw ( d , buf , len , NULL , 0 , 0 ) ;
}
EXPORT_SYMBOL ( dvb_usb_generic_write ) ;
2006-09-30 06:53:48 -03:00
static void dvb_usb_data_complete ( struct usb_data_stream * stream , u8 * buffer , size_t length )
2005-07-07 17:58:08 -07:00
{
2006-09-30 06:53:48 -03:00
struct dvb_usb_adapter * adap = stream - > user_priv ;
if ( adap - > feedcount > 0 & & adap - > state & DVB_USB_ADAP_STATE_DVB )
dvb_dmx_swfilter ( & adap - > demux , buffer , length ) ;
2005-06-23 22:02:35 -07:00
}
2006-09-19 12:51:43 -03:00
static void dvb_usb_data_complete_204 ( struct usb_data_stream * stream , u8 * buffer , size_t length )
{
struct dvb_usb_adapter * adap = stream - > user_priv ;
if ( adap - > feedcount > 0 & & adap - > state & DVB_USB_ADAP_STATE_DVB )
dvb_dmx_swfilter_204 ( & adap - > demux , buffer , length ) ;
}
2011-09-08 04:47:20 -03:00
static void dvb_usb_data_complete_raw ( struct usb_data_stream * stream ,
u8 * buffer , size_t length )
{
struct dvb_usb_adapter * adap = stream - > user_priv ;
if ( adap - > feedcount > 0 & & adap - > state & DVB_USB_ADAP_STATE_DVB )
dvb_dmx_swfilter_raw ( & adap - > demux , buffer , length ) ;
}
2006-09-30 06:53:48 -03:00
int dvb_usb_adapter_stream_init ( struct dvb_usb_adapter * adap )
2005-07-07 17:58:08 -07:00
{
2011-09-06 09:31:57 -03:00
int i , ret = 0 ;
for ( i = 0 ; i < adap - > props . num_frontends ; i + + ) {
adap - > fe_adap [ i ] . stream . udev = adap - > dev - > udev ;
if ( adap - > props . fe [ i ] . caps & DVB_USB_ADAP_RECEIVES_204_BYTE_TS )
adap - > fe_adap [ i ] . stream . complete =
dvb_usb_data_complete_204 ;
else
2011-09-08 04:47:20 -03:00
if ( adap - > props . fe [ i ] . caps & DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD )
adap - > fe_adap [ i ] . stream . complete =
dvb_usb_data_complete_raw ;
else
2011-09-06 09:31:57 -03:00
adap - > fe_adap [ i ] . stream . complete = dvb_usb_data_complete ;
adap - > fe_adap [ i ] . stream . user_priv = adap ;
ret = usb_urb_init ( & adap - > fe_adap [ i ] . stream ,
& adap - > props . fe [ i ] . stream ) ;
if ( ret < 0 )
break ;
}
return ret ;
2005-06-23 22:02:35 -07:00
}
2006-09-30 06:53:48 -03:00
int dvb_usb_adapter_stream_exit ( struct dvb_usb_adapter * adap )
2005-06-23 22:02:35 -07:00
{
2011-09-06 09:31:57 -03:00
int i ;
for ( i = 0 ; i < adap - > props . num_frontends ; i + + )
usb_urb_exit ( & adap - > fe_adap [ i ] . stream ) ;
return 0 ;
2005-06-23 22:02:35 -07:00
}