diff options
-rw-r--r-- | drivers/hid/hid-core.c | 24 | ||||
-rw-r--r-- | include/linux/hid.h | 46 |
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 | ||
1326 | unlock: | 1326 | unlock: |
1327 | up(&hid->driver_lock); | 1327 | up(&hid->driver_input_lock); |
1328 | return ret; | 1328 | return ret; |
1329 | } | 1329 | } |
1330 | EXPORT_SYMBOL_GPL(hid_input_report); | 1330 | EXPORT_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 | } |
1869 | unlock: | 1874 | unlock: |
1875 | if (!hdev->io_started) | ||
1876 | up(&hdev->driver_input_lock); | ||
1877 | unlock_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); | ||
1908 | unlock_driver_lock: | ||
1892 | up(&hdev->driver_lock); | 1909 | up(&hdev->driver_lock); |
1893 | return 0; | 1910 | return ret; |
1894 | } | 1911 | } |
1895 | 1912 | ||
1896 | static ssize_t modalias_show(struct device *dev, struct device_attribute *a, | 1913 | static 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, | |||
738 | s32 hid_snto32(__u32 value, unsigned n); | 744 | s32 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 | */ | ||
755 | static 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 | */ | ||
775 | static 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 |