From 4ea5454203d991ec85264f64f89ca8855fce69b0 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Wed, 10 Aug 2011 14:02:07 +0200 Subject: HID: Fix race condition between driver core and ll-driver HID low level drivers register new devices with the HID core which then adds the devices to the HID bus. The HID bus normally immediately probes an appropriate driver which then handles HID input for this device. The ll driver now uses the hid_input_report() function to report input events for a specific device. However, if the HID bus unloads the driver at the same time (for instance via a call to /sys/bus/hid/devices//unbind) then the hdev->driver pointer may be used by hid_input_report() and hid_device_remove() at the same time which may cause hdev->driver to point to invalid memory. This fix adds a semaphore to every hid device which protects hdev->driver from asynchronous access. This semaphore is locked during driver *_probe and *_remove and also inside hid_input_report(). The *_probe and *_remove functions may sleep so the semaphore is good here, however, hid_input_report() is in atomic context and hence only uses down_trylock(). If it cannot acquire the lock it simply drops the input package. The low-level drivers report input events synchronously so hid_input_report() should never be entered twice at the same time on the same device. Hence, the lock should always be available. But if the driver is currently probed/removed then the lock is not available and dropping the package should be safe because this is what would have happened if the package arrived some milliseconds earlier/later. This also fixes another race condition while probing drivers: First the *_probe function of the driver is called and only if that succeeds, the related input device of hidinput is registered. If the low level driver reports input events after the *_probe function returned but before the input device is registered, then a NULL pointer dereference will occur. (Equivalently on driver remove function). This is not possible anymore, since the semaphore lock drops all incoming packages until the driver/device is fully initialized. Signed-off-by: David Herrmann Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 41 ++++++++++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 7 deletions(-) (limited to 'drivers/hid/hid-core.c') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 1a5cf0c9cfc..f9cff933559 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -1087,14 +1088,23 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i unsigned int i; int ret; - if (!hid || !hid->driver) + if (!hid) return -ENODEV; + + if (down_trylock(&hid->driver_lock)) + return -EBUSY; + + if (!hid->driver) { + ret = -ENODEV; + goto unlock; + } report_enum = hid->report_enum + type; hdrv = hid->driver; if (!size) { dbg_hid("empty report\n"); - return -1; + ret = -1; + goto unlock; } 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 nomem: report = hid_get_report(report_enum, data); - if (!report) - return -1; + if (!report) { + ret = -1; + goto unlock; + } if (hdrv && hdrv->raw_event && hid_match_report(hid, report)) { ret = hdrv->raw_event(hid, report, data, size); - if (ret != 0) - return ret < 0 ? ret : 0; + if (ret != 0) { + ret = ret < 0 ? ret : 0; + goto unlock; + } } hid_report_raw_event(hid, type, data, size, interrupt); +unlock: + up(&hid->driver_lock); return 0; } EXPORT_SYMBOL_GPL(hid_input_report); @@ -1617,6 +1633,9 @@ static int hid_device_probe(struct device *dev) const struct hid_device_id *id; int ret = 0; + if (down_interruptible(&hdev->driver_lock)) + return -EINTR; + if (!hdev->driver) { id = hid_match_device(hdev, hdrv); if (id == NULL) @@ -1633,14 +1652,20 @@ static int hid_device_probe(struct device *dev) if (ret) hdev->driver = NULL; } + + up(&hdev->driver_lock); return ret; } static int hid_device_remove(struct device *dev) { struct hid_device *hdev = container_of(dev, struct hid_device, dev); - struct hid_driver *hdrv = hdev->driver; + struct hid_driver *hdrv; + + if (down_interruptible(&hdev->driver_lock)) + return -EINTR; + hdrv = hdev->driver; if (hdrv) { if (hdrv->remove) hdrv->remove(hdev); @@ -1649,6 +1674,7 @@ static int hid_device_remove(struct device *dev) hdev->driver = NULL; } + up(&hdev->driver_lock); return 0; } @@ -1996,6 +2022,7 @@ struct hid_device *hid_allocate_device(void) init_waitqueue_head(&hdev->debug_wait); INIT_LIST_HEAD(&hdev->debug_list); + sema_init(&hdev->driver_lock, 1); return hdev; err: -- cgit v1.2.3-18-g5258 From 45dc1ac73d28b3adb5819818785e758b1f369b74 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Wed, 10 Aug 2011 14:02:59 +0200 Subject: HID: propagate return value correctly in hid_input_report() Fix a return value propagation that was omitted in David Herrmann's locking fix around hid_input_report(). Reported-by: David Herrmann Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/hid/hid-core.c') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index f9cff933559..bf1f74041dc 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1086,7 +1086,7 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i struct hid_report *report; char *buf; unsigned int i; - int ret; + int ret = 0; if (!hid) return -ENODEV; @@ -1145,7 +1145,7 @@ nomem: unlock: up(&hid->driver_lock); - return 0; + return ret; } EXPORT_SYMBOL_GPL(hid_input_report); -- cgit v1.2.3-18-g5258 From f6f554f09c5b831efdaf67c449e18ca06ee648fe Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Wed, 10 Aug 2011 14:12:52 +0200 Subject: HID: add MacBookAir4,2 to hid_have_special_driver[] Otherwise the generic driver wouldn't unbind from it and wouldn't let hid-apple to automatically take over. Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/hid/hid-core.c') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index bf1f74041dc..681387377ed 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1356,6 +1356,9 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ISO) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_JIS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_ISO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_JIS) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS) }, -- cgit v1.2.3-18-g5258 From ad395ccadb6b2f0a4f9e004c9e6f2a8c22091ed0 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Sun, 14 Aug 2011 20:42:05 +0100 Subject: IHD: Support force feedback on MP-8866 Support force feedback on the Dual USB Force Feedback Joypad (MP-8866). Signed-off-by: Sean Young Acked-by: Jussi Kivilinna Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/hid/hid-core.c') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 681387377ed..d34eb34dbe2 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1517,6 +1517,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_UNITEC, USB_DEVICE_ID_UNITEC_USB_TOUCH_0709) }, { HID_USB_DEVICE(USB_VENDOR_ID_UNITEC, USB_DEVICE_ID_UNITEC_USB_TOUCH_0A19) }, { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SMARTJOY_PLUS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) }, { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SLIM_TABLET_5_8_INCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SLIM_TABLET_12_1_INCH) }, -- cgit v1.2.3-18-g5258 From ba623a774f5b529f89b3d63e0837df52e16ffb3b Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 24 Aug 2011 14:27:46 +0300 Subject: HID: unlock on error path in hid_device_probe() We recently introduced locking into this function, but we missed an error path which needs an unlock. Signed-off-by: Dan Carpenter Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/hid/hid-core.c') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index d34eb34dbe2..d98332b1100 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1642,8 +1642,10 @@ static int hid_device_probe(struct device *dev) if (!hdev->driver) { id = hid_match_device(hdev, hdrv); - if (id == NULL) - return -ENODEV; + if (id == NULL) { + ret = -ENODEV; + goto unlock; + } hdev->driver = hdrv; if (hdrv->probe) { @@ -1656,7 +1658,7 @@ static int hid_device_probe(struct device *dev) if (ret) hdev->driver = NULL; } - +unlock: up(&hdev->driver_lock); return ret; } -- cgit v1.2.3-18-g5258 From d762cc290b9f17e346f4297fd5984b70ce71ef66 Mon Sep 17 00:00:00 2001 From: Nobuhiro Iwamatsu Date: Sat, 1 Oct 2011 15:54:53 +0900 Subject: HID: Add support MacbookAir 4,1 keyboard Added USB device IDs and keyboard map for MacBookAir 4,1 keyboard. Signed-off-by: Nobuhiro Iwamatsu Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/hid/hid-core.c') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index d98332b1100..5b4b76e6c90 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1359,6 +1359,9 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_ISO) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_JIS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS) }, -- cgit v1.2.3-18-g5258 From 4b086910ad1b889ddf3ef5598caec03178cf2bb4 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Tue, 4 Oct 2011 14:01:12 +0200 Subject: HID: MacbookAir4,1 and MacbookAir4,2 need entry in hid_mouse_ignore_list[] The respective mouse devices are already supported by bcm5974. Now that Nobuhiro Iwamatsu added support for keyboard to hid-apple driver, we need to ignore the mouse interfaces of these so that they can still be properly claimed by bcm5974 driver. Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/hid/hid-core.c') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 5b4b76e6c90..d5dae955cc4 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1924,6 +1924,12 @@ static const struct hid_device_id hid_mouse_ignore_list[] = { { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ISO) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_JIS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_ISO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_JIS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) }, { } -- cgit v1.2.3-18-g5258 From f6a04605f303852963f3f357d19b967aa83c172f Mon Sep 17 00:00:00 2001 From: Terry Lambert Date: Fri, 14 Oct 2011 17:18:54 -0700 Subject: HID: support primax keyboards violating USB HID spec Primax keyboards with the issue this driver addresses report modifier keys as in band key events instead of as out of band modifier bits, resulting in the modifier keys generating key up events immediately before the keys they are intended to modify. This driver rewrites the raw report data from such keyboards into USB HID 1.11 compliant report data. It only matches the USB vendor and product IDs for the keyboard it has been tested on. Since there are several keyboards, notably a number of laptops and folding USB keyboards known to have similar unresolved problem reports, the list is expected to grow. Signed-off-by: Terry Lambert Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/hid/hid-core.c') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index d5dae955cc4..df693e7ccc9 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1480,6 +1480,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_WKB2000) }, { HID_USB_DEVICE(USB_VENDOR_ID_PENMOUNT, USB_DEVICE_ID_PENMOUNT_PCI) }, { HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_KEYBOARD) }, { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN) }, { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONE) }, -- cgit v1.2.3-18-g5258 From 1bcc20675a1ac1ba47eaa201e02a89b0508e17b2 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Thu, 20 Oct 2011 21:26:21 +0100 Subject: HID: Add device IDs for more SJOY adapters Support the following models: Super Joy Box 3 Pro, Super Dual Box Pro and Super Joy Box 5 Pro. These models have support for pressure sensitive buttons and they can force the controller to either digital or analog mode, both of which are not supported yet. Signed-off-by: Sean Young Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/hid/hid-core.c') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index df693e7ccc9..e345370dc52 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1522,6 +1522,9 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_UNITEC, USB_DEVICE_ID_UNITEC_USB_TOUCH_0A19) }, { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SMARTJOY_PLUS) }, { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD) }, + { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SUPER_JOY_BOX_3_PRO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SUPER_DUAL_BOX_PRO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SUPER_JOY_BOX_5_PRO) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) }, { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SLIM_TABLET_5_8_INCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SLIM_TABLET_12_1_INCH) }, -- cgit v1.2.3-18-g5258