diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index 017629e3c..23be7347d 100644 --- a/drivers/media/common/siano/smscoreapi.c +++ b/drivers/media/common/siano/smscoreapi.c @@ -1644,6 +1644,18 @@ struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev) } EXPORT_SYMBOL_GPL(smscore_getbuffer); +struct smscore_buffer_t * +smscore_getbuffer_abortable(struct smscore_device_t *coredev, bool *abort) +{ + struct smscore_buffer_t *cb = NULL; + + wait_event(coredev->buffer_mng_waitq, + READ_ONCE(*abort) || (cb = get_entry(coredev))); + + return cb; +} +EXPORT_SYMBOL_GPL(smscore_getbuffer_abortable); + /* * return buffer descriptor to a pool * @@ -1654,8 +1666,8 @@ EXPORT_SYMBOL_GPL(smscore_getbuffer); */ void smscore_putbuffer(struct smscore_device_t *coredev, struct smscore_buffer_t *cb) { - wake_up_interruptible(&coredev->buffer_mng_waitq); list_add_locked(&cb->entry, &coredev->buffers, &coredev->bufferslock); + wake_up(&coredev->buffer_mng_waitq); } EXPORT_SYMBOL_GPL(smscore_putbuffer); diff --git a/drivers/media/common/siano/smscoreapi.h b/drivers/media/common/siano/smscoreapi.h index d945a2d6d..f8a9e6ef7 100644 --- a/drivers/media/common/siano/smscoreapi.h +++ b/drivers/media/common/siano/smscoreapi.h @@ -1117,6 +1117,8 @@ extern void smscore_onresponse(struct smscore_device_t *coredev, extern struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev); +struct smscore_buffer_t * +smscore_getbuffer_abortable(struct smscore_device_t *coredev, bool *abort); extern void smscore_putbuffer(struct smscore_device_t *coredev, struct smscore_buffer_t *cb); diff --git a/drivers/media/usb/siano/smsusb.c b/drivers/media/usb/siano/smsusb.c index 0fdc2e095..98ae94e19 100644 --- a/drivers/media/usb/siano/smsusb.c +++ b/drivers/media/usb/siano/smsusb.c @@ -58,6 +58,8 @@ struct smsusb_device_t { unsigned char in_ep; unsigned char out_ep; enum smsusb_state state; + bool streaming; + bool stopping; }; static int smsusb_submit_urb(struct smsusb_device_t *dev, @@ -71,8 +73,14 @@ static void do_submit_urb(struct work_struct *work) { struct smsusb_urb_t *surb = container_of(work, struct smsusb_urb_t, wq); struct smsusb_device_t *dev = surb->dev; + int rc; - smsusb_submit_urb(dev, surb); + if (!READ_ONCE(dev->streaming)) + return; + + rc = smsusb_submit_urb(dev, surb); + if (rc < 0 && READ_ONCE(dev->streaming)) + pr_err("smsusb_submit_urb(...) failed\n"); } /* @@ -143,19 +151,22 @@ static void smsusb_onresponse(struct urb *urb) exit_and_resubmit: - INIT_WORK(&surb->wq, do_submit_urb); - schedule_work(&surb->wq); + if (READ_ONCE(dev->streaming)) + schedule_work(&surb->wq); } static int smsusb_submit_urb(struct smsusb_device_t *dev, struct smsusb_urb_t *surb) { + int rc; + if (!surb->cb) { /* This function can sleep */ - surb->cb = smscore_getbuffer(dev->coredev); + surb->cb = smscore_getbuffer_abortable(dev->coredev, + &dev->stopping); if (!surb->cb) { - pr_err("smscore_getbuffer(...) returned NULL\n"); - return -ENOMEM; + pr_debug("device is stopping\n"); + return -ESHUTDOWN; } } @@ -168,20 +179,34 @@ static int smsusb_submit_urb(struct smsusb_device_t *dev, smsusb_onresponse, surb ); - surb->urb->transfer_flags |= URB_FREE_BUFFER; + rc = usb_submit_urb(surb->urb, GFP_ATOMIC); + if (rc) { + smscore_putbuffer(dev->coredev, surb->cb); + surb->cb = NULL; + } - return usb_submit_urb(surb->urb, GFP_ATOMIC); + return rc; } static void smsusb_stop_streaming(struct smsusb_device_t *dev) { int i; - for (i = 0; i < MAX_URBS; i++) { + WRITE_ONCE(dev->streaming, false); + WRITE_ONCE(dev->stopping, true); + if (dev->coredev) + wake_up(&dev->coredev->buffer_mng_waitq); + + for (i = 0; i < MAX_URBS; i++) usb_kill_urb(dev->surbs[i].urb); - if (dev->surbs[i].wq.func) - cancel_work_sync(&dev->surbs[i].wq); + for (i = 0; i < MAX_URBS; i++) + cancel_work_sync(&dev->surbs[i].wq); + + for (i = 0; i < MAX_URBS; i++) + usb_kill_urb(dev->surbs[i].urb); + + for (i = 0; i < MAX_URBS; i++) { if (dev->surbs[i].cb) { smscore_putbuffer(dev->coredev, dev->surbs[i].cb); dev->surbs[i].cb = NULL; @@ -193,6 +218,9 @@ static int smsusb_start_streaming(struct smsusb_device_t *dev) { int i, rc; + WRITE_ONCE(dev->stopping, false); + WRITE_ONCE(dev->streaming, true); + for (i = 0; i < MAX_URBS; i++) { rc = smsusb_submit_urb(dev, &dev->surbs[i]); if (rc < 0) { @@ -401,6 +429,11 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id) if (!dev) return -ENOMEM; + for (i = 0; i < MAX_URBS; i++) { + dev->surbs[i].dev = dev; + INIT_WORK(&dev->surbs[i].wq, do_submit_urb); + } + memset(¶ms, 0, sizeof(params)); usb_set_intfdata(intf, dev); dev->udev = interface_to_usbdev(intf); @@ -467,7 +500,6 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id) /* initialize urbs */ for (i = 0; i < MAX_URBS; i++) { - dev->surbs[i].dev = dev; dev->surbs[i].urb = usb_alloc_urb(0, GFP_KERNEL); if (!dev->surbs[i].urb) goto err_unregister_device;