Author: hselasky
Date: Thu Jan 10 07:45:46 2013
New Revision: 245248
URL: http://svnweb.freebsd.org/changeset/base/245248

Log:
  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

Modified:
  head/sys/dev/usb/input/ukbd.c
  head/sys/dev/usb/input/ums.c
  head/sys/dev/usb/usb_hid.c
  head/sys/dev/usb/usbhid.h

Modified: head/sys/dev/usb/input/ukbd.c
==============================================================================
--- head/sys/dev/usb/input/ukbd.c       Thu Jan 10 05:36:42 2013        
(r245247)
+++ head/sys/dev/usb/input/ukbd.c       Thu Jan 10 07:45:46 2013        
(r245248)
@@ -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);
 }

Modified: head/sys/dev/usb/input/ums.c
==============================================================================
--- head/sys/dev/usb/input/ums.c        Thu Jan 10 05:36:42 2013        
(r245247)
+++ head/sys/dev/usb/input/ums.c        Thu Jan 10 07:45:46 2013        
(r245248)
@@ -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

Modified: head/sys/dev/usb/usb_hid.c
==============================================================================
--- head/sys/dev/usb/usb_hid.c  Thu Jan 10 05:36:42 2013        (r245247)
+++ head/sys/dev/usb/usb_hid.c  Thu Jan 10 07:45:46 2013        (r245248)
@@ -845,3 +845,79 @@ usbd_req_get_hid_desc(struct usb_device 
        }
        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);
+}

Modified: head/sys/dev/usb/usbhid.h
==============================================================================
--- head/sys/dev/usb/usbhid.h   Thu Jan 10 05:36:42 2013        (r245247)
+++ head/sys/dev/usb/usbhid.h   Thu Jan 10 07:45:46 2013        (r245248)
@@ -242,5 +242,7 @@ struct usb_hid_descriptor *hid_get_descr
 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_ */
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to