From d36b7d4c271b2f93127e7e7cc007b5768a296594 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 6 Jun 2017 23:59:31 -0700 Subject: HID: hiddev: use hid_hw_open/close instead of usbhid_open/close Instead of calling into usbhid code directly, let's use the standard accessors for the transport HID drivers, and stop clobbering their errors with -EIO. This also allows us make usbhid_open and close static. Signed-off-by: Dmitry Torokhov Reviewed-by: Andy Shevchenko Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hid-core.c | 4 ++-- drivers/hid/usbhid/hiddev.c | 16 +++++++++------- drivers/hid/usbhid/usbhid.h | 2 -- 3 files changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers/hid/usbhid') diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index 83772fa7d92a..fb0cf5d70504 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -677,7 +677,7 @@ static int hid_get_class_descriptor(struct usb_device *dev, int ifnum, return result; } -int usbhid_open(struct hid_device *hid) +static int usbhid_open(struct hid_device *hid) { struct usbhid_device *usbhid = hid->driver_data; int res = 0; @@ -722,7 +722,7 @@ done: return res; } -void usbhid_close(struct hid_device *hid) +static void usbhid_close(struct hid_device *hid) { struct usbhid_device *usbhid = hid->driver_data; diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c index 0e06368d1fbb..b4f714752245 100644 --- a/drivers/hid/usbhid/hiddev.c +++ b/drivers/hid/usbhid/hiddev.c @@ -237,7 +237,7 @@ static int hiddev_release(struct inode * inode, struct file * file) mutex_lock(&list->hiddev->existancelock); if (!--list->hiddev->open) { if (list->hiddev->exist) { - usbhid_close(list->hiddev->hid); + hid_hw_close(list->hiddev->hid); usbhid_put_power(list->hiddev->hid); } else { mutex_unlock(&list->hiddev->existancelock); @@ -282,11 +282,9 @@ static int hiddev_open(struct inode *inode, struct file *file) */ if (list->hiddev->exist) { if (!list->hiddev->open++) { - res = usbhid_open(hiddev->hid); - if (res < 0) { - res = -EIO; + res = hid_hw_open(hiddev->hid); + if (res < 0) goto bail; - } } } else { res = -ENODEV; @@ -306,10 +304,14 @@ static int hiddev_open(struct inode *inode, struct file *file) res = -EIO; goto bail_unlock; } - usbhid_open(hid); + res = hid_hw_open(hid); + if (res < 0) + goto bail_put_power; } mutex_unlock(&hiddev->existancelock); return 0; +bail_put_power: + usbhid_put_power(hid); bail_unlock: mutex_unlock(&hiddev->existancelock); bail: @@ -935,7 +937,7 @@ void hiddev_disconnect(struct hid_device *hid) if (hiddev->open) { mutex_unlock(&hiddev->existancelock); - usbhid_close(hiddev->hid); + hid_hw_close(hiddev->hid); wake_up_interruptible(&hiddev->wait); } else { mutex_unlock(&hiddev->existancelock); diff --git a/drivers/hid/usbhid/usbhid.h b/drivers/hid/usbhid/usbhid.h index fa47d666cfcf..83ef5c14aa92 100644 --- a/drivers/hid/usbhid/usbhid.h +++ b/drivers/hid/usbhid/usbhid.h @@ -34,8 +34,6 @@ #include /* API provided by hid-core.c for USB HID drivers */ -void usbhid_close(struct hid_device *hid); -int usbhid_open(struct hid_device *hid); void usbhid_init_reports(struct hid_device *hid); int usbhid_get_power(struct hid_device *hid); void usbhid_put_power(struct hid_device *hid); -- cgit From 9a83563fb3f926cbf0d5992d5c70d760c445ba09 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 6 Jun 2017 23:59:32 -0700 Subject: HID: hiddev: use hid_hw_power instead of usbhid_get/put_power Instead of calling into usbhid code directly, let's use the standard accessors for the transport HID drivers, and stop clobbering their error codes with -EIO. This also allows us to remove usbhid_get/put_power(), leaving only usbhid_power(). Signed-off-by: Dmitry Torokhov Reviewed-by: Andy Shevchenko Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hid-core.c | 22 +++++----------------- drivers/hid/usbhid/hiddev.c | 14 ++++++-------- drivers/hid/usbhid/usbhid.h | 2 -- 3 files changed, 11 insertions(+), 27 deletions(-) (limited to 'drivers/hid/usbhid') diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index fb0cf5d70504..62b660622265 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -1203,16 +1203,19 @@ static void usbhid_stop(struct hid_device *hid) static int usbhid_power(struct hid_device *hid, int lvl) { + struct usbhid_device *usbhid = hid->driver_data; int r = 0; switch (lvl) { case PM_HINT_FULLON: - r = usbhid_get_power(hid); + r = usb_autopm_get_interface(usbhid->intf); break; + case PM_HINT_NORMAL: - usbhid_put_power(hid); + usb_autopm_put_interface(usbhid->intf); break; } + return r; } @@ -1492,21 +1495,6 @@ static int hid_post_reset(struct usb_interface *intf) 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_resume_common(struct hid_device *hid, bool driver_suspended) { diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c index b4f714752245..7d749b19c27c 100644 --- a/drivers/hid/usbhid/hiddev.c +++ b/drivers/hid/usbhid/hiddev.c @@ -238,7 +238,7 @@ static int hiddev_release(struct inode * inode, struct file * file) if (!--list->hiddev->open) { if (list->hiddev->exist) { hid_hw_close(list->hiddev->hid); - usbhid_put_power(list->hiddev->hid); + hid_hw_power(list->hiddev->hid, PM_HINT_NORMAL); } else { mutex_unlock(&list->hiddev->existancelock); kfree(list->hiddev); @@ -299,19 +299,17 @@ static int hiddev_open(struct inode *inode, struct file *file) if (!list->hiddev->open++) if (list->hiddev->exist) { struct hid_device *hid = hiddev->hid; - res = usbhid_get_power(hid); - if (res < 0) { - res = -EIO; + res = hid_hw_power(hid, PM_HINT_FULLON); + if (res < 0) goto bail_unlock; - } res = hid_hw_open(hid); if (res < 0) - goto bail_put_power; + goto bail_normal_power; } mutex_unlock(&hiddev->existancelock); return 0; -bail_put_power: - usbhid_put_power(hid); +bail_normal_power: + hid_hw_power(hid, PM_HINT_NORMAL); bail_unlock: mutex_unlock(&hiddev->existancelock); bail: diff --git a/drivers/hid/usbhid/usbhid.h b/drivers/hid/usbhid/usbhid.h index 83ef5c14aa92..ffcd329b3c3b 100644 --- a/drivers/hid/usbhid/usbhid.h +++ b/drivers/hid/usbhid/usbhid.h @@ -35,8 +35,6 @@ /* API provided by hid-core.c for USB HID drivers */ void usbhid_init_reports(struct hid_device *hid); -int usbhid_get_power(struct hid_device *hid); -void usbhid_put_power(struct hid_device *hid); struct usb_interface *usbhid_find_interface(int minor); /* iofl flags */ -- cgit From 28cbc863f4bfa92c26143493f0463e4eb96a1783 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 6 Jun 2017 23:59:33 -0700 Subject: HID: usbhid: do not rely on hid->open when deciding to do IO Instead of checking hid->open (that we plan on having HID core manage) in hid_start_in(), let's allocate a couple of new flags: HID_IN_POLLING and HID_OPENED, and use them to decide whether we should be submitting URBs or not. Signed-off-by: Dmitry Torokhov Reviewed-by: Andy Shevchenko Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hid-core.c | 25 ++++++++++++++++++------- drivers/hid/usbhid/usbhid.h | 11 +++++++++++ 2 files changed, 29 insertions(+), 7 deletions(-) (limited to 'drivers/hid/usbhid') diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index 62b660622265..d927fe4ba592 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -85,10 +85,10 @@ static int hid_start_in(struct hid_device *hid) struct usbhid_device *usbhid = hid->driver_data; spin_lock_irqsave(&usbhid->lock, flags); - if ((hid->open > 0 || hid->quirks & HID_QUIRK_ALWAYS_POLL) && - !test_bit(HID_DISCONNECTED, &usbhid->iofl) && - !test_bit(HID_SUSPENDED, &usbhid->iofl) && - !test_and_set_bit(HID_IN_RUNNING, &usbhid->iofl)) { + if (test_bit(HID_IN_POLLING, &usbhid->iofl) && + !test_bit(HID_DISCONNECTED, &usbhid->iofl) && + !test_bit(HID_SUSPENDED, &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); @@ -272,13 +272,13 @@ static int usbhid_restart_ctrl_queue(struct usbhid_device *usbhid) static void hid_irq_in(struct urb *urb) { struct hid_device *hid = urb->context; - struct usbhid_device *usbhid = hid->driver_data; + struct usbhid_device *usbhid = hid->driver_data; int status; switch (urb->status) { case 0: /* success */ usbhid->retry_delay = 0; - if ((hid->quirks & HID_QUIRK_ALWAYS_POLL) && !hid->open) + if (!test_bit(HID_OPENED, &usbhid->iofl)) break; usbhid_mark_busy(usbhid); if (!test_bit(HID_RESUME_RUNNING, &usbhid->iofl)) { @@ -692,6 +692,8 @@ static int usbhid_open(struct hid_device *hid) goto done; } usbhid->intf->needs_remote_wakeup = 1; + set_bit(HID_OPENED, &usbhid->iofl); + set_bit(HID_IN_POLLING, &usbhid->iofl); set_bit(HID_RESUME_RUNNING, &usbhid->iofl); res = hid_start_in(hid); if (res) { @@ -701,6 +703,9 @@ static int usbhid_open(struct hid_device *hid) } else { /* no use opening if resources are insufficient */ hid->open--; + clear_bit(HID_OPENED, &usbhid->iofl); + if (!(hid->quirks & HID_QUIRK_ALWAYS_POLL)) + clear_bit(HID_IN_POLLING, &usbhid->iofl); res = -EBUSY; usbhid->intf->needs_remote_wakeup = 0; } @@ -734,6 +739,9 @@ static void usbhid_close(struct hid_device *hid) */ spin_lock_irq(&usbhid->lock); if (!--hid->open) { + if (!(hid->quirks & HID_QUIRK_ALWAYS_POLL)) + clear_bit(HID_IN_POLLING, &usbhid->iofl); + clear_bit(HID_OPENED, &usbhid->iofl); spin_unlock_irq(&usbhid->lock); hid_cancel_delayed_stuff(usbhid); if (!(hid->quirks & HID_QUIRK_ALWAYS_POLL)) { @@ -1135,6 +1143,7 @@ static int usbhid_start(struct hid_device *hid) ret = usb_autopm_get_interface(usbhid->intf); if (ret) goto fail; + set_bit(HID_IN_POLLING, &usbhid->iofl); usbhid->intf->needs_remote_wakeup = 1; ret = hid_start_in(hid); if (ret) { @@ -1176,8 +1185,10 @@ static void usbhid_stop(struct hid_device *hid) if (WARN_ON(!usbhid)) return; - if (hid->quirks & HID_QUIRK_ALWAYS_POLL) + if (hid->quirks & HID_QUIRK_ALWAYS_POLL) { + clear_bit(HID_IN_POLLING, &usbhid->iofl); usbhid->intf->needs_remote_wakeup = 0; + } clear_bit(HID_STARTED, &usbhid->iofl); spin_lock_irq(&usbhid->lock); /* Sync with error and led handlers */ diff --git a/drivers/hid/usbhid/usbhid.h b/drivers/hid/usbhid/usbhid.h index ffcd329b3c3b..da9c61d54be6 100644 --- a/drivers/hid/usbhid/usbhid.h +++ b/drivers/hid/usbhid/usbhid.h @@ -49,6 +49,17 @@ struct usb_interface *usbhid_find_interface(int minor); #define HID_KEYS_PRESSED 10 #define HID_NO_BANDWIDTH 11 #define HID_RESUME_RUNNING 12 +/* + * The device is opened, meaning there is a client that is interested + * in data coming from the device. + */ +#define HID_OPENED 13 +/* + * We are polling input endpoint by [re]submitting IN URB, because + * either HID device is opened or ALWAYS POLL quirk is set for the + * device. + */ +#define HID_IN_POLLING 14 /* * USB-specific HID struct, to be pointed to -- cgit From e399396a6b061ba9e68e64e2867cc3a0f26f0ace Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 6 Jun 2017 23:59:36 -0700 Subject: HID: usbhid: remove custom locking from usbhid_open/close Now that HID core enforces serialization of transport driver open/close calls we can remove custom locking from usbhid driver. Signed-off-by: Dmitry Torokhov Reviewed-by: Andy Shevchenko Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hid-core.c | 115 +++++++++++++++++++----------------------- 1 file changed, 53 insertions(+), 62 deletions(-) (limited to 'drivers/hid/usbhid') diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index d927fe4ba592..76013eb5cb7f 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -70,8 +70,6 @@ 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 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); @@ -680,50 +678,48 @@ static int hid_get_class_descriptor(struct usb_device *dev, int ifnum, static int usbhid_open(struct hid_device *hid) { struct usbhid_device *usbhid = hid->driver_data; - int res = 0; - - mutex_lock(&hid_open_mut); - if (!hid->open++) { - res = usb_autopm_get_interface(usbhid->intf); - /* the device must be awake to reliably request remote wakeup */ - if (res < 0) { - hid->open--; - res = -EIO; - goto done; - } - usbhid->intf->needs_remote_wakeup = 1; - set_bit(HID_OPENED, &usbhid->iofl); - set_bit(HID_IN_POLLING, &usbhid->iofl); - set_bit(HID_RESUME_RUNNING, &usbhid->iofl); - res = hid_start_in(hid); - if (res) { - if (res != -ENOSPC) { - hid_io_error(hid); - res = 0; - } else { - /* no use opening if resources are insufficient */ - hid->open--; - clear_bit(HID_OPENED, &usbhid->iofl); - if (!(hid->quirks & HID_QUIRK_ALWAYS_POLL)) - clear_bit(HID_IN_POLLING, &usbhid->iofl); - res = -EBUSY; - usbhid->intf->needs_remote_wakeup = 0; - } - } - usb_autopm_put_interface(usbhid->intf); + int res; - /* - * In case events are generated while nobody was listening, - * some are released when the device is re-opened. - * Wait 50 msec for the queue to empty before allowing events - * to go through hid. - */ - if (res == 0 && !(hid->quirks & HID_QUIRK_ALWAYS_POLL)) - msleep(50); - clear_bit(HID_RESUME_RUNNING, &usbhid->iofl); + if (hid->quirks & HID_QUIRK_ALWAYS_POLL) + return 0; + + res = usb_autopm_get_interface(usbhid->intf); + /* the device must be awake to reliably request remote wakeup */ + if (res < 0) + return -EIO; + + usbhid->intf->needs_remote_wakeup = 1; + + set_bit(HID_RESUME_RUNNING, &usbhid->iofl); + set_bit(HID_OPENED, &usbhid->iofl); + set_bit(HID_IN_POLLING, &usbhid->iofl); + + res = hid_start_in(hid); + if (res) { + if (res != -ENOSPC) { + hid_io_error(hid); + res = 0; + } else { + /* no use opening if resources are insufficient */ + res = -EBUSY; + clear_bit(HID_OPENED, &usbhid->iofl); + clear_bit(HID_IN_POLLING, &usbhid->iofl); + usbhid->intf->needs_remote_wakeup = 0; + } } -done: - mutex_unlock(&hid_open_mut); + + usb_autopm_put_interface(usbhid->intf); + + /* + * In case events are generated while nobody was listening, + * some are released when the device is re-opened. + * Wait 50 msec for the queue to empty before allowing events + * to go through hid. + */ + if (res == 0) + msleep(50); + + clear_bit(HID_RESUME_RUNNING, &usbhid->iofl); return res; } @@ -731,27 +727,22 @@ static void usbhid_close(struct hid_device *hid) { struct usbhid_device *usbhid = hid->driver_data; - mutex_lock(&hid_open_mut); + if (hid->quirks & HID_QUIRK_ALWAYS_POLL) + return; - /* protecting hid->open to make sure we don't restart - * data acquistion due to a resumption we no longer - * care about + /* + * Make sure we don't restart data acquisition due to + * a resumption we no longer care about by avoiding racing + * with hid_start_in(). */ spin_lock_irq(&usbhid->lock); - if (!--hid->open) { - if (!(hid->quirks & HID_QUIRK_ALWAYS_POLL)) - clear_bit(HID_IN_POLLING, &usbhid->iofl); - clear_bit(HID_OPENED, &usbhid->iofl); - spin_unlock_irq(&usbhid->lock); - hid_cancel_delayed_stuff(usbhid); - if (!(hid->quirks & HID_QUIRK_ALWAYS_POLL)) { - usb_kill_urb(usbhid->urbin); - usbhid->intf->needs_remote_wakeup = 0; - } - } else { - spin_unlock_irq(&usbhid->lock); - } - mutex_unlock(&hid_open_mut); + clear_bit(HID_IN_POLLING, &usbhid->iofl); + clear_bit(HID_OPENED, &usbhid->iofl); + spin_unlock_irq(&usbhid->lock); + + hid_cancel_delayed_stuff(usbhid); + usb_kill_urb(usbhid->urbin); + usbhid->intf->needs_remote_wakeup = 0; } /* -- cgit