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
This commit is contained in:
hselasky 2013-01-10 07:45:46 +00:00
parent 0bad7195e9
commit be9f533741
4 changed files with 101 additions and 60 deletions

View File

@ -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);
}

View File

@ -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

View File

@ -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);
}

View File

@ -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_ */