Loading drivers/hid/hid-core.c +16 −0 Original line number Diff line number Diff line Loading @@ -1819,6 +1819,22 @@ void hid_unregister_driver(struct hid_driver *hdrv) } EXPORT_SYMBOL_GPL(hid_unregister_driver); int hid_check_keys_pressed(struct hid_device *hid) { struct hid_input *hidinput; int i; list_for_each_entry(hidinput, &hid->inputs, list) { for (i = 0; i < BITS_TO_LONGS(KEY_MAX); i++) if (hidinput->input->key[i]) return 1; } return 0; } EXPORT_SYMBOL_GPL(hid_check_keys_pressed); static int __init hid_init(void) { int ret; Loading drivers/hid/hidraw.c +14 −3 Original line number Diff line number Diff line Loading @@ -181,10 +181,18 @@ static int hidraw_open(struct inode *inode, struct file *file) dev = hidraw_table[minor]; if (!dev->open++) { err = dev->hid->ll_driver->open(dev->hid); if (dev->hid->ll_driver->power) { err = dev->hid->ll_driver->power(dev->hid, PM_HINT_FULLON); if (err < 0) goto out_unlock; } err = dev->hid->ll_driver->open(dev->hid); if (err < 0) { if (dev->hid->ll_driver->power) dev->hid->ll_driver->power(dev->hid, PM_HINT_NORMAL); dev->open--; } } out_unlock: mutex_unlock(&minors_lock); Loading @@ -209,11 +217,14 @@ static int hidraw_release(struct inode * inode, struct file * file) list_del(&list->node); dev = hidraw_table[minor]; if (!--dev->open) { if (list->hidraw->exist) if (list->hidraw->exist) { if (dev->hid->ll_driver->power) dev->hid->ll_driver->power(dev->hid, PM_HINT_NORMAL); dev->hid->ll_driver->close(dev->hid); else } else { kfree(list->hidraw); } } kfree(list); Loading drivers/hid/usbhid/hid-core.c +367 −105 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc * Copyright (c) 2006-2008 Jiri Kosina * Copyright (c) 2007-2008 Oliver Neukum */ /* Loading @@ -27,6 +28,7 @@ #include <asm/byteorder.h> #include <linux/input.h> #include <linux/wait.h> #include <linux/workqueue.h> #include <linux/usb.h> Loading @@ -53,6 +55,10 @@ static unsigned int hid_mousepoll_interval; module_param_named(mousepoll, hid_mousepoll_interval, uint, 0644); MODULE_PARM_DESC(mousepoll, "Polling interval of mice"); static unsigned int ignoreled; module_param_named(ignoreled, ignoreled, uint, 0644); MODULE_PARM_DESC(ignoreled, "Autosuspend with active leds"); /* Quirks specified at module load time */ static char *quirks_param[MAX_USBHID_BOOT_QUIRKS] = { [ 0 ... (MAX_USBHID_BOOT_QUIRKS - 1) ] = NULL }; module_param_array_named(quirks, quirks_param, charp, NULL, 0444); Loading @@ -63,8 +69,13 @@ MODULE_PARM_DESC(quirks, "Add/modify USB HID quirks by specifying " /* * 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); static int hid_submit_ctrl(struct hid_device *hid); static void hid_cancel_delayed_stuff(struct usbhid_device *usbhid); /* Start up the input URB */ static int hid_start_in(struct hid_device *hid) Loading @@ -73,15 +84,16 @@ static int hid_start_in(struct hid_device *hid) int rc = 0; struct usbhid_device *usbhid = hid->driver_data; spin_lock_irqsave(&usbhid->inlock, flags); if (hid->open > 0 && !test_bit(HID_SUSPENDED, &usbhid->iofl) && spin_lock_irqsave(&usbhid->lock, flags); if (hid->open > 0 && !test_bit(HID_DISCONNECTED, &usbhid->iofl) && !test_bit(HID_REPORTED_IDLE, &usbhid->iofl) && !test_and_set_bit(HID_IN_RUNNING, &usbhid->iofl)) { rc = usb_submit_urb(usbhid->urbin, GFP_ATOMIC); if (rc != 0) clear_bit(HID_IN_RUNNING, &usbhid->iofl); } spin_unlock_irqrestore(&usbhid->inlock, flags); spin_unlock_irqrestore(&usbhid->lock, flags); return rc; } Loading Loading @@ -145,7 +157,7 @@ static void hid_io_error(struct hid_device *hid) unsigned long flags; struct usbhid_device *usbhid = hid->driver_data; spin_lock_irqsave(&usbhid->inlock, flags); spin_lock_irqsave(&usbhid->lock, flags); /* Stop when disconnected */ if (test_bit(HID_DISCONNECTED, &usbhid->iofl)) Loading Loading @@ -175,7 +187,51 @@ static void hid_io_error(struct hid_device *hid) mod_timer(&usbhid->io_retry, jiffies + msecs_to_jiffies(usbhid->retry_delay)); done: spin_unlock_irqrestore(&usbhid->inlock, flags); spin_unlock_irqrestore(&usbhid->lock, flags); } static void usbhid_mark_busy(struct usbhid_device *usbhid) { struct usb_interface *intf = usbhid->intf; usb_mark_last_busy(interface_to_usbdev(intf)); } static int usbhid_restart_out_queue(struct usbhid_device *usbhid) { struct hid_device *hid = usb_get_intfdata(usbhid->intf); int kicked; if (!hid) return 0; if ((kicked = (usbhid->outhead != usbhid->outtail))) { dbg("Kicking head %d tail %d", usbhid->outhead, usbhid->outtail); if (hid_submit_out(hid)) { clear_bit(HID_OUT_RUNNING, &usbhid->iofl); wake_up(&usbhid->wait); } } return kicked; } static int usbhid_restart_ctrl_queue(struct usbhid_device *usbhid) { struct hid_device *hid = usb_get_intfdata(usbhid->intf); int kicked; WARN_ON(hid == NULL); if (!hid) return 0; if ((kicked = (usbhid->ctrlhead != usbhid->ctrltail))) { dbg("Kicking head %d tail %d", usbhid->ctrlhead, usbhid->ctrltail); if (hid_submit_ctrl(hid)) { clear_bit(HID_CTRL_RUNNING, &usbhid->iofl); wake_up(&usbhid->wait); } } return kicked; } /* Loading @@ -190,12 +246,23 @@ static void hid_irq_in(struct urb *urb) switch (urb->status) { case 0: /* success */ usbhid_mark_busy(usbhid); usbhid->retry_delay = 0; hid_input_report(urb->context, HID_INPUT_REPORT, urb->transfer_buffer, urb->actual_length, 1); /* * autosuspend refused while keys are pressed * because most keyboards don't wake up when * a key is released */ if (hid_check_keys_pressed(hid)) set_bit(HID_KEYS_PRESSED, &usbhid->iofl); else clear_bit(HID_KEYS_PRESSED, &usbhid->iofl); break; case -EPIPE: /* stall */ usbhid_mark_busy(usbhid); clear_bit(HID_IN_RUNNING, &usbhid->iofl); set_bit(HID_CLEAR_HALT, &usbhid->iofl); schedule_work(&usbhid->reset_work); Loading @@ -209,6 +276,7 @@ static void hid_irq_in(struct urb *urb) case -EPROTO: /* protocol error or unplug */ case -ETIME: /* protocol error or unplug */ case -ETIMEDOUT: /* Should never happen, but... */ usbhid_mark_busy(usbhid); clear_bit(HID_IN_RUNNING, &usbhid->iofl); hid_io_error(hid); return; Loading Loading @@ -239,6 +307,7 @@ static int hid_submit_out(struct hid_device *hid) report = usbhid->out[usbhid->outtail].report; raw_report = usbhid->out[usbhid->outtail].raw_report; 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); memcpy(usbhid->outbuf, raw_report, usbhid->urbout->transfer_buffer_length); Loading @@ -250,6 +319,14 @@ static int hid_submit_out(struct hid_device *hid) err_hid("usb_submit_urb(out) failed"); return -1; } } 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; } Loading @@ -266,6 +343,7 @@ static int hid_submit_ctrl(struct hid_device *hid) raw_report = usbhid->ctrl[usbhid->ctrltail].raw_report; dir = usbhid->ctrl[usbhid->ctrltail].dir; if (!test_bit(HID_REPORTED_IDLE, &usbhid->iofl)) { len = ((report->size - 1) >> 3) + 1 + (report->id > 0); if (dir == USB_DIR_OUT) { usbhid->urbctrl->pipe = usb_sndctrlpipe(hid_to_usb_dev(hid), 0); Loading Loading @@ -302,6 +380,14 @@ static int hid_submit_ctrl(struct hid_device *hid) err_hid("usb_submit_urb(ctrl) failed"); return -1; } } 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; } Loading Loading @@ -332,7 +418,7 @@ static void hid_irq_out(struct urb *urb) "received\n", urb->status); } spin_lock_irqsave(&usbhid->outlock, flags); spin_lock_irqsave(&usbhid->lock, flags); if (unplug) usbhid->outtail = usbhid->outhead; Loading @@ -344,12 +430,12 @@ static void hid_irq_out(struct urb *urb) clear_bit(HID_OUT_RUNNING, &usbhid->iofl); wake_up(&usbhid->wait); } spin_unlock_irqrestore(&usbhid->outlock, flags); spin_unlock_irqrestore(&usbhid->lock, flags); return; } clear_bit(HID_OUT_RUNNING, &usbhid->iofl); spin_unlock_irqrestore(&usbhid->outlock, flags); spin_unlock_irqrestore(&usbhid->lock, flags); wake_up(&usbhid->wait); } Loading @@ -361,12 +447,11 @@ static void hid_ctrl(struct urb *urb) { struct hid_device *hid = urb->context; struct usbhid_device *usbhid = hid->driver_data; unsigned long flags; int unplug = 0; int unplug = 0, status = urb->status; spin_lock_irqsave(&usbhid->ctrllock, flags); spin_lock(&usbhid->lock); switch (urb->status) { switch (status) { case 0: /* success */ if (usbhid->ctrl[usbhid->ctrltail].dir == USB_DIR_IN) hid_input_report(urb->context, Loading @@ -383,7 +468,7 @@ static void hid_ctrl(struct urb *urb) break; default: /* error */ dev_warn(&urb->dev->dev, "ctrl urb status %d " "received\n", urb->status); "received\n", status); } if (unplug) Loading @@ -396,19 +481,18 @@ static void hid_ctrl(struct urb *urb) clear_bit(HID_CTRL_RUNNING, &usbhid->iofl); wake_up(&usbhid->wait); } spin_unlock_irqrestore(&usbhid->ctrllock, flags); spin_unlock(&usbhid->lock); return; } clear_bit(HID_CTRL_RUNNING, &usbhid->iofl); spin_unlock_irqrestore(&usbhid->ctrllock, flags); spin_unlock(&usbhid->lock); wake_up(&usbhid->wait); } void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir) void __usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir) { int head; unsigned long flags; struct usbhid_device *usbhid = hid->driver_data; int len = ((report->size - 1) >> 3) + 1 + (report->id > 0); Loading @@ -416,18 +500,13 @@ void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, uns return; if (usbhid->urbout && dir == USB_DIR_OUT && report->type == HID_OUTPUT_REPORT) { spin_lock_irqsave(&usbhid->outlock, flags); if ((head = (usbhid->outhead + 1) & (HID_OUTPUT_FIFO_SIZE - 1)) == usbhid->outtail) { spin_unlock_irqrestore(&usbhid->outlock, flags); dev_warn(&hid->dev, "output queue full\n"); return; } usbhid->out[usbhid->outhead].raw_report = kmalloc(len, GFP_ATOMIC); if (!usbhid->out[usbhid->outhead].raw_report) { spin_unlock_irqrestore(&usbhid->outlock, flags); dev_warn(&hid->dev, "output queueing failed\n"); return; } Loading @@ -438,15 +517,10 @@ void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, uns if (!test_and_set_bit(HID_OUT_RUNNING, &usbhid->iofl)) if (hid_submit_out(hid)) clear_bit(HID_OUT_RUNNING, &usbhid->iofl); spin_unlock_irqrestore(&usbhid->outlock, flags); return; } spin_lock_irqsave(&usbhid->ctrllock, flags); if ((head = (usbhid->ctrlhead + 1) & (HID_CONTROL_FIFO_SIZE - 1)) == usbhid->ctrltail) { spin_unlock_irqrestore(&usbhid->ctrllock, flags); dev_warn(&hid->dev, "control queue full\n"); return; } Loading @@ -454,7 +528,6 @@ void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, uns if (dir == USB_DIR_OUT) { usbhid->ctrl[usbhid->ctrlhead].raw_report = kmalloc(len, GFP_ATOMIC); if (!usbhid->ctrl[usbhid->ctrlhead].raw_report) { spin_unlock_irqrestore(&usbhid->ctrllock, flags); dev_warn(&hid->dev, "control queueing failed\n"); return; } Loading @@ -467,15 +540,25 @@ void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, uns if (!test_and_set_bit(HID_CTRL_RUNNING, &usbhid->iofl)) if (hid_submit_ctrl(hid)) clear_bit(HID_CTRL_RUNNING, &usbhid->iofl); } void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir) { struct usbhid_device *usbhid = hid->driver_data; unsigned long flags; spin_unlock_irqrestore(&usbhid->ctrllock, flags); spin_lock_irqsave(&usbhid->lock, flags); __usbhid_submit_report(hid, report, dir); spin_unlock_irqrestore(&usbhid->lock, flags); } EXPORT_SYMBOL_GPL(usbhid_submit_report); static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { struct hid_device *hid = input_get_drvdata(dev); struct usbhid_device *usbhid = hid->driver_data; struct hid_field *field; unsigned long flags; int offset; if (type == EV_FF) Loading @@ -490,6 +573,15 @@ static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, un } hid_set_field(field, offset, value); if (value) { spin_lock_irqsave(&usbhid->lock, flags); usbhid->ledcount++; spin_unlock_irqrestore(&usbhid->lock, flags); } else { spin_lock_irqsave(&usbhid->lock, flags); usbhid->ledcount--; spin_unlock_irqrestore(&usbhid->lock, flags); } usbhid_submit_report(hid, field->report, USB_DIR_OUT); return 0; Loading Loading @@ -538,15 +630,22 @@ int usbhid_open(struct hid_device *hid) struct usbhid_device *usbhid = hid->driver_data; int res; 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 */ if (res < 0) { hid->open--; mutex_unlock(&hid_open_mut); return -EIO; } } usbhid->intf->needs_remote_wakeup = 1; if (hid_start_in(hid)) hid_io_error(hid); usb_autopm_put_interface(usbhid->intf); } mutex_unlock(&hid_open_mut); return 0; } Loading @@ -554,10 +653,22 @@ void usbhid_close(struct hid_device *hid) { struct usbhid_device *usbhid = hid->driver_data; mutex_lock(&hid_open_mut); /* protecting hid->open to make sure we don't restart * data acquistion due to a resumption we no longer * care about */ spin_lock_irq(&usbhid->lock); if (!--hid->open) { spin_unlock_irq(&usbhid->lock); usb_kill_urb(usbhid->urbin); usb_autopm_put_interface(usbhid->intf); flush_scheduled_work(); usbhid->intf->needs_remote_wakeup = 0; } else { spin_unlock_irq(&usbhid->lock); } mutex_unlock(&hid_open_mut); } /* Loading Loading @@ -687,6 +798,25 @@ static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t co return ret; } static void usbhid_restart_queues(struct usbhid_device *usbhid) { if (usbhid->urbout) usbhid_restart_out_queue(usbhid); 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; Loading Loading @@ -853,11 +983,11 @@ static int usbhid_start(struct hid_device *hid) 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->inlock); spin_lock_init(&usbhid->outlock); spin_lock_init(&usbhid->ctrllock); spin_lock_init(&usbhid->lock); spin_lock_init(&usbhid->lock); usbhid->intf = intf; usbhid->ifnum = interface->desc.bInterfaceNumber; Loading Loading @@ -909,15 +1039,14 @@ static void usbhid_stop(struct hid_device *hid) return; clear_bit(HID_STARTED, &usbhid->iofl); spin_lock_irq(&usbhid->inlock); /* Sync with error handler */ spin_lock_irq(&usbhid->lock); /* Sync with error handler */ set_bit(HID_DISCONNECTED, &usbhid->iofl); spin_unlock_irq(&usbhid->inlock); spin_unlock_irq(&usbhid->lock); usb_kill_urb(usbhid->urbin); usb_kill_urb(usbhid->urbout); usb_kill_urb(usbhid->urbctrl); del_timer_sync(&usbhid->io_retry); cancel_work_sync(&usbhid->reset_work); hid_cancel_delayed_stuff(usbhid); if (hid->claimed & HID_CLAIMED_INPUT) hidinput_disconnect(hid); Loading @@ -938,12 +1067,28 @@ static void usbhid_stop(struct hid_device *hid) hid_free_buffers(hid_to_usb_dev(hid), hid); } static int usbhid_power(struct hid_device *hid, int lvl) { int r = 0; switch (lvl) { case PM_HINT_FULLON: r = usbhid_get_power(hid); break; case PM_HINT_NORMAL: usbhid_put_power(hid); break; } return r; } static struct hid_ll_driver usb_hid_driver = { .parse = usbhid_parse, .start = usbhid_start, .stop = usbhid_stop, .open = usbhid_open, .close = usbhid_close, .power = usbhid_power, .hidinput_input_event = usb_hidinput_input_event, }; Loading Loading @@ -1052,19 +1197,126 @@ static void hid_disconnect(struct usb_interface *intf) kfree(usbhid); } static int hid_suspend(struct usb_interface *intf, pm_message_t message) 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); } static void hid_cease_io(struct usbhid_device *usbhid) { del_timer(&usbhid->io_retry); usb_kill_urb(usbhid->urbin); usb_kill_urb(usbhid->urbctrl); usb_kill_urb(usbhid->urbout); } /* Treat USB reset pretty much the same as suspend/resume */ static int hid_pre_reset(struct usb_interface *intf) { struct hid_device *hid = usb_get_intfdata(intf); struct usbhid_device *usbhid = hid->driver_data; if (!test_bit(HID_STARTED, &usbhid->iofl)) 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; } spin_lock_irq(&usbhid->inlock); /* Sync with error handler */ set_bit(HID_SUSPENDED, &usbhid->iofl); spin_unlock_irq(&usbhid->inlock); del_timer_sync(&usbhid->io_retry); usb_kill_urb(usbhid->urbin); /* Same routine used for post_reset and reset_resume */ static int hid_post_reset(struct usb_interface *intf) { struct usb_device *dev = interface_to_usbdev (intf); struct hid_device *hid = usb_get_intfdata(intf); struct usbhid_device *usbhid = hid->driver_data; int status; spin_lock_irq(&usbhid->lock); clear_bit(HID_RESET_PENDING, &usbhid->iofl); spin_unlock_irq(&usbhid->lock); hid_set_idle(dev, intf->cur_altsetting->desc.bInterfaceNumber, 0, 0); /* FIXME: Any more reinitialization needed? */ status = hid_start_in(hid); if (status < 0) hid_io_error(hid); usbhid_restart_queues(usbhid); return 0; } int usbhid_get_power(struct hid_device *hid) { struct usbhid_device *usbhid = hid->driver_data; return usb_autopm_get_interface(usbhid->intf); } void usbhid_put_power(struct hid_device *hid) { struct usbhid_device *usbhid = hid->driver_data; usb_autopm_put_interface(usbhid->intf); } #ifdef CONFIG_PM static int hid_suspend(struct usb_interface *intf, pm_message_t message) { struct hid_device *hid = usb_get_intfdata(intf); struct usbhid_device *usbhid = hid->driver_data; struct usb_device *udev = interface_to_usbdev(intf); int status; if (udev->auto_pm) { spin_lock_irq(&usbhid->lock); /* Sync with error handler */ if (!test_bit(HID_RESET_PENDING, &usbhid->iofl) && !test_bit(HID_CLEAR_HALT, &usbhid->iofl) && !test_bit(HID_OUT_RUNNING, &usbhid->iofl) && !test_bit(HID_CTRL_RUNNING, &usbhid->iofl) && !test_bit(HID_KEYS_PRESSED, &usbhid->iofl) && (!usbhid->ledcount || ignoreled)) { set_bit(HID_REPORTED_IDLE, &usbhid->iofl); spin_unlock_irq(&usbhid->lock); } else { usbhid_mark_busy(usbhid); spin_unlock_irq(&usbhid->lock); return -EBUSY; } } else { spin_lock_irq(&usbhid->lock); set_bit(HID_REPORTED_IDLE, &usbhid->iofl); spin_unlock_irq(&usbhid->lock); if (usbhid_wait_io(hid) < 0) return -EIO; } if (!ignoreled && udev->auto_pm) { spin_lock_irq(&usbhid->lock); if (test_bit(HID_LED_ON, &usbhid->iofl)) { spin_unlock_irq(&usbhid->lock); usbhid_mark_busy(usbhid); return -EBUSY; } spin_unlock_irq(&usbhid->lock); } hid_cancel_delayed_stuff(usbhid); hid_cease_io(usbhid); if (udev->auto_pm && test_bit(HID_KEYS_PRESSED, &usbhid->iofl)) { /* lost race against keypresses */ status = hid_start_in(hid); if (status < 0) hid_io_error(hid); usbhid_mark_busy(usbhid); return -EBUSY; } dev_dbg(&intf->dev, "suspend\n"); return 0; } Loading @@ -1078,32 +1330,33 @@ static int hid_resume(struct usb_interface *intf) if (!test_bit(HID_STARTED, &usbhid->iofl)) return 0; clear_bit(HID_SUSPENDED, &usbhid->iofl); clear_bit(HID_REPORTED_IDLE, &usbhid->iofl); usbhid_mark_busy(usbhid); if (test_bit(HID_CLEAR_HALT, &usbhid->iofl) || test_bit(HID_RESET_PENDING, &usbhid->iofl)) schedule_work(&usbhid->reset_work); usbhid->retry_delay = 0; status = hid_start_in(hid); dev_dbg(&intf->dev, "resume status %d\n", status); return status; } if (status < 0) hid_io_error(hid); usbhid_restart_queues(usbhid); /* Treat USB reset pretty much the same as suspend/resume */ static int hid_pre_reset(struct usb_interface *intf) { /* FIXME: What if the interface is already suspended? */ hid_suspend(intf, PMSG_ON); dev_dbg(&intf->dev, "resume status %d\n", status); return 0; } /* Same routine used for post_reset and reset_resume */ static int hid_post_reset(struct usb_interface *intf) static int hid_reset_resume(struct usb_interface *intf) { struct usb_device *dev = interface_to_usbdev (intf); hid_set_idle(dev, intf->cur_altsetting->desc.bInterfaceNumber, 0, 0); /* FIXME: Any more reinitialization needed? */ struct hid_device *hid = usb_get_intfdata(intf); struct usbhid_device *usbhid = hid->driver_data; return hid_resume(intf); clear_bit(HID_REPORTED_IDLE, &usbhid->iofl); return hid_post_reset(intf); } #endif /* CONFIG_PM */ static struct usb_device_id hid_usb_ids [] = { { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS, .bInterfaceClass = USB_INTERFACE_CLASS_HID }, Loading @@ -1116,9 +1369,11 @@ static struct usb_driver hid_driver = { .name = "usbhid", .probe = hid_probe, .disconnect = hid_disconnect, #ifdef CONFIG_PM .suspend = hid_suspend, .resume = hid_resume, .reset_resume = hid_post_reset, .reset_resume = hid_reset_resume, #endif .pre_reset = hid_pre_reset, .post_reset = hid_post_reset, .id_table = hid_usb_ids, Loading @@ -1137,7 +1392,11 @@ static struct hid_driver hid_usb_driver = { static int __init hid_init(void) { int retval; 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; Loading @@ -1161,6 +1420,8 @@ static int __init hid_init(void) usbhid_quirks_init_fail: hid_unregister_driver(&hid_usb_driver); hid_register_fail: destroy_workqueue(resumption_waker); no_queue: return retval; } Loading @@ -1170,6 +1431,7 @@ static void __exit hid_exit(void) hiddev_exit(); usbhid_quirks_exit(); hid_unregister_driver(&hid_usb_driver); destroy_workqueue(resumption_waker); } module_init(hid_init); Loading drivers/hid/usbhid/hiddev.c +15 −2 Original line number Diff line number Diff line Loading @@ -246,11 +246,13 @@ static int hiddev_release(struct inode * inode, struct file * file) spin_unlock_irqrestore(&list->hiddev->list_lock, flags); if (!--list->hiddev->open) { if (list->hiddev->exist) if (list->hiddev->exist) { usbhid_close(list->hiddev->hid); else usbhid_put_power(list->hiddev->hid); } else { kfree(list->hiddev); } } kfree(list); Loading Loading @@ -300,6 +302,17 @@ static int hiddev_open(struct inode *inode, struct file *file) list_add_tail(&list->node, &hiddev_table[i]->list); spin_unlock_irq(&list->hiddev->list_lock); if (!list->hiddev->open++) if (list->hiddev->exist) { struct hid_device *hid = hiddev_table[i]->hid; res = usbhid_get_power(hid); if (res < 0) { res = -EIO; goto bail; } usbhid_open(hid); } return 0; bail: file->private_data = NULL; Loading drivers/hid/usbhid/usbhid.h +10 −4 Original line number Diff line number Diff line Loading @@ -38,7 +38,10 @@ int usbhid_wait_io(struct hid_device* hid); void usbhid_close(struct hid_device *hid); int usbhid_open(struct hid_device *hid); void usbhid_init_reports(struct hid_device *hid); void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir); void usbhid_submit_report (struct hid_device *hid, struct hid_report *report, unsigned char dir); int usbhid_get_power(struct hid_device *hid); void usbhid_put_power(struct hid_device *hid); /* iofl flags */ #define HID_CTRL_RUNNING 1 Loading @@ -49,6 +52,9 @@ void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, uns #define HID_CLEAR_HALT 6 #define HID_DISCONNECTED 7 #define HID_STARTED 8 #define HID_REPORTED_IDLE 9 #define HID_KEYS_PRESSED 10 #define HID_LED_ON 11 /* * USB-specific HID struct, to be pointed to Loading @@ -66,7 +72,6 @@ struct usbhid_device { struct urb *urbin; /* Input URB */ char *inbuf; /* Input buffer */ dma_addr_t inbuf_dma; /* Input buffer dma */ spinlock_t inlock; /* Input fifo spinlock */ struct urb *urbctrl; /* Control URB */ struct usb_ctrlrequest *cr; /* Control request struct */ Loading @@ -75,21 +80,22 @@ struct usbhid_device { unsigned char ctrlhead, ctrltail; /* Control fifo head & tail */ char *ctrlbuf; /* Control buffer */ dma_addr_t ctrlbuf_dma; /* Control buffer dma */ spinlock_t ctrllock; /* Control fifo spinlock */ struct urb *urbout; /* Output URB */ struct hid_output_fifo out[HID_CONTROL_FIFO_SIZE]; /* Output pipe fifo */ unsigned char outhead, outtail; /* Output pipe fifo head & tail */ char *outbuf; /* Output buffer */ dma_addr_t outbuf_dma; /* Output buffer dma */ spinlock_t outlock; /* Output fifo spinlock */ spinlock_t lock; /* fifo spinlock */ unsigned long iofl; /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */ struct timer_list io_retry; /* Retry timer */ unsigned long stop_retry; /* Time to give up, in jiffies */ unsigned int retry_delay; /* Delay length in ms */ struct work_struct reset_work; /* Task context for resets */ struct work_struct restart_work; /* waking up for output to be done in a task */ wait_queue_head_t wait; /* For sleeping */ int ledcount; /* counting the number of active leds */ }; #define hid_to_usb_dev(hid_dev) \ Loading Loading
drivers/hid/hid-core.c +16 −0 Original line number Diff line number Diff line Loading @@ -1819,6 +1819,22 @@ void hid_unregister_driver(struct hid_driver *hdrv) } EXPORT_SYMBOL_GPL(hid_unregister_driver); int hid_check_keys_pressed(struct hid_device *hid) { struct hid_input *hidinput; int i; list_for_each_entry(hidinput, &hid->inputs, list) { for (i = 0; i < BITS_TO_LONGS(KEY_MAX); i++) if (hidinput->input->key[i]) return 1; } return 0; } EXPORT_SYMBOL_GPL(hid_check_keys_pressed); static int __init hid_init(void) { int ret; Loading
drivers/hid/hidraw.c +14 −3 Original line number Diff line number Diff line Loading @@ -181,10 +181,18 @@ static int hidraw_open(struct inode *inode, struct file *file) dev = hidraw_table[minor]; if (!dev->open++) { err = dev->hid->ll_driver->open(dev->hid); if (dev->hid->ll_driver->power) { err = dev->hid->ll_driver->power(dev->hid, PM_HINT_FULLON); if (err < 0) goto out_unlock; } err = dev->hid->ll_driver->open(dev->hid); if (err < 0) { if (dev->hid->ll_driver->power) dev->hid->ll_driver->power(dev->hid, PM_HINT_NORMAL); dev->open--; } } out_unlock: mutex_unlock(&minors_lock); Loading @@ -209,11 +217,14 @@ static int hidraw_release(struct inode * inode, struct file * file) list_del(&list->node); dev = hidraw_table[minor]; if (!--dev->open) { if (list->hidraw->exist) if (list->hidraw->exist) { if (dev->hid->ll_driver->power) dev->hid->ll_driver->power(dev->hid, PM_HINT_NORMAL); dev->hid->ll_driver->close(dev->hid); else } else { kfree(list->hidraw); } } kfree(list); Loading
drivers/hid/usbhid/hid-core.c +367 −105 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc * Copyright (c) 2006-2008 Jiri Kosina * Copyright (c) 2007-2008 Oliver Neukum */ /* Loading @@ -27,6 +28,7 @@ #include <asm/byteorder.h> #include <linux/input.h> #include <linux/wait.h> #include <linux/workqueue.h> #include <linux/usb.h> Loading @@ -53,6 +55,10 @@ static unsigned int hid_mousepoll_interval; module_param_named(mousepoll, hid_mousepoll_interval, uint, 0644); MODULE_PARM_DESC(mousepoll, "Polling interval of mice"); static unsigned int ignoreled; module_param_named(ignoreled, ignoreled, uint, 0644); MODULE_PARM_DESC(ignoreled, "Autosuspend with active leds"); /* Quirks specified at module load time */ static char *quirks_param[MAX_USBHID_BOOT_QUIRKS] = { [ 0 ... (MAX_USBHID_BOOT_QUIRKS - 1) ] = NULL }; module_param_array_named(quirks, quirks_param, charp, NULL, 0444); Loading @@ -63,8 +69,13 @@ MODULE_PARM_DESC(quirks, "Add/modify USB HID quirks by specifying " /* * 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); static int hid_submit_ctrl(struct hid_device *hid); static void hid_cancel_delayed_stuff(struct usbhid_device *usbhid); /* Start up the input URB */ static int hid_start_in(struct hid_device *hid) Loading @@ -73,15 +84,16 @@ static int hid_start_in(struct hid_device *hid) int rc = 0; struct usbhid_device *usbhid = hid->driver_data; spin_lock_irqsave(&usbhid->inlock, flags); if (hid->open > 0 && !test_bit(HID_SUSPENDED, &usbhid->iofl) && spin_lock_irqsave(&usbhid->lock, flags); if (hid->open > 0 && !test_bit(HID_DISCONNECTED, &usbhid->iofl) && !test_bit(HID_REPORTED_IDLE, &usbhid->iofl) && !test_and_set_bit(HID_IN_RUNNING, &usbhid->iofl)) { rc = usb_submit_urb(usbhid->urbin, GFP_ATOMIC); if (rc != 0) clear_bit(HID_IN_RUNNING, &usbhid->iofl); } spin_unlock_irqrestore(&usbhid->inlock, flags); spin_unlock_irqrestore(&usbhid->lock, flags); return rc; } Loading Loading @@ -145,7 +157,7 @@ static void hid_io_error(struct hid_device *hid) unsigned long flags; struct usbhid_device *usbhid = hid->driver_data; spin_lock_irqsave(&usbhid->inlock, flags); spin_lock_irqsave(&usbhid->lock, flags); /* Stop when disconnected */ if (test_bit(HID_DISCONNECTED, &usbhid->iofl)) Loading Loading @@ -175,7 +187,51 @@ static void hid_io_error(struct hid_device *hid) mod_timer(&usbhid->io_retry, jiffies + msecs_to_jiffies(usbhid->retry_delay)); done: spin_unlock_irqrestore(&usbhid->inlock, flags); spin_unlock_irqrestore(&usbhid->lock, flags); } static void usbhid_mark_busy(struct usbhid_device *usbhid) { struct usb_interface *intf = usbhid->intf; usb_mark_last_busy(interface_to_usbdev(intf)); } static int usbhid_restart_out_queue(struct usbhid_device *usbhid) { struct hid_device *hid = usb_get_intfdata(usbhid->intf); int kicked; if (!hid) return 0; if ((kicked = (usbhid->outhead != usbhid->outtail))) { dbg("Kicking head %d tail %d", usbhid->outhead, usbhid->outtail); if (hid_submit_out(hid)) { clear_bit(HID_OUT_RUNNING, &usbhid->iofl); wake_up(&usbhid->wait); } } return kicked; } static int usbhid_restart_ctrl_queue(struct usbhid_device *usbhid) { struct hid_device *hid = usb_get_intfdata(usbhid->intf); int kicked; WARN_ON(hid == NULL); if (!hid) return 0; if ((kicked = (usbhid->ctrlhead != usbhid->ctrltail))) { dbg("Kicking head %d tail %d", usbhid->ctrlhead, usbhid->ctrltail); if (hid_submit_ctrl(hid)) { clear_bit(HID_CTRL_RUNNING, &usbhid->iofl); wake_up(&usbhid->wait); } } return kicked; } /* Loading @@ -190,12 +246,23 @@ static void hid_irq_in(struct urb *urb) switch (urb->status) { case 0: /* success */ usbhid_mark_busy(usbhid); usbhid->retry_delay = 0; hid_input_report(urb->context, HID_INPUT_REPORT, urb->transfer_buffer, urb->actual_length, 1); /* * autosuspend refused while keys are pressed * because most keyboards don't wake up when * a key is released */ if (hid_check_keys_pressed(hid)) set_bit(HID_KEYS_PRESSED, &usbhid->iofl); else clear_bit(HID_KEYS_PRESSED, &usbhid->iofl); break; case -EPIPE: /* stall */ usbhid_mark_busy(usbhid); clear_bit(HID_IN_RUNNING, &usbhid->iofl); set_bit(HID_CLEAR_HALT, &usbhid->iofl); schedule_work(&usbhid->reset_work); Loading @@ -209,6 +276,7 @@ static void hid_irq_in(struct urb *urb) case -EPROTO: /* protocol error or unplug */ case -ETIME: /* protocol error or unplug */ case -ETIMEDOUT: /* Should never happen, but... */ usbhid_mark_busy(usbhid); clear_bit(HID_IN_RUNNING, &usbhid->iofl); hid_io_error(hid); return; Loading Loading @@ -239,6 +307,7 @@ static int hid_submit_out(struct hid_device *hid) report = usbhid->out[usbhid->outtail].report; raw_report = usbhid->out[usbhid->outtail].raw_report; 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); memcpy(usbhid->outbuf, raw_report, usbhid->urbout->transfer_buffer_length); Loading @@ -250,6 +319,14 @@ static int hid_submit_out(struct hid_device *hid) err_hid("usb_submit_urb(out) failed"); return -1; } } 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; } Loading @@ -266,6 +343,7 @@ static int hid_submit_ctrl(struct hid_device *hid) raw_report = usbhid->ctrl[usbhid->ctrltail].raw_report; dir = usbhid->ctrl[usbhid->ctrltail].dir; if (!test_bit(HID_REPORTED_IDLE, &usbhid->iofl)) { len = ((report->size - 1) >> 3) + 1 + (report->id > 0); if (dir == USB_DIR_OUT) { usbhid->urbctrl->pipe = usb_sndctrlpipe(hid_to_usb_dev(hid), 0); Loading Loading @@ -302,6 +380,14 @@ static int hid_submit_ctrl(struct hid_device *hid) err_hid("usb_submit_urb(ctrl) failed"); return -1; } } 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; } Loading Loading @@ -332,7 +418,7 @@ static void hid_irq_out(struct urb *urb) "received\n", urb->status); } spin_lock_irqsave(&usbhid->outlock, flags); spin_lock_irqsave(&usbhid->lock, flags); if (unplug) usbhid->outtail = usbhid->outhead; Loading @@ -344,12 +430,12 @@ static void hid_irq_out(struct urb *urb) clear_bit(HID_OUT_RUNNING, &usbhid->iofl); wake_up(&usbhid->wait); } spin_unlock_irqrestore(&usbhid->outlock, flags); spin_unlock_irqrestore(&usbhid->lock, flags); return; } clear_bit(HID_OUT_RUNNING, &usbhid->iofl); spin_unlock_irqrestore(&usbhid->outlock, flags); spin_unlock_irqrestore(&usbhid->lock, flags); wake_up(&usbhid->wait); } Loading @@ -361,12 +447,11 @@ static void hid_ctrl(struct urb *urb) { struct hid_device *hid = urb->context; struct usbhid_device *usbhid = hid->driver_data; unsigned long flags; int unplug = 0; int unplug = 0, status = urb->status; spin_lock_irqsave(&usbhid->ctrllock, flags); spin_lock(&usbhid->lock); switch (urb->status) { switch (status) { case 0: /* success */ if (usbhid->ctrl[usbhid->ctrltail].dir == USB_DIR_IN) hid_input_report(urb->context, Loading @@ -383,7 +468,7 @@ static void hid_ctrl(struct urb *urb) break; default: /* error */ dev_warn(&urb->dev->dev, "ctrl urb status %d " "received\n", urb->status); "received\n", status); } if (unplug) Loading @@ -396,19 +481,18 @@ static void hid_ctrl(struct urb *urb) clear_bit(HID_CTRL_RUNNING, &usbhid->iofl); wake_up(&usbhid->wait); } spin_unlock_irqrestore(&usbhid->ctrllock, flags); spin_unlock(&usbhid->lock); return; } clear_bit(HID_CTRL_RUNNING, &usbhid->iofl); spin_unlock_irqrestore(&usbhid->ctrllock, flags); spin_unlock(&usbhid->lock); wake_up(&usbhid->wait); } void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir) void __usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir) { int head; unsigned long flags; struct usbhid_device *usbhid = hid->driver_data; int len = ((report->size - 1) >> 3) + 1 + (report->id > 0); Loading @@ -416,18 +500,13 @@ void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, uns return; if (usbhid->urbout && dir == USB_DIR_OUT && report->type == HID_OUTPUT_REPORT) { spin_lock_irqsave(&usbhid->outlock, flags); if ((head = (usbhid->outhead + 1) & (HID_OUTPUT_FIFO_SIZE - 1)) == usbhid->outtail) { spin_unlock_irqrestore(&usbhid->outlock, flags); dev_warn(&hid->dev, "output queue full\n"); return; } usbhid->out[usbhid->outhead].raw_report = kmalloc(len, GFP_ATOMIC); if (!usbhid->out[usbhid->outhead].raw_report) { spin_unlock_irqrestore(&usbhid->outlock, flags); dev_warn(&hid->dev, "output queueing failed\n"); return; } Loading @@ -438,15 +517,10 @@ void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, uns if (!test_and_set_bit(HID_OUT_RUNNING, &usbhid->iofl)) if (hid_submit_out(hid)) clear_bit(HID_OUT_RUNNING, &usbhid->iofl); spin_unlock_irqrestore(&usbhid->outlock, flags); return; } spin_lock_irqsave(&usbhid->ctrllock, flags); if ((head = (usbhid->ctrlhead + 1) & (HID_CONTROL_FIFO_SIZE - 1)) == usbhid->ctrltail) { spin_unlock_irqrestore(&usbhid->ctrllock, flags); dev_warn(&hid->dev, "control queue full\n"); return; } Loading @@ -454,7 +528,6 @@ void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, uns if (dir == USB_DIR_OUT) { usbhid->ctrl[usbhid->ctrlhead].raw_report = kmalloc(len, GFP_ATOMIC); if (!usbhid->ctrl[usbhid->ctrlhead].raw_report) { spin_unlock_irqrestore(&usbhid->ctrllock, flags); dev_warn(&hid->dev, "control queueing failed\n"); return; } Loading @@ -467,15 +540,25 @@ void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, uns if (!test_and_set_bit(HID_CTRL_RUNNING, &usbhid->iofl)) if (hid_submit_ctrl(hid)) clear_bit(HID_CTRL_RUNNING, &usbhid->iofl); } void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir) { struct usbhid_device *usbhid = hid->driver_data; unsigned long flags; spin_unlock_irqrestore(&usbhid->ctrllock, flags); spin_lock_irqsave(&usbhid->lock, flags); __usbhid_submit_report(hid, report, dir); spin_unlock_irqrestore(&usbhid->lock, flags); } EXPORT_SYMBOL_GPL(usbhid_submit_report); static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { struct hid_device *hid = input_get_drvdata(dev); struct usbhid_device *usbhid = hid->driver_data; struct hid_field *field; unsigned long flags; int offset; if (type == EV_FF) Loading @@ -490,6 +573,15 @@ static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, un } hid_set_field(field, offset, value); if (value) { spin_lock_irqsave(&usbhid->lock, flags); usbhid->ledcount++; spin_unlock_irqrestore(&usbhid->lock, flags); } else { spin_lock_irqsave(&usbhid->lock, flags); usbhid->ledcount--; spin_unlock_irqrestore(&usbhid->lock, flags); } usbhid_submit_report(hid, field->report, USB_DIR_OUT); return 0; Loading Loading @@ -538,15 +630,22 @@ int usbhid_open(struct hid_device *hid) struct usbhid_device *usbhid = hid->driver_data; int res; 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 */ if (res < 0) { hid->open--; mutex_unlock(&hid_open_mut); return -EIO; } } usbhid->intf->needs_remote_wakeup = 1; if (hid_start_in(hid)) hid_io_error(hid); usb_autopm_put_interface(usbhid->intf); } mutex_unlock(&hid_open_mut); return 0; } Loading @@ -554,10 +653,22 @@ void usbhid_close(struct hid_device *hid) { struct usbhid_device *usbhid = hid->driver_data; mutex_lock(&hid_open_mut); /* protecting hid->open to make sure we don't restart * data acquistion due to a resumption we no longer * care about */ spin_lock_irq(&usbhid->lock); if (!--hid->open) { spin_unlock_irq(&usbhid->lock); usb_kill_urb(usbhid->urbin); usb_autopm_put_interface(usbhid->intf); flush_scheduled_work(); usbhid->intf->needs_remote_wakeup = 0; } else { spin_unlock_irq(&usbhid->lock); } mutex_unlock(&hid_open_mut); } /* Loading Loading @@ -687,6 +798,25 @@ static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t co return ret; } static void usbhid_restart_queues(struct usbhid_device *usbhid) { if (usbhid->urbout) usbhid_restart_out_queue(usbhid); 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; Loading Loading @@ -853,11 +983,11 @@ static int usbhid_start(struct hid_device *hid) 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->inlock); spin_lock_init(&usbhid->outlock); spin_lock_init(&usbhid->ctrllock); spin_lock_init(&usbhid->lock); spin_lock_init(&usbhid->lock); usbhid->intf = intf; usbhid->ifnum = interface->desc.bInterfaceNumber; Loading Loading @@ -909,15 +1039,14 @@ static void usbhid_stop(struct hid_device *hid) return; clear_bit(HID_STARTED, &usbhid->iofl); spin_lock_irq(&usbhid->inlock); /* Sync with error handler */ spin_lock_irq(&usbhid->lock); /* Sync with error handler */ set_bit(HID_DISCONNECTED, &usbhid->iofl); spin_unlock_irq(&usbhid->inlock); spin_unlock_irq(&usbhid->lock); usb_kill_urb(usbhid->urbin); usb_kill_urb(usbhid->urbout); usb_kill_urb(usbhid->urbctrl); del_timer_sync(&usbhid->io_retry); cancel_work_sync(&usbhid->reset_work); hid_cancel_delayed_stuff(usbhid); if (hid->claimed & HID_CLAIMED_INPUT) hidinput_disconnect(hid); Loading @@ -938,12 +1067,28 @@ static void usbhid_stop(struct hid_device *hid) hid_free_buffers(hid_to_usb_dev(hid), hid); } static int usbhid_power(struct hid_device *hid, int lvl) { int r = 0; switch (lvl) { case PM_HINT_FULLON: r = usbhid_get_power(hid); break; case PM_HINT_NORMAL: usbhid_put_power(hid); break; } return r; } static struct hid_ll_driver usb_hid_driver = { .parse = usbhid_parse, .start = usbhid_start, .stop = usbhid_stop, .open = usbhid_open, .close = usbhid_close, .power = usbhid_power, .hidinput_input_event = usb_hidinput_input_event, }; Loading Loading @@ -1052,19 +1197,126 @@ static void hid_disconnect(struct usb_interface *intf) kfree(usbhid); } static int hid_suspend(struct usb_interface *intf, pm_message_t message) 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); } static void hid_cease_io(struct usbhid_device *usbhid) { del_timer(&usbhid->io_retry); usb_kill_urb(usbhid->urbin); usb_kill_urb(usbhid->urbctrl); usb_kill_urb(usbhid->urbout); } /* Treat USB reset pretty much the same as suspend/resume */ static int hid_pre_reset(struct usb_interface *intf) { struct hid_device *hid = usb_get_intfdata(intf); struct usbhid_device *usbhid = hid->driver_data; if (!test_bit(HID_STARTED, &usbhid->iofl)) 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; } spin_lock_irq(&usbhid->inlock); /* Sync with error handler */ set_bit(HID_SUSPENDED, &usbhid->iofl); spin_unlock_irq(&usbhid->inlock); del_timer_sync(&usbhid->io_retry); usb_kill_urb(usbhid->urbin); /* Same routine used for post_reset and reset_resume */ static int hid_post_reset(struct usb_interface *intf) { struct usb_device *dev = interface_to_usbdev (intf); struct hid_device *hid = usb_get_intfdata(intf); struct usbhid_device *usbhid = hid->driver_data; int status; spin_lock_irq(&usbhid->lock); clear_bit(HID_RESET_PENDING, &usbhid->iofl); spin_unlock_irq(&usbhid->lock); hid_set_idle(dev, intf->cur_altsetting->desc.bInterfaceNumber, 0, 0); /* FIXME: Any more reinitialization needed? */ status = hid_start_in(hid); if (status < 0) hid_io_error(hid); usbhid_restart_queues(usbhid); return 0; } int usbhid_get_power(struct hid_device *hid) { struct usbhid_device *usbhid = hid->driver_data; return usb_autopm_get_interface(usbhid->intf); } void usbhid_put_power(struct hid_device *hid) { struct usbhid_device *usbhid = hid->driver_data; usb_autopm_put_interface(usbhid->intf); } #ifdef CONFIG_PM static int hid_suspend(struct usb_interface *intf, pm_message_t message) { struct hid_device *hid = usb_get_intfdata(intf); struct usbhid_device *usbhid = hid->driver_data; struct usb_device *udev = interface_to_usbdev(intf); int status; if (udev->auto_pm) { spin_lock_irq(&usbhid->lock); /* Sync with error handler */ if (!test_bit(HID_RESET_PENDING, &usbhid->iofl) && !test_bit(HID_CLEAR_HALT, &usbhid->iofl) && !test_bit(HID_OUT_RUNNING, &usbhid->iofl) && !test_bit(HID_CTRL_RUNNING, &usbhid->iofl) && !test_bit(HID_KEYS_PRESSED, &usbhid->iofl) && (!usbhid->ledcount || ignoreled)) { set_bit(HID_REPORTED_IDLE, &usbhid->iofl); spin_unlock_irq(&usbhid->lock); } else { usbhid_mark_busy(usbhid); spin_unlock_irq(&usbhid->lock); return -EBUSY; } } else { spin_lock_irq(&usbhid->lock); set_bit(HID_REPORTED_IDLE, &usbhid->iofl); spin_unlock_irq(&usbhid->lock); if (usbhid_wait_io(hid) < 0) return -EIO; } if (!ignoreled && udev->auto_pm) { spin_lock_irq(&usbhid->lock); if (test_bit(HID_LED_ON, &usbhid->iofl)) { spin_unlock_irq(&usbhid->lock); usbhid_mark_busy(usbhid); return -EBUSY; } spin_unlock_irq(&usbhid->lock); } hid_cancel_delayed_stuff(usbhid); hid_cease_io(usbhid); if (udev->auto_pm && test_bit(HID_KEYS_PRESSED, &usbhid->iofl)) { /* lost race against keypresses */ status = hid_start_in(hid); if (status < 0) hid_io_error(hid); usbhid_mark_busy(usbhid); return -EBUSY; } dev_dbg(&intf->dev, "suspend\n"); return 0; } Loading @@ -1078,32 +1330,33 @@ static int hid_resume(struct usb_interface *intf) if (!test_bit(HID_STARTED, &usbhid->iofl)) return 0; clear_bit(HID_SUSPENDED, &usbhid->iofl); clear_bit(HID_REPORTED_IDLE, &usbhid->iofl); usbhid_mark_busy(usbhid); if (test_bit(HID_CLEAR_HALT, &usbhid->iofl) || test_bit(HID_RESET_PENDING, &usbhid->iofl)) schedule_work(&usbhid->reset_work); usbhid->retry_delay = 0; status = hid_start_in(hid); dev_dbg(&intf->dev, "resume status %d\n", status); return status; } if (status < 0) hid_io_error(hid); usbhid_restart_queues(usbhid); /* Treat USB reset pretty much the same as suspend/resume */ static int hid_pre_reset(struct usb_interface *intf) { /* FIXME: What if the interface is already suspended? */ hid_suspend(intf, PMSG_ON); dev_dbg(&intf->dev, "resume status %d\n", status); return 0; } /* Same routine used for post_reset and reset_resume */ static int hid_post_reset(struct usb_interface *intf) static int hid_reset_resume(struct usb_interface *intf) { struct usb_device *dev = interface_to_usbdev (intf); hid_set_idle(dev, intf->cur_altsetting->desc.bInterfaceNumber, 0, 0); /* FIXME: Any more reinitialization needed? */ struct hid_device *hid = usb_get_intfdata(intf); struct usbhid_device *usbhid = hid->driver_data; return hid_resume(intf); clear_bit(HID_REPORTED_IDLE, &usbhid->iofl); return hid_post_reset(intf); } #endif /* CONFIG_PM */ static struct usb_device_id hid_usb_ids [] = { { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS, .bInterfaceClass = USB_INTERFACE_CLASS_HID }, Loading @@ -1116,9 +1369,11 @@ static struct usb_driver hid_driver = { .name = "usbhid", .probe = hid_probe, .disconnect = hid_disconnect, #ifdef CONFIG_PM .suspend = hid_suspend, .resume = hid_resume, .reset_resume = hid_post_reset, .reset_resume = hid_reset_resume, #endif .pre_reset = hid_pre_reset, .post_reset = hid_post_reset, .id_table = hid_usb_ids, Loading @@ -1137,7 +1392,11 @@ static struct hid_driver hid_usb_driver = { static int __init hid_init(void) { int retval; 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; Loading @@ -1161,6 +1420,8 @@ static int __init hid_init(void) usbhid_quirks_init_fail: hid_unregister_driver(&hid_usb_driver); hid_register_fail: destroy_workqueue(resumption_waker); no_queue: return retval; } Loading @@ -1170,6 +1431,7 @@ static void __exit hid_exit(void) hiddev_exit(); usbhid_quirks_exit(); hid_unregister_driver(&hid_usb_driver); destroy_workqueue(resumption_waker); } module_init(hid_init); Loading
drivers/hid/usbhid/hiddev.c +15 −2 Original line number Diff line number Diff line Loading @@ -246,11 +246,13 @@ static int hiddev_release(struct inode * inode, struct file * file) spin_unlock_irqrestore(&list->hiddev->list_lock, flags); if (!--list->hiddev->open) { if (list->hiddev->exist) if (list->hiddev->exist) { usbhid_close(list->hiddev->hid); else usbhid_put_power(list->hiddev->hid); } else { kfree(list->hiddev); } } kfree(list); Loading Loading @@ -300,6 +302,17 @@ static int hiddev_open(struct inode *inode, struct file *file) list_add_tail(&list->node, &hiddev_table[i]->list); spin_unlock_irq(&list->hiddev->list_lock); if (!list->hiddev->open++) if (list->hiddev->exist) { struct hid_device *hid = hiddev_table[i]->hid; res = usbhid_get_power(hid); if (res < 0) { res = -EIO; goto bail; } usbhid_open(hid); } return 0; bail: file->private_data = NULL; Loading
drivers/hid/usbhid/usbhid.h +10 −4 Original line number Diff line number Diff line Loading @@ -38,7 +38,10 @@ int usbhid_wait_io(struct hid_device* hid); void usbhid_close(struct hid_device *hid); int usbhid_open(struct hid_device *hid); void usbhid_init_reports(struct hid_device *hid); void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir); void usbhid_submit_report (struct hid_device *hid, struct hid_report *report, unsigned char dir); int usbhid_get_power(struct hid_device *hid); void usbhid_put_power(struct hid_device *hid); /* iofl flags */ #define HID_CTRL_RUNNING 1 Loading @@ -49,6 +52,9 @@ void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, uns #define HID_CLEAR_HALT 6 #define HID_DISCONNECTED 7 #define HID_STARTED 8 #define HID_REPORTED_IDLE 9 #define HID_KEYS_PRESSED 10 #define HID_LED_ON 11 /* * USB-specific HID struct, to be pointed to Loading @@ -66,7 +72,6 @@ struct usbhid_device { struct urb *urbin; /* Input URB */ char *inbuf; /* Input buffer */ dma_addr_t inbuf_dma; /* Input buffer dma */ spinlock_t inlock; /* Input fifo spinlock */ struct urb *urbctrl; /* Control URB */ struct usb_ctrlrequest *cr; /* Control request struct */ Loading @@ -75,21 +80,22 @@ struct usbhid_device { unsigned char ctrlhead, ctrltail; /* Control fifo head & tail */ char *ctrlbuf; /* Control buffer */ dma_addr_t ctrlbuf_dma; /* Control buffer dma */ spinlock_t ctrllock; /* Control fifo spinlock */ struct urb *urbout; /* Output URB */ struct hid_output_fifo out[HID_CONTROL_FIFO_SIZE]; /* Output pipe fifo */ unsigned char outhead, outtail; /* Output pipe fifo head & tail */ char *outbuf; /* Output buffer */ dma_addr_t outbuf_dma; /* Output buffer dma */ spinlock_t outlock; /* Output fifo spinlock */ spinlock_t lock; /* fifo spinlock */ unsigned long iofl; /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */ struct timer_list io_retry; /* Retry timer */ unsigned long stop_retry; /* Time to give up, in jiffies */ unsigned int retry_delay; /* Delay length in ms */ struct work_struct reset_work; /* Task context for resets */ struct work_struct restart_work; /* waking up for output to be done in a task */ wait_queue_head_t wait; /* For sleeping */ int ledcount; /* counting the number of active leds */ }; #define hid_to_usb_dev(hid_dev) \ Loading