From: Hans de Goede Date: Mon, 7 May 2012 09:25:30 +0000 (-0300) Subject: [media] gspca: Call sd_stop0 on disconnect X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=eb238732a52b100bdf4a766a50e11e6fd9bd1d83;p=linux-beck.git [media] gspca: Call sd_stop0 on disconnect This is necessary to ensure that worker-threads accessing the device are stopped before our disconnect handler returns. This causes a problem with stream_off calling sd_stop0 a second time when the device handle is closed. This is fixed by setting gscpa_dev->streaming to 0 on disconnect. Note that now stream_off will never be called on a disconnected device, and the present check can thus be removed from stream_off. Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index 8b97f777ddf4..b7cb9977f778 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c @@ -595,16 +595,12 @@ static int gspca_set_alt0(struct gspca_dev *gspca_dev) static void gspca_stream_off(struct gspca_dev *gspca_dev) { gspca_dev->streaming = 0; - if (gspca_dev->present) { - if (gspca_dev->sd_desc->stopN) - gspca_dev->sd_desc->stopN(gspca_dev); - destroy_urbs(gspca_dev); - gspca_input_destroy_urb(gspca_dev); - gspca_set_alt0(gspca_dev); - gspca_input_create_urb(gspca_dev); - } - - /* always call stop0 to free the subdriver's resources */ + if (gspca_dev->sd_desc->stopN) + gspca_dev->sd_desc->stopN(gspca_dev); + destroy_urbs(gspca_dev); + gspca_input_destroy_urb(gspca_dev); + gspca_set_alt0(gspca_dev); + gspca_input_create_urb(gspca_dev); if (gspca_dev->sd_desc->stop0) gspca_dev->sd_desc->stop0(gspca_dev); PDEBUG(D_STREAM, "stream off OK"); @@ -2369,7 +2365,6 @@ void gspca_disconnect(struct usb_interface *intf) usb_set_intfdata(intf, NULL); gspca_dev->dev = NULL; gspca_dev->present = 0; - wake_up_interruptible(&gspca_dev->wq); destroy_urbs(gspca_dev); #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) @@ -2380,6 +2375,11 @@ void gspca_disconnect(struct usb_interface *intf) input_unregister_device(input_dev); } #endif + /* Free subdriver's streaming resources / stop sd workqueue(s) */ + if (gspca_dev->sd_desc->stop0 && gspca_dev->streaming) + gspca_dev->sd_desc->stop0(gspca_dev); + gspca_dev->streaming = 0; + wake_up_interruptible(&gspca_dev->wq); v4l2_device_disconnect(&gspca_dev->v4l2_dev); video_unregister_device(&gspca_dev->vdev);