diff options
-rw-r--r-- | drivers/hid/hid-core.c | 41 | ||||
-rw-r--r-- | include/linux/hid.h | 2 |
2 files changed, 36 insertions, 7 deletions
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 1a5cf0c9cfca..f9cff9335595 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/wait.h> | 29 | #include <linux/wait.h> |
30 | #include <linux/vmalloc.h> | 30 | #include <linux/vmalloc.h> |
31 | #include <linux/sched.h> | 31 | #include <linux/sched.h> |
32 | #include <linux/semaphore.h> | ||
32 | 33 | ||
33 | #include <linux/hid.h> | 34 | #include <linux/hid.h> |
34 | #include <linux/hiddev.h> | 35 | #include <linux/hiddev.h> |
@@ -1087,14 +1088,23 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i | |||
1087 | unsigned int i; | 1088 | unsigned int i; |
1088 | int ret; | 1089 | int ret; |
1089 | 1090 | ||
1090 | if (!hid || !hid->driver) | 1091 | if (!hid) |
1091 | return -ENODEV; | 1092 | return -ENODEV; |
1093 | |||
1094 | if (down_trylock(&hid->driver_lock)) | ||
1095 | return -EBUSY; | ||
1096 | |||
1097 | if (!hid->driver) { | ||
1098 | ret = -ENODEV; | ||
1099 | goto unlock; | ||
1100 | } | ||
1092 | report_enum = hid->report_enum + type; | 1101 | report_enum = hid->report_enum + type; |
1093 | hdrv = hid->driver; | 1102 | hdrv = hid->driver; |
1094 | 1103 | ||
1095 | if (!size) { | 1104 | if (!size) { |
1096 | dbg_hid("empty report\n"); | 1105 | dbg_hid("empty report\n"); |
1097 | return -1; | 1106 | ret = -1; |
1107 | goto unlock; | ||
1098 | } | 1108 | } |
1099 | 1109 | ||
1100 | buf = kmalloc(sizeof(char) * HID_DEBUG_BUFSIZE, GFP_ATOMIC); | 1110 | buf = kmalloc(sizeof(char) * HID_DEBUG_BUFSIZE, GFP_ATOMIC); |
@@ -1118,17 +1128,23 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i | |||
1118 | nomem: | 1128 | nomem: |
1119 | report = hid_get_report(report_enum, data); | 1129 | report = hid_get_report(report_enum, data); |
1120 | 1130 | ||
1121 | if (!report) | 1131 | if (!report) { |
1122 | return -1; | 1132 | ret = -1; |
1133 | goto unlock; | ||
1134 | } | ||
1123 | 1135 | ||
1124 | if (hdrv && hdrv->raw_event && hid_match_report(hid, report)) { | 1136 | if (hdrv && hdrv->raw_event && hid_match_report(hid, report)) { |
1125 | ret = hdrv->raw_event(hid, report, data, size); | 1137 | ret = hdrv->raw_event(hid, report, data, size); |
1126 | if (ret != 0) | 1138 | if (ret != 0) { |
1127 | return ret < 0 ? ret : 0; | 1139 | ret = ret < 0 ? ret : 0; |
1140 | goto unlock; | ||
1141 | } | ||
1128 | } | 1142 | } |
1129 | 1143 | ||
1130 | hid_report_raw_event(hid, type, data, size, interrupt); | 1144 | hid_report_raw_event(hid, type, data, size, interrupt); |
1131 | 1145 | ||
1146 | unlock: | ||
1147 | up(&hid->driver_lock); | ||
1132 | return 0; | 1148 | return 0; |
1133 | } | 1149 | } |
1134 | EXPORT_SYMBOL_GPL(hid_input_report); | 1150 | EXPORT_SYMBOL_GPL(hid_input_report); |
@@ -1617,6 +1633,9 @@ static int hid_device_probe(struct device *dev) | |||
1617 | const struct hid_device_id *id; | 1633 | const struct hid_device_id *id; |
1618 | int ret = 0; | 1634 | int ret = 0; |
1619 | 1635 | ||
1636 | if (down_interruptible(&hdev->driver_lock)) | ||
1637 | return -EINTR; | ||
1638 | |||
1620 | if (!hdev->driver) { | 1639 | if (!hdev->driver) { |
1621 | id = hid_match_device(hdev, hdrv); | 1640 | id = hid_match_device(hdev, hdrv); |
1622 | if (id == NULL) | 1641 | if (id == NULL) |
@@ -1633,14 +1652,20 @@ static int hid_device_probe(struct device *dev) | |||
1633 | if (ret) | 1652 | if (ret) |
1634 | hdev->driver = NULL; | 1653 | hdev->driver = NULL; |
1635 | } | 1654 | } |
1655 | |||
1656 | up(&hdev->driver_lock); | ||
1636 | return ret; | 1657 | return ret; |
1637 | } | 1658 | } |
1638 | 1659 | ||
1639 | static int hid_device_remove(struct device *dev) | 1660 | static int hid_device_remove(struct device *dev) |
1640 | { | 1661 | { |
1641 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); | 1662 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); |
1642 | struct hid_driver *hdrv = hdev->driver; | 1663 | struct hid_driver *hdrv; |
1664 | |||
1665 | if (down_interruptible(&hdev->driver_lock)) | ||
1666 | return -EINTR; | ||
1643 | 1667 | ||
1668 | hdrv = hdev->driver; | ||
1644 | if (hdrv) { | 1669 | if (hdrv) { |
1645 | if (hdrv->remove) | 1670 | if (hdrv->remove) |
1646 | hdrv->remove(hdev); | 1671 | hdrv->remove(hdev); |
@@ -1649,6 +1674,7 @@ static int hid_device_remove(struct device *dev) | |||
1649 | hdev->driver = NULL; | 1674 | hdev->driver = NULL; |
1650 | } | 1675 | } |
1651 | 1676 | ||
1677 | up(&hdev->driver_lock); | ||
1652 | return 0; | 1678 | return 0; |
1653 | } | 1679 | } |
1654 | 1680 | ||
@@ -1996,6 +2022,7 @@ struct hid_device *hid_allocate_device(void) | |||
1996 | 2022 | ||
1997 | init_waitqueue_head(&hdev->debug_wait); | 2023 | init_waitqueue_head(&hdev->debug_wait); |
1998 | INIT_LIST_HEAD(&hdev->debug_list); | 2024 | INIT_LIST_HEAD(&hdev->debug_list); |
2025 | sema_init(&hdev->driver_lock, 1); | ||
1999 | 2026 | ||
2000 | return hdev; | 2027 | return hdev; |
2001 | err: | 2028 | err: |
diff --git a/include/linux/hid.h b/include/linux/hid.h index 9cf8e7ae7450..9c02d07af0d1 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h | |||
@@ -71,6 +71,7 @@ | |||
71 | #include <linux/timer.h> | 71 | #include <linux/timer.h> |
72 | #include <linux/workqueue.h> | 72 | #include <linux/workqueue.h> |
73 | #include <linux/input.h> | 73 | #include <linux/input.h> |
74 | #include <linux/semaphore.h> | ||
74 | 75 | ||
75 | /* | 76 | /* |
76 | * We parse each description item into this structure. Short items data | 77 | * We parse each description item into this structure. Short items data |
@@ -475,6 +476,7 @@ struct hid_device { /* device report descriptor */ | |||
475 | unsigned country; /* HID country */ | 476 | unsigned country; /* HID country */ |
476 | struct hid_report_enum report_enum[HID_REPORT_TYPES]; | 477 | struct hid_report_enum report_enum[HID_REPORT_TYPES]; |
477 | 478 | ||
479 | struct semaphore driver_lock; /* protects the current driver */ | ||
478 | struct device dev; /* device */ | 480 | struct device dev; /* device */ |
479 | struct hid_driver *driver; | 481 | struct hid_driver *driver; |
480 | struct hid_ll_driver *ll_driver; | 482 | struct hid_ll_driver *ll_driver; |