aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/hid/hid-core.c41
-rw-r--r--include/linux/hid.h2
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
1118nomem: 1128nomem:
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
1146unlock:
1147 up(&hid->driver_lock);
1132 return 0; 1148 return 0;
1133} 1149}
1134EXPORT_SYMBOL_GPL(hid_input_report); 1150EXPORT_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
1639static int hid_device_remove(struct device *dev) 1660static 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;
2001err: 2028err:
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;