This originally came about as report of uhid sending duplicate open and
premature close when hidraw was used alongside of input. After looking at
the drivers I think we should consolidate user tracking inside of the HID
core. While implementing this, there were a few cleanups as well.
V2:
- added greybus hid changes
- added error handling in hiddev around hid_hw_open which is __much_check
Dmitry Torokhov (8):
HID: hiddev: use hid_hw_open/close instead of usbhid_open/close
HID: hiddev: use hid_hw_power instead of usbhid_get/put_power
HID: usbhid: do not rely on hid->open when deciding to do IO
HID: serialize hid_hw_open and hid_hw_close
HID: i2c-hid: remove custom locking from i2c_hid_open/close
HID: usbhid: remove custom locking from usbhid_open/close
greybus: hid: remove custom locking from gb_hid_open/close
HID: remove no longer used hid->open field
drivers/hid/hid-core.c | 89 +++++++++++++++++++++++++
drivers/hid/i2c-hid/i2c-hid.c | 32 +++------
drivers/hid/usbhid/hid-core.c | 150 ++++++++++++++++++++----------------------
drivers/hid/usbhid/hiddev.c | 24 +++----
drivers/hid/usbhid/usbhid.h | 15 +++--
drivers/staging/greybus/hid.c | 43 ++++--------
include/linux/hid.h | 73 +++-----------------
7 files changed, 214 insertions(+), 212 deletions(-)
Thanks.
--
Dmitry
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 <dmitry.torokhov@gmail.com>
---
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(-)
@@ -35,8 +35,6 @@/* API provided by hid-core.c for USB HID drivers */voidusbhid_init_reports(structhid_device*hid);-intusbhid_get_power(structhid_device*hid);-voidusbhid_put_power(structhid_device*hid);structusb_interface*usbhid_find_interface(intminor);/* iofl flags */
@@ -32,8 +32,6 @@ struct gb_hid {char*inbuf;};-staticDEFINE_MUTEX(gb_hid_open_mutex);-/* Routines to get controller's information over greybus *//* Operations performed on greybus */
@@ -366,21 +359,13 @@ static void gb_hid_close(struct hid_device *hid)structgb_hid*ghid=hid->driver_data;intret;-/*-*Protectinghid->opentomakesurewedon'trestartdataacquistion-*duetoaresumptionwenolongercareabout..-*/-mutex_lock(&gb_hid_open_mutex);-if(!--hid->open){-clear_bit(GB_HID_STARTED,&ghid->flags);--/* Save some power */-ret=gb_hid_set_power(ghid,GB_HID_TYPE_PWR_OFF);-if(ret)-dev_err(&ghid->connection->bundle->dev,-"failed to power off (%d)\n",ret);-}-mutex_unlock(&gb_hid_open_mutex);+clear_bit(GB_HID_STARTED,&ghid->flags);++/* Save some power */+ret=gb_hid_set_power(ghid,GB_HID_TYPE_PWR_OFF);+if(ret)+dev_err(&ghid->connection->bundle->dev,+"failed to power off (%d)\n",ret);}staticintgb_hid_power(structhid_device*hid,intlvl)
Now that all users have migrated to use hid->ll_open_count, we can remove
hid->open field.
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
include/linux/hid.h | 1 -
1 file changed, 1 deletion(-)
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 <dmitry.torokhov@gmail.com>
---
drivers/hid/usbhid/hid-core.c | 115 +++++++++++++++++++-----------------------
1 file changed, 53 insertions(+), 62 deletions(-)
@@ -70,8 +70,6 @@ MODULE_PARM_DESC(quirks, "Add/modify USB HID quirks by specifying "/**InputsubmissionandI/Oerrorhandler.*/-staticDEFINE_MUTEX(hid_open_mut);-staticvoidhid_io_error(structhid_device*hid);staticinthid_submit_out(structhid_device*hid);staticinthid_submit_ctrl(structhid_device*hid);
@@ -680,50 +678,48 @@ static int hid_get_class_descriptor(struct usb_device *dev, int ifnum,staticintusbhid_open(structhid_device*hid){structusbhid_device*usbhid=hid->driver_data;-intres=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;-gotodone;-}-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);+intres;-/*-*Incaseeventsaregeneratedwhilenobodywaslistening,-*somearereleasedwhenthedeviceisre-opened.-*Wait50msecforthequeuetoemptybeforeallowingevents-*togothroughhid.-*/-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)+return0;++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);++/*+*Incaseeventsaregeneratedwhilenobodywaslistening,+*somearereleasedwhenthedeviceisre-opened.+*Wait50msecforthequeuetoemptybeforeallowingevents+*togothroughhid.+*/+if(res==0)+msleep(50);++clear_bit(HID_RESUME_RUNNING,&usbhid->iofl);returnres;}
@@ -731,27 +727,22 @@ static void usbhid_close(struct hid_device *hid){structusbhid_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-*dataacquistionduetoaresumptionwenolonger-*careabout+/*+*Makesurewedon'trestartdataacquisitiondueto+*aresumptionwenolongercareaboutbyavoidingracing+*withhid_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;}/*
Now that HID core enforces serialization of transport driver open/close
calls we can remove custom locking from i2c-hid driver.
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
drivers/hid/i2c-hid/i2c-hid.c | 32 +++++++++-----------------------
1 file changed, 9 insertions(+), 23 deletions(-)
@@ -743,18 +743,12 @@ static int i2c_hid_open(struct hid_device *hid)structi2c_hid*ihid=i2c_get_clientdata(client);intret=0;-mutex_lock(&i2c_hid_open_mut);-if(!hid->open++){-ret=pm_runtime_get_sync(&client->dev);-if(ret<0){-hid->open--;-gotodone;-}-set_bit(I2C_HID_STARTED,&ihid->flags);-}-done:-mutex_unlock(&i2c_hid_open_mut);-returnret<0?ret:0;+ret=pm_runtime_get_sync(&client->dev);+if(ret<0)+returnret;++set_bit(I2C_HID_STARTED,&ihid->flags);+return0;}staticvoidi2c_hid_close(structhid_device*hid)
@@ -762,18 +756,10 @@ static void i2c_hid_close(struct hid_device *hid)structi2c_client*client=hid->driver_data;structi2c_hid*ihid=i2c_get_clientdata(client);-/* protecting hid->open to make sure we don't restart-*dataacquistionduetoaresumptionwenolonger-*careabout-*/-mutex_lock(&i2c_hid_open_mut);-if(!--hid->open){-clear_bit(I2C_HID_STARTED,&ihid->flags);+clear_bit(I2C_HID_STARTED,&ihid->flags);-/* Save some power */-pm_runtime_put(&client->dev);-}-mutex_unlock(&i2c_hid_open_mut);+/* Save some power */+pm_runtime_put(&client->dev);}staticinti2c_hid_power(structhid_device*hid,intlvl)
The HID transport drivers either re-implement exactly the same logic
(usbhid, i2c-hid) or forget to implement it (usbhid) which causes issues
when the same device is accessed via multiple interfaces (for example input
device through evdev and also hidraw). Let's muve the locking logic into
HID core to make sure the serialized behavior is always enforced.
Also let's uninline and move hid_hw_start() and hid_hw_stop() into hid-core
as hid_hw_start() is somewhat large and do not believe we get any benefit
from these two being inline.
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
drivers/hid/hid-core.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/hid.h | 72 +++++-----------------------------------
2 files changed, 98 insertions(+), 63 deletions(-)
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 <dmitry.torokhov@gmail.com>
---
drivers/hid/usbhid/hid-core.c | 25 ++++++++++++++++++-------
drivers/hid/usbhid/usbhid.h | 11 +++++++++++
2 files changed, 29 insertions(+), 7 deletions(-)
@@ -692,6 +692,8 @@ static int usbhid_open(struct hid_device *hid)gotodone;}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;}
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 <dmitry.torokhov@gmail.com>
---
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(-)
@@ -34,8 +34,6 @@#include<linux/input.h>/* API provided by hid-core.c for USB HID drivers */-voidusbhid_close(structhid_device*hid);-intusbhid_open(structhid_device*hid);voidusbhid_init_reports(structhid_device*hid);intusbhid_get_power(structhid_device*hid);voidusbhid_put_power(structhid_device*hid);
From: Andy Shevchenko <hidden> Date: 2017-06-07 08:40:22
On Wed, Jun 7, 2017 at 9:59 AM, Dmitry Torokhov
[off-list ref] wrote:
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().
break;
+
case PM_HINT_NORMAL:
}
+
return r;
I think you can drop above changes.
--
With Best Regards,
Andy Shevchenko
From: Andy Shevchenko <hidden> Date: 2017-06-07 08:45:50
On Wed, Jun 7, 2017 at 9:59 AM, Dmitry Torokhov
[off-list ref] wrote:
This originally came about as report of uhid sending duplicate open and
premature close when hidraw was used alongside of input. After looking at
the drivers I think we should consolidate user tracking inside of the HID
core. While implementing this, there were a few cleanups as well.
V2:
- added greybus hid changes
- added error handling in hiddev around hid_hw_open which is __much_check
FWIW,
Reviewed-by: Andy Shevchenko <redacted>
Dmitry Torokhov (8):
HID: hiddev: use hid_hw_open/close instead of usbhid_open/close
HID: hiddev: use hid_hw_power instead of usbhid_get/put_power
HID: usbhid: do not rely on hid->open when deciding to do IO
HID: serialize hid_hw_open and hid_hw_close
HID: i2c-hid: remove custom locking from i2c_hid_open/close
HID: usbhid: remove custom locking from usbhid_open/close
greybus: hid: remove custom locking from gb_hid_open/close
HID: remove no longer used hid->open field
drivers/hid/hid-core.c | 89 +++++++++++++++++++++++++
drivers/hid/i2c-hid/i2c-hid.c | 32 +++------
drivers/hid/usbhid/hid-core.c | 150 ++++++++++++++++++++----------------------
drivers/hid/usbhid/hiddev.c | 24 +++----
drivers/hid/usbhid/usbhid.h | 15 +++--
drivers/staging/greybus/hid.c | 43 ++++--------
include/linux/hid.h | 73 +++-----------------
7 files changed, 214 insertions(+), 212 deletions(-)
Thanks.
--
Dmitry
From: Benjamin Tissoires <hidden> Date: 2017-06-07 13:43:35
On Jun 06 2017 or thereabouts, Dmitry Torokhov wrote:
This originally came about as report of uhid sending duplicate open and
premature close when hidraw was used alongside of input. After looking at
the drivers I think we should consolidate user tracking inside of the HID
core. While implementing this, there were a few cleanups as well.
V2:
- added greybus hid changes
- added error handling in hiddev around hid_hw_open which is __much_check
Looks good to me:
Reviewed-by: Benjamin Tissoires <redacted>
Dmitry Torokhov (8):
HID: hiddev: use hid_hw_open/close instead of usbhid_open/close
HID: hiddev: use hid_hw_power instead of usbhid_get/put_power
HID: usbhid: do not rely on hid->open when deciding to do IO
HID: serialize hid_hw_open and hid_hw_close
HID: i2c-hid: remove custom locking from i2c_hid_open/close
HID: usbhid: remove custom locking from usbhid_open/close
greybus: hid: remove custom locking from gb_hid_open/close
HID: remove no longer used hid->open field
drivers/hid/hid-core.c | 89 +++++++++++++++++++++++++
drivers/hid/i2c-hid/i2c-hid.c | 32 +++------
drivers/hid/usbhid/hid-core.c | 150 ++++++++++++++++++++----------------------
drivers/hid/usbhid/hiddev.c | 24 +++----
drivers/hid/usbhid/usbhid.h | 15 +++--
drivers/staging/greybus/hid.c | 43 ++++--------
include/linux/hid.h | 73 +++-----------------
7 files changed, 214 insertions(+), 212 deletions(-)
Thanks.
--
Dmitry
This originally came about as report of uhid sending duplicate open and
premature close when hidraw was used alongside of input. After looking at
the drivers I think we should consolidate user tracking inside of the HID
core. While implementing this, there were a few cleanups as well.
V2:
- added greybus hid changes
- added error handling in hiddev around hid_hw_open which is __much_check