From be9f5337410f30f1cbb6b0646baf3e6810698083 Mon Sep 17 00:00:00 2001 From: hselasky Date: Thu, 10 Jan 2013 07:45:46 +0000 Subject: [PATCH] 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 --- sys/dev/usb/input/ukbd.c | 36 +++++++++---------- sys/dev/usb/input/ums.c | 47 ++++--------------------- sys/dev/usb/usb_hid.c | 76 ++++++++++++++++++++++++++++++++++++++++ sys/dev/usb/usbhid.h | 2 ++ 4 files changed, 101 insertions(+), 60 deletions(-) diff --git a/sys/dev/usb/input/ukbd.c b/sys/dev/usb/input/ukbd.c index 45ac8fc5b0f8..7a3e9552a948 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 c20c98674a83..52e1b539ebbe 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 6552546d2507..c201bb4d270b 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 f40232aac4be..f6c447cadaa1 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_ */