From bbbb54f2c420babb0189cea65c304d040123eaa6 Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Thu, 21 Aug 2014 13:17:29 -0400 Subject: [PATCH 1/2] don't unlink in-flight urbs when closing Here we just wait for the completion handlers to finish rather than calling usb_kill_urb, which unlinks them. Perhaps letting the requests complete will yield better device behavior. --- mod/piuio.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/mod/piuio.c b/mod/piuio.c index b2cc048..5f75f1f 100644 --- a/mod/piuio.c +++ b/mod/piuio.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -66,6 +67,7 @@ struct piuio { struct usb_device *usbdev; struct urb *in, *out; struct usb_ctrlrequest cr_in, cr_out; + wait_queue_head_t shutdown_wait; unsigned long old[PIUIO_MULTIPLEX][PIUIO_MSG_LONGS]; unsigned long new[PIUIO_MSG_LONGS]; @@ -119,7 +121,7 @@ static void piuio_in_completed(struct urb *urb) case -ECONNRESET: /* unlink */ case -ENOENT: case -ESHUTDOWN: - return; + goto in_finished; default: /* error */ dev_warn(&piu->dev->dev, "in urb status %d received\n", urb->status); @@ -168,6 +170,10 @@ static void piuio_in_completed(struct urb *urb) dev_err(&piu->dev->dev, "usb_submit_urb(new) failed, status %d", i); } + +in_finished: + /* Let any waiting threads know we're done here */ + wake_up(&piu->shutdown_wait); } static void piuio_out_completed(struct urb *urb) @@ -181,7 +187,7 @@ static void piuio_out_completed(struct urb *urb) case -ECONNRESET: /* unlink */ case -ENOENT: case -ESHUTDOWN: - return; + goto out_finished; default: /* error */ dev_warn(&piu->dev->dev, "out urb status %d received\n", ret); @@ -210,6 +216,10 @@ static void piuio_out_completed(struct urb *urb) "usb_submit_urb(lights) failed, status %d\n", ret); } + +out_finished: + /* Let any waiting threads know we're done here */ + wake_up(&piu->shutdown_wait); } @@ -235,9 +245,13 @@ static void piuio_close(struct input_dev *dev) { struct piuio *piu = input_get_drvdata(dev); - /* Stop polling */ - usb_kill_urb(piu->in); - usb_kill_urb(piu->out); + /* Stop polling, but wait for the last requests to complete */ + usb_block_urb(piu->in); + usb_block_urb(piu->out); + wait_event(piu->shutdown_wait, atomic_read(&piu->in->use_count) == 0 && + atomic_read(&piu->out->use_count) == 0); + usb_unblock_urb(piu->in); + usb_unblock_urb(piu->out); /* XXX Kill the lights! */ /* XXX Re-initialize parts of piuio struct */ @@ -292,6 +306,8 @@ static int piuio_init(struct piuio *piu, struct input_dev *dev, if (!(piu->out = usb_alloc_urb(0, GFP_KERNEL))) return -ENOMEM; + init_waitqueue_head(&piu->shutdown_wait); + piu->dev = dev; piu->usbdev = usbdev; usb_make_path(usbdev, piu->phys, sizeof(piu->phys)); From 60c40636c801862e58e7e7c1217266f14184256f Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Fri, 22 Aug 2014 00:53:04 -0400 Subject: [PATCH 2/2] timeout on wait_event when closing because I'm just nervous, that's why... --- mod/piuio.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/mod/piuio.c b/mod/piuio.c index 5f75f1f..90055b3 100644 --- a/mod/piuio.c +++ b/mod/piuio.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -248,8 +249,10 @@ static void piuio_close(struct input_dev *dev) /* Stop polling, but wait for the last requests to complete */ usb_block_urb(piu->in); usb_block_urb(piu->out); - wait_event(piu->shutdown_wait, atomic_read(&piu->in->use_count) == 0 && - atomic_read(&piu->out->use_count) == 0); + wait_event_timeout(piu->shutdown_wait, + atomic_read(&piu->in->use_count) == 0 && + atomic_read(&piu->out->use_count) == 0, + msecs_to_jiffies(5)); usb_unblock_urb(piu->in); usb_unblock_urb(piu->out);