summaryrefslogtreecommitdiff
path: root/drivers/hid/hid-picolcd_core.c
diff options
context:
space:
mode:
authorBruno Prémont <bonbons@linux-vserver.org>2012-07-30 21:38:57 +0200
committerJiri Kosina <jkosina@suse.cz>2012-08-15 10:13:26 +0200
commita93ab8494873a88622bf74be861a93f875643524 (patch)
tree19f76ccf334ffb78b387b10c047df61f44d8fa07 /drivers/hid/hid-picolcd_core.c
parentbaacf9c5d2e631e7c940527ad670c8d4b019da81 (diff)
HID: picoLCD: Improve unplug handling
Stop earlier attempting to submit new reports/URBs (though locking and usbhid still prevents to bail out early enough to not produce multiple hid-picolcd 0003:04D8:C002.0003: usb_submit_urb(out) failed: -19 messages in kernel log. Strengthen framebuffer removal to be less racy. Signed-off-by: Bruno Prémont <bonbons@linux-vserver.org> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid/hid-picolcd_core.c')
-rw-r--r--drivers/hid/hid-picolcd_core.c21
1 files changed, 15 insertions, 6 deletions
diff --git a/drivers/hid/hid-picolcd_core.c b/drivers/hid/hid-picolcd_core.c
index 8d5d341adeab..2d7ef688d66e 100644
--- a/drivers/hid/hid-picolcd_core.c
+++ b/drivers/hid/hid-picolcd_core.c
@@ -105,12 +105,17 @@ struct picolcd_pending *picolcd_send_and_wait(struct hid_device *hdev,
hid_set_field(report->field[i], j, k < size ? raw_data[k] : 0);
k++;
}
- data->pending = work;
- usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
- spin_unlock_irqrestore(&data->lock, flags);
- wait_for_completion_interruptible_timeout(&work->ready, HZ*2);
- spin_lock_irqsave(&data->lock, flags);
- data->pending = NULL;
+ if (data->status & PICOLCD_FAILED) {
+ kfree(work);
+ work = NULL;
+ } else {
+ data->pending = work;
+ usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
+ spin_unlock_irqrestore(&data->lock, flags);
+ wait_for_completion_interruptible_timeout(&work->ready, HZ*2);
+ spin_lock_irqsave(&data->lock, flags);
+ data->pending = NULL;
+ }
spin_unlock_irqrestore(&data->lock, flags);
mutex_unlock(&data->mutex);
return work;
@@ -235,6 +240,10 @@ int picolcd_reset(struct hid_device *hdev)
/* perform the reset */
hid_set_field(report->field[0], 0, 1);
+ if (data->status & PICOLCD_FAILED) {
+ spin_unlock_irqrestore(&data->lock, flags);
+ return -ENODEV;
+ }
usbhid_submit_report(hdev, report, USB_DIR_OUT);
spin_unlock_irqrestore(&data->lock, flags);