* Input submission and I/O error handler.
*/
static DEFINE_MUTEX(hid_open_mut);
-static struct workqueue_struct *resumption_waker;
static void hid_io_error(struct hid_device *hid);
static int hid_submit_out(struct hid_device *hid);
struct hid_report *report;
char *raw_report;
struct usbhid_device *usbhid = hid->driver_data;
+ int r;
report = usbhid->out[usbhid->outtail].report;
raw_report = usbhid->out[usbhid->outtail].raw_report;
+ r = usb_autopm_get_interface_async(usbhid->intf);
+ if (r < 0)
+ return -1;
+
+ /*
+ * if the device hasn't been woken, we leave the output
+ * to resume()
+ */
if (!test_bit(HID_REPORTED_IDLE, &usbhid->iofl)) {
usbhid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) + 1 + (report->id > 0);
usbhid->urbout->dev = hid_to_usb_dev(hid);
if (usb_submit_urb(usbhid->urbout, GFP_ATOMIC)) {
hid_err(hid, "usb_submit_urb(out) failed\n");
+ usb_autopm_put_interface_async(usbhid->intf);
return -1;
}
usbhid->last_out = jiffies;
- } else {
- /*
- * queue work to wake up the device.
- * as the work queue is freezeable, this is safe
- * with respect to STD and STR
- */
- queue_work(resumption_waker, &usbhid->restart_work);
}
return 0;
struct hid_report *report;
unsigned char dir;
char *raw_report;
- int len;
+ int len, r;
struct usbhid_device *usbhid = hid->driver_data;
report = usbhid->ctrl[usbhid->ctrltail].report;
raw_report = usbhid->ctrl[usbhid->ctrltail].raw_report;
dir = usbhid->ctrl[usbhid->ctrltail].dir;
+ r = usb_autopm_get_interface_async(usbhid->intf);
+ if (r < 0)
+ return -1;
if (!test_bit(HID_REPORTED_IDLE, &usbhid->iofl)) {
len = ((report->size - 1) >> 3) + 1 + (report->id > 0);
if (dir == USB_DIR_OUT) {
usbhid->cr->wValue, usbhid->cr->wIndex, usbhid->cr->wLength);
if (usb_submit_urb(usbhid->urbctrl, GFP_ATOMIC)) {
+ usb_autopm_put_interface_async(usbhid->intf);
hid_err(hid, "usb_submit_urb(ctrl) failed\n");
return -1;
}
usbhid->last_ctrl = jiffies;
- } else {
- /*
- * queue work to wake up the device.
- * as the work queue is freezeable, this is safe
- * with respect to STD and STR
- */
- queue_work(resumption_waker, &usbhid->restart_work);
}
return 0;
clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
spin_unlock_irqrestore(&usbhid->lock, flags);
+ usb_autopm_put_interface_async(usbhid->intf);
wake_up(&usbhid->wait);
}
wake_up(&usbhid->wait);
}
spin_unlock(&usbhid->lock);
+ usb_autopm_put_interface_async(usbhid->intf);
return;
}
clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
spin_unlock(&usbhid->lock);
+ usb_autopm_put_interface_async(usbhid->intf);
wake_up(&usbhid->wait);
}
mutex_lock(&hid_open_mut);
if (!hid->open++) {
res = usb_autopm_get_interface(usbhid->intf);
- /* the device must be awake to reliable request remote wakeup */
+ /* the device must be awake to reliably request remote wakeup */
if (res < 0) {
hid->open--;
mutex_unlock(&hid_open_mut);
usbhid_restart_ctrl_queue(usbhid);
}
-static void __usbhid_restart_queues(struct work_struct *work)
-{
- struct usbhid_device *usbhid =
- container_of(work, struct usbhid_device, restart_work);
- int r;
-
- r = usb_autopm_get_interface(usbhid->intf);
- if (r < 0)
- return;
- usb_autopm_put_interface(usbhid->intf);
-}
-
static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid)
{
struct usbhid_device *usbhid = hid->driver_data;
init_waitqueue_head(&usbhid->wait);
INIT_WORK(&usbhid->reset_work, hid_reset);
- INIT_WORK(&usbhid->restart_work, __usbhid_restart_queues);
setup_timer(&usbhid->io_retry, hid_retry_timeout, (unsigned long) hid);
spin_lock_init(&usbhid->lock);
static void hid_cancel_delayed_stuff(struct usbhid_device *usbhid)
{
del_timer_sync(&usbhid->io_retry);
- cancel_work_sync(&usbhid->restart_work);
cancel_work_sync(&usbhid->reset_work);
}
spin_lock_irq(&usbhid->lock);
set_bit(HID_RESET_PENDING, &usbhid->iofl);
spin_unlock_irq(&usbhid->lock);
- cancel_work_sync(&usbhid->restart_work);
hid_cease_io(usbhid);
return 0;
{
int retval = -ENOMEM;
- resumption_waker = create_freezeable_workqueue("usbhid_resumer");
- if (!resumption_waker)
- goto no_queue;
retval = hid_register_driver(&hid_usb_driver);
if (retval)
goto hid_register_fail;
usbhid_quirks_init_fail:
hid_unregister_driver(&hid_usb_driver);
hid_register_fail:
- destroy_workqueue(resumption_waker);
-no_queue:
return retval;
}
usb_deregister(&hid_driver);
usbhid_quirks_exit();
hid_unregister_driver(&hid_usb_driver);
- destroy_workqueue(resumption_waker);
}
module_init(hid_init);