Commit 5f7fb877 authored by Thierry's avatar Thierry Committed by Mauro Carvalho Chehab

V4L/DVB (4928): Usbvision_v4l2 robustness on disconnect

This patch corrects 2 bugs (causes kernel oops) that occur when
unplugging the peripheral whereas nobody has opened it yet :
- do not call usbvision_stop_isoc if usbvision_init_isoc has not been called
- do not call wakeup_interruptible on waitqueues that did not have been
initialized with init_waitqueue_head
Signed-off-by: default avatarThierry MERLE <thierry.merle@free.fr>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@infradead.org>
parent f2242ee5
...@@ -2287,7 +2287,7 @@ static void usbvision_isocIrq(struct urb *urb, struct pt_regs *regs) ...@@ -2287,7 +2287,7 @@ static void usbvision_isocIrq(struct urb *urb, struct pt_regs *regs)
/* Manage streaming interruption */ /* Manage streaming interruption */
if (usbvision->streaming == Stream_Interrupt) { if (usbvision->streaming == Stream_Interrupt) {
usbvision->streaming = Stream_Off; usbvision->streaming = Stream_Idle;
if ((*f)) { if ((*f)) {
(*f)->grabstate = FrameState_Ready; (*f)->grabstate = FrameState_Ready;
(*f)->scanstate = ScanState_Scanning; (*f)->scanstate = ScanState_Scanning;
...@@ -3092,7 +3092,7 @@ static int usbvision_stream_interrupt(struct usb_usbvision *usbvision) ...@@ -3092,7 +3092,7 @@ static int usbvision_stream_interrupt(struct usb_usbvision *usbvision)
usbvision->streaming = Stream_Interrupt; usbvision->streaming = Stream_Interrupt;
ret = wait_event_timeout(usbvision->wait_stream, ret = wait_event_timeout(usbvision->wait_stream,
(usbvision->streaming == Stream_Off), (usbvision->streaming == Stream_Idle),
msecs_to_jiffies(USBVISION_NUMSBUF*USBVISION_URB_FRAMES)); msecs_to_jiffies(USBVISION_NUMSBUF*USBVISION_URB_FRAMES));
return ret; return ret;
} }
...@@ -3579,7 +3579,7 @@ static int usbvision_init_isoc(struct usb_usbvision *usbvision) ...@@ -3579,7 +3579,7 @@ static int usbvision_init_isoc(struct usb_usbvision *usbvision)
} }
} }
usbvision->streaming = Stream_On; usbvision->streaming = Stream_Idle;
PDEBUG(DBG_ISOC, "%s: streaming=1 usbvision->video_endp=$%02x", __FUNCTION__, usbvision->video_endp); PDEBUG(DBG_ISOC, "%s: streaming=1 usbvision->video_endp=$%02x", __FUNCTION__, usbvision->video_endp);
return 0; return 0;
} }
...@@ -3595,8 +3595,7 @@ static void usbvision_stop_isoc(struct usb_usbvision *usbvision) ...@@ -3595,8 +3595,7 @@ static void usbvision_stop_isoc(struct usb_usbvision *usbvision)
{ {
int bufIdx, errCode, regValue; int bufIdx, errCode, regValue;
// FIXME : removed the streaming==Stream_Off. This field has not the same signification than before ! if ((usbvision->streaming == Stream_Off) || (usbvision->dev == NULL))
if (usbvision->dev == NULL)
return; return;
/* Unschedule all of the iso td's */ /* Unschedule all of the iso td's */
...@@ -4292,7 +4291,7 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, ...@@ -4292,7 +4291,7 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file,
return -EINVAL; return -EINVAL;
if (list_empty(&(usbvision->outqueue))) { if (list_empty(&(usbvision->outqueue))) {
if (usbvision->streaming == Stream_Off) if (usbvision->streaming == Stream_Idle)
return -EINVAL; return -EINVAL;
ret = wait_event_interruptible ret = wait_event_interruptible
(usbvision->wait_frame, (usbvision->wait_frame,
...@@ -5665,6 +5664,7 @@ static int __devinit usbvision_probe(struct usb_interface *intf, const struct us ...@@ -5665,6 +5664,7 @@ static int __devinit usbvision_probe(struct usb_interface *intf, const struct us
usbvision->isocPacketSize = 0; usbvision->isocPacketSize = 0;
usbvision->usb_bandwidth = 0; usbvision->usb_bandwidth = 0;
usbvision->user = 0; usbvision->user = 0;
usbvision->streaming = Stream_Off;
usbvision_register_video(usbvision); usbvision_register_video(usbvision);
usbvision_configure_video(usbvision); usbvision_configure_video(usbvision);
...@@ -5713,13 +5713,12 @@ static void __devexit usbvision_disconnect(struct usb_interface *intf) ...@@ -5713,13 +5713,12 @@ static void __devexit usbvision_disconnect(struct usb_interface *intf)
usb_put_dev(usbvision->dev); usb_put_dev(usbvision->dev);
usbvision->dev = NULL; // USB device is no more usbvision->dev = NULL; // USB device is no more
wake_up_interruptible(&usbvision->wait_frame);
wake_up_interruptible(&usbvision->wait_stream);
up(&usbvision->lock); up(&usbvision->lock);
if (usbvision->user) { if (usbvision->user) {
info("%s: In use, disconnect pending", __FUNCTION__); info("%s: In use, disconnect pending", __FUNCTION__);
wake_up_interruptible(&usbvision->wait_frame);
wake_up_interruptible(&usbvision->wait_stream);
} }
else { else {
usbvision_release(usbvision); usbvision_release(usbvision);
......
...@@ -227,9 +227,10 @@ enum FrameState { ...@@ -227,9 +227,10 @@ enum FrameState {
/* stream states */ /* stream states */
enum StreamState { enum StreamState {
Stream_Off, Stream_Off, /* Driver streaming is completely OFF */
Stream_Interrupt, Stream_Idle, /* Driver streaming is ready to be put ON by the application */
Stream_On, Stream_Interrupt, /* Driver streaming must be interrupted */
Stream_On, /* Driver streaming is put ON by the application */
}; };
enum IsocState { enum IsocState {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment