summaryrefslogtreecommitdiffstats
path: root/sys/dev/usb
diff options
context:
space:
mode:
authorhselasky <hselasky@FreeBSD.org>2013-01-10 07:45:46 +0000
committerhselasky <hselasky@FreeBSD.org>2013-01-10 07:45:46 +0000
commitbe9f5337410f30f1cbb6b0646baf3e6810698083 (patch)
treec09445eae4ecd1ea5f4dc9102868ac4142a702db /sys/dev/usb
parent0bad7195e9475f33750e9d06c45763523c287188 (diff)
downloadFreeBSD-src-be9f5337410f30f1cbb6b0646baf3e6810698083.zip
FreeBSD-src-be9f5337410f30f1cbb6b0646baf3e6810698083.tar.gz
Fix detection of Razer Copperhead as a USB mouse.
Factor out USB mouse and keyboard detection logic. Reject USB keyboards which have mouse alike HID items in their HID descriptors. Submitted by: Matthew W MFC after: 1 week
Diffstat (limited to 'sys/dev/usb')
-rw-r--r--sys/dev/usb/input/ukbd.c36
-rw-r--r--sys/dev/usb/input/ums.c47
-rw-r--r--sys/dev/usb/usb_hid.c76
-rw-r--r--sys/dev/usb/usbhid.h2
4 files changed, 101 insertions, 60 deletions
diff --git a/sys/dev/usb/input/ukbd.c b/sys/dev/usb/input/ukbd.c
index 45ac8fc..7a3e955 100644
--- a/sys/dev/usb/input/ukbd.c
+++ b/sys/dev/usb/input/ukbd.c
@@ -995,13 +995,12 @@ ukbd_probe(device_t dev)
if (uaa->info.bInterfaceClass != UICLASS_HID)
return (ENXIO);
+ if (usb_test_quirk(uaa, UQ_KBD_IGNORE))
+ return (ENXIO);
+
if ((uaa->info.bInterfaceSubClass == UISUBCLASS_BOOT) &&
- (uaa->info.bInterfaceProtocol == UIPROTO_BOOT_KEYBOARD)) {
- if (usb_test_quirk(uaa, UQ_KBD_IGNORE))
- return (ENXIO);
- else
- return (BUS_PROBE_DEFAULT);
- }
+ (uaa->info.bInterfaceProtocol == UIPROTO_BOOT_KEYBOARD))
+ return (BUS_PROBE_DEFAULT);
error = usbd_req_get_hid_desc(uaa->device, NULL,
&d_ptr, &d_len, M_TEMP, uaa->info.bIfaceIndex);
@@ -1009,23 +1008,20 @@ ukbd_probe(device_t dev)
if (error)
return (ENXIO);
- /*
- * NOTE: we currently don't support USB mouse and USB keyboard
- * on the same USB endpoint.
- */
- if (hid_is_collection(d_ptr, d_len,
- HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_MOUSE))) {
- /* most likely a mouse */
- error = ENXIO;
- } else if (hid_is_collection(d_ptr, d_len,
- HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_KEYBOARD))) {
- if (usb_test_quirk(uaa, UQ_KBD_IGNORE))
+ if (hid_is_keyboard(d_ptr, d_len)) {
+ if (hid_is_mouse(d_ptr, d_len)) {
+ /*
+ * NOTE: We currently don't support USB mouse
+ * and USB keyboard on the same USB endpoint.
+ * Let "ums" driver win.
+ */
error = ENXIO;
- else
+ } else {
error = BUS_PROBE_DEFAULT;
- } else
+ }
+ } else {
error = ENXIO;
-
+ }
free(d_ptr, M_TEMP);
return (error);
}
diff --git a/sys/dev/usb/input/ums.c b/sys/dev/usb/input/ums.c
index c20c986..52e1b53 100644
--- a/sys/dev/usb/input/ums.c
+++ b/sys/dev/usb/input/ums.c
@@ -368,9 +368,7 @@ ums_probe(device_t dev)
{
struct usb_attach_arg *uaa = device_get_ivars(dev);
void *d_ptr;
- struct hid_data *hd;
- struct hid_item hi;
- int error, mdepth, found;
+ int error;
uint16_t d_len;
DPRINTFN(11, "\n");
@@ -394,44 +392,13 @@ ums_probe(device_t dev)
if (error)
return (ENXIO);
- hd = hid_start_parse(d_ptr, d_len, 1 << hid_input);
- if (hd == NULL)
- return (0);
- mdepth = 0;
- found = 0;
- while (hid_get_item(hd, &hi)) {
- switch (hi.kind) {
- case hid_collection:
- if (mdepth != 0)
- mdepth++;
- else if (hi.collection == 1 &&
- hi.usage ==
- HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_MOUSE))
- mdepth++;
- break;
- case hid_endcollection:
- if (mdepth != 0)
- mdepth--;
- break;
- case hid_input:
- if (mdepth == 0)
- break;
- if (hi.usage ==
- HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X) &&
- (hi.flags & MOUSE_FLAGS_MASK) == MOUSE_FLAGS)
- found++;
- if (hi.usage ==
- HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y) &&
- (hi.flags & MOUSE_FLAGS_MASK) == MOUSE_FLAGS)
- found++;
- break;
- default:
- break;
- }
- }
- hid_end_parse(hd);
+ if (hid_is_mouse(d_ptr, d_len))
+ error = BUS_PROBE_DEFAULT;
+ else
+ error = ENXIO;
+
free(d_ptr, M_TEMP);
- return (found ? BUS_PROBE_DEFAULT : ENXIO);
+ return (error);
}
static void
diff --git a/sys/dev/usb/usb_hid.c b/sys/dev/usb/usb_hid.c
index 6552546..c201bb4 100644
--- a/sys/dev/usb/usb_hid.c
+++ b/sys/dev/usb/usb_hid.c
@@ -845,3 +845,79 @@ usbd_req_get_hid_desc(struct usb_device *udev, struct mtx *mtx,
}
return (USB_ERR_NORMAL_COMPLETION);
}
+
+/*------------------------------------------------------------------------*
+ * hid_is_mouse
+ *
+ * This function will decide if a USB descriptor belongs to a USB mouse.
+ *
+ * Return values:
+ * Zero: Not a USB mouse.
+ * Else: Is a USB mouse.
+ *------------------------------------------------------------------------*/
+int
+hid_is_mouse(const void *d_ptr, uint16_t d_len)
+{
+ struct hid_data *hd;
+ struct hid_item hi;
+ int mdepth;
+ int found;
+
+ hd = hid_start_parse(d_ptr, d_len, 1 << hid_input);
+ if (hd == NULL)
+ return (0);
+
+ mdepth = 0;
+ found = 0;
+
+ while (hid_get_item(hd, &hi)) {
+ switch (hi.kind) {
+ case hid_collection:
+ if (mdepth != 0)
+ mdepth++;
+ else if (hi.collection == 1 &&
+ hi.usage ==
+ HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_MOUSE))
+ mdepth++;
+ break;
+ case hid_endcollection:
+ if (mdepth != 0)
+ mdepth--;
+ break;
+ case hid_input:
+ if (mdepth == 0)
+ break;
+ if (hi.usage ==
+ HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X) &&
+ (hi.flags & (HIO_CONST|HIO_RELATIVE)) == HIO_RELATIVE)
+ found++;
+ if (hi.usage ==
+ HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y) &&
+ (hi.flags & (HIO_CONST|HIO_RELATIVE)) == HIO_RELATIVE)
+ found++;
+ break;
+ default:
+ break;
+ }
+ }
+ hid_end_parse(hd);
+ return (found);
+}
+
+/*------------------------------------------------------------------------*
+ * hid_is_keyboard
+ *
+ * This function will decide if a USB descriptor belongs to a USB keyboard.
+ *
+ * Return values:
+ * Zero: Not a USB keyboard.
+ * Else: Is a USB keyboard.
+ *------------------------------------------------------------------------*/
+int
+hid_is_keyboard(const void *d_ptr, uint16_t d_len)
+{
+ if (hid_is_collection(d_ptr, d_len,
+ HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_KEYBOARD)))
+ return (1);
+ return (0);
+}
diff --git a/sys/dev/usb/usbhid.h b/sys/dev/usb/usbhid.h
index f40232a..f6c447c 100644
--- a/sys/dev/usb/usbhid.h
+++ b/sys/dev/usb/usbhid.h
@@ -242,5 +242,7 @@ struct usb_hid_descriptor *hid_get_descriptor_from_usb(
usb_error_t usbd_req_get_hid_desc(struct usb_device *udev, struct mtx *mtx,
void **descp, uint16_t *sizep, struct malloc_type *mem,
uint8_t iface_index);
+int hid_is_mouse(const void *d_ptr, uint16_t d_len);
+int hid_is_keyboard(const void *d_ptr, uint16_t d_len);
#endif /* _KERNEL */
#endif /* _USB_HID_H_ */
OpenPOWER on IntegriCloud