aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew de los Reyes <adlr@chromium.org>2013-02-18 12:20:21 -0500
committerJiri Kosina <jkosina@suse.cz>2013-03-01 08:13:07 -0500
commitc849a6143bec520aff2a6646518b0d041402428b (patch)
tree95da329533d67acdd1ee0152a6212346062707a5
parent48a732dfaa77a4dfec803aa8f248373998704f76 (diff)
HID: Separate struct hid_device's driver_lock into two locks.
This patch separates struct hid_device's driver_lock into two. The goal is to allow hid device drivers to receive input during their probe() or remove() function calls. This is necessary because some drivers need to communicate with the device to determine parameters needed during probe (e.g., size of a multi-touch surface), and if possible, may perfer to communicate with a device on host-initiated disconnect (e.g., to put it into a low-power state). Historically, three functions used driver_lock: - hid_device_probe: blocks to acquire lock - hid_device_remove: blocks to acquire lock - hid_input_report: if locked returns -EBUSY, else acquires lock This patch adds another lock (driver_input_lock) which is used to block input from occurring. The lock behavior is now: - hid_device_probe: blocks to acq. driver_lock, then driver_input_lock - hid_device_remove: blocks to acq. driver_lock, then driver_input_lock - hid_input_report: if driver_input_lock locked returns -EBUSY, else acquires driver_input_lock This patch also adds two helper functions to be called during probe() or remove(): hid_device_io_start() and hid_device_io_stop(). These functions lock and unlock, respectively, driver_input_lock; they also make a note of whether they did so that hid-core knows if a driver has changed the lock state. This patch results in no behavior change for existing devices and drivers. However, during a probe() or remove() function call in a driver, that driver may now selectively call hid_device_io_start() to let input events come through, then optionally call hid_device_io_stop() to stop them. Signed-off-by: Andrew de los Reyes <adlr@chromium.org> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
-rw-r--r--drivers/hid/hid-core.c24
-rw-r--r--include/linux/hid.h46
2 files changed, 66 insertions, 4 deletions
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index ff75cabf7393..680068c0c46a 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1267,7 +1267,7 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i
1267 if (!hid) 1267 if (!hid)
1268 return -ENODEV; 1268 return -ENODEV;
1269 1269
1270 if (down_trylock(&hid->driver_lock)) 1270 if (down_trylock(&hid->driver_input_lock))
1271 return -EBUSY; 1271 return -EBUSY;
1272 1272
1273 if (!hid->driver) { 1273 if (!hid->driver) {
@@ -1324,7 +1324,7 @@ nomem:
1324 ret = hid_report_raw_event(hid, type, data, size, interrupt); 1324 ret = hid_report_raw_event(hid, type, data, size, interrupt);
1325 1325
1326unlock: 1326unlock:
1327 up(&hid->driver_lock); 1327 up(&hid->driver_input_lock);
1328 return ret; 1328 return ret;
1329} 1329}
1330EXPORT_SYMBOL_GPL(hid_input_report); 1330EXPORT_SYMBOL_GPL(hid_input_report);
@@ -1845,6 +1845,11 @@ static int hid_device_probe(struct device *dev)
1845 1845
1846 if (down_interruptible(&hdev->driver_lock)) 1846 if (down_interruptible(&hdev->driver_lock))
1847 return -EINTR; 1847 return -EINTR;
1848 if (down_interruptible(&hdev->driver_input_lock)) {
1849 ret = -EINTR;
1850 goto unlock_driver_lock;
1851 }
1852 hdev->io_started = false;
1848 1853
1849 if (!hdev->driver) { 1854 if (!hdev->driver) {
1850 id = hid_match_device(hdev, hdrv); 1855 id = hid_match_device(hdev, hdrv);
@@ -1867,6 +1872,9 @@ static int hid_device_probe(struct device *dev)
1867 } 1872 }
1868 } 1873 }
1869unlock: 1874unlock:
1875 if (!hdev->io_started)
1876 up(&hdev->driver_input_lock);
1877unlock_driver_lock:
1870 up(&hdev->driver_lock); 1878 up(&hdev->driver_lock);
1871 return ret; 1879 return ret;
1872} 1880}
@@ -1875,9 +1883,15 @@ static int hid_device_remove(struct device *dev)
1875{ 1883{
1876 struct hid_device *hdev = container_of(dev, struct hid_device, dev); 1884 struct hid_device *hdev = container_of(dev, struct hid_device, dev);
1877 struct hid_driver *hdrv; 1885 struct hid_driver *hdrv;
1886 int ret = 0;
1878 1887
1879 if (down_interruptible(&hdev->driver_lock)) 1888 if (down_interruptible(&hdev->driver_lock))
1880 return -EINTR; 1889 return -EINTR;
1890 if (down_interruptible(&hdev->driver_input_lock)) {
1891 ret = -EINTR;
1892 goto unlock_driver_lock;
1893 }
1894 hdev->io_started = false;
1881 1895
1882 hdrv = hdev->driver; 1896 hdrv = hdev->driver;
1883 if (hdrv) { 1897 if (hdrv) {
@@ -1889,8 +1903,11 @@ static int hid_device_remove(struct device *dev)
1889 hdev->driver = NULL; 1903 hdev->driver = NULL;
1890 } 1904 }
1891 1905
1906 if (!hdev->io_started)
1907 up(&hdev->driver_input_lock);
1908unlock_driver_lock:
1892 up(&hdev->driver_lock); 1909 up(&hdev->driver_lock);
1893 return 0; 1910 return ret;
1894} 1911}
1895 1912
1896static ssize_t modalias_show(struct device *dev, struct device_attribute *a, 1913static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
@@ -2329,6 +2346,7 @@ struct hid_device *hid_allocate_device(void)
2329 init_waitqueue_head(&hdev->debug_wait); 2346 init_waitqueue_head(&hdev->debug_wait);
2330 INIT_LIST_HEAD(&hdev->debug_list); 2347 INIT_LIST_HEAD(&hdev->debug_list);
2331 sema_init(&hdev->driver_lock, 1); 2348 sema_init(&hdev->driver_lock, 1);
2349 sema_init(&hdev->driver_input_lock, 1);
2332 2350
2333 return hdev; 2351 return hdev;
2334} 2352}
diff --git a/include/linux/hid.h b/include/linux/hid.h
index e14b465b1146..895b85639dec 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -456,7 +456,8 @@ struct hid_device { /* device report descriptor */
456 unsigned country; /* HID country */ 456 unsigned country; /* HID country */
457 struct hid_report_enum report_enum[HID_REPORT_TYPES]; 457 struct hid_report_enum report_enum[HID_REPORT_TYPES];
458 458
459 struct semaphore driver_lock; /* protects the current driver */ 459 struct semaphore driver_lock; /* protects the current driver, except during input */
460 struct semaphore driver_input_lock; /* protects the current driver */
460 struct device dev; /* device */ 461 struct device dev; /* device */
461 struct hid_driver *driver; 462 struct hid_driver *driver;
462 struct hid_ll_driver *ll_driver; 463 struct hid_ll_driver *ll_driver;
@@ -477,6 +478,7 @@ struct hid_device { /* device report descriptor */
477 unsigned int status; /* see STAT flags above */ 478 unsigned int status; /* see STAT flags above */
478 unsigned claimed; /* Claimed by hidinput, hiddev? */ 479 unsigned claimed; /* Claimed by hidinput, hiddev? */
479 unsigned quirks; /* Various quirks the device can pull on us */ 480 unsigned quirks; /* Various quirks the device can pull on us */
481 bool io_started; /* Protected by driver_lock. If IO has started */
480 482
481 struct list_head inputs; /* The list of inputs */ 483 struct list_head inputs; /* The list of inputs */
482 void *hiddev; /* The hiddev structure */ 484 void *hiddev; /* The hiddev structure */
@@ -599,6 +601,10 @@ struct hid_usage_id {
599 * @resume: invoked on resume if device was not reset (NULL means nop) 601 * @resume: invoked on resume if device was not reset (NULL means nop)
600 * @reset_resume: invoked on resume if device was reset (NULL means nop) 602 * @reset_resume: invoked on resume if device was reset (NULL means nop)
601 * 603 *
604 * probe should return -errno on error, or 0 on success. During probe,
605 * input will not be passed to raw_event unless hid_device_io_start is
606 * called.
607 *
602 * raw_event and event should return 0 on no action performed, 1 when no 608 * raw_event and event should return 0 on no action performed, 1 when no
603 * further processing should be done and negative on error 609 * further processing should be done and negative on error
604 * 610 *
@@ -738,6 +744,44 @@ const struct hid_device_id *hid_match_id(struct hid_device *hdev,
738s32 hid_snto32(__u32 value, unsigned n); 744s32 hid_snto32(__u32 value, unsigned n);
739 745
740/** 746/**
747 * hid_device_io_start - enable HID input during probe, remove
748 *
749 * @hid - the device
750 *
751 * This should only be called during probe or remove and only be
752 * called by the thread calling probe or remove. It will allow
753 * incoming packets to be delivered to the driver.
754 */
755static inline void hid_device_io_start(struct hid_device *hid) {
756 if (hid->io_started) {
757 dev_warn(&hid->dev, "io already started");
758 return;
759 }
760 hid->io_started = true;
761 up(&hid->driver_input_lock);
762}
763
764/**
765 * hid_device_io_stop - disable HID input during probe, remove
766 *
767 * @hid - the device
768 *
769 * Should only be called after hid_device_io_start. It will prevent
770 * incoming packets from going to the driver for the duration of
771 * probe, remove. If called during probe, packets will still go to the
772 * driver after probe is complete. This function should only be called
773 * by the thread calling probe or remove.
774 */
775static inline void hid_device_io_stop(struct hid_device *hid) {
776 if (!hid->io_started) {
777 dev_warn(&hid->dev, "io already stopped");
778 return;
779 }
780 hid->io_started = false;
781 down(&hid->driver_input_lock);
782}
783
784/**
741 * hid_map_usage - map usage input bits 785 * hid_map_usage - map usage input bits
742 * 786 *
743 * @hidinput: hidinput which we are interested in 787 * @hidinput: hidinput which we are interested in