Port-i386 archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: Microsoft Wireless Laser Mouse 6000 v2.0 vs. NetBSD



On Wed, Apr 01, 2009 at 09:38:14AM -0400, Rafal Boni wrote:
> Folks:
>       I picked up one of the above rodents cheap, and while it works fine
>       on my XP laptop and on my desktop when booted to Vista, I can't get
>       it to work under NetBSD... it attaches fine, but no data appears on
>       the /dev/wsmouseN device associated with it.
> 
>       Here's what the kernel messages for the attachment look like:
> uhidev0: Microsoft Microsoft\xc2\xae 2.4GHz Transceiver V2.0, rev 2.00/2.70, 
> addr 2, iclass 3/1
> uhidev0: 23 report ids
> ums0 at uhidev0 reportid 17: 5 buttons and Z dir.
> wsmouse1 at ums0 mux 0
> uhid0 at uhidev0 reportid 18: input=0, output=0, feature=1
> uhid1 at uhidev0 reportid 19: input=1, output=0, feature=0
> uhid2 at uhidev0 reportid 20: input=1, output=0, feature=0
> uhid3 at uhidev0 reportid 21: input=3, output=0, feature=0
> uhid4 at uhidev0 reportid 23: input=0, output=0, feature=1
> 
>       Attempting to read data from the device shows nothing, but there
>       are no errors of any kind reported either.  I have not debugged
>       further, but thought I'd at least send a note here in case anyone
>       has fallen afoul of this device and figured out what the problem
>       is.

It looks like this mouse has several issues with our USB stack:

        * We either mis-calculate the report size of the report descriptor
          used by the mouse to signal events, or the report size is mis-
          reported by the device,
        * I think as a result of the above, we allocate the interrupt pipe
          with a too small packet size, causing every report to be dropped
          due to the device stalling (presumably because it doesn't have
          enough room to write it's packet).

It also looks like it has it's own issues, where it reports various HID
items incorrectly (though again, this could be the fault of the NetBSD
USB code):
        * The position of the (wheel) update in the interrupt packet is
          reported incorrectly, causing it to overlap with the buttons,
          so scrolling doesn't work and I get occasional scroll artifacts
          when pressing the other buttons.
        * The wheel has a 'tilt' axis, but this is reported as an unusual
          HID type (Consumer:AC Pan), so it isn't used.

Attached is a patch that makes my mouse works, though I'm not 100% sure
if the handling of the report isize / interrupt pipe packet size is the
right way to solve that problem (if it got the report isize correct, the
rest would simply fall out, but that's harder to make a quirk for).  

I'll PR this when I get a chance and/or think about the report isize bit
a bit more...

Enjoy, and let me know if you have comments on the code,
--rafal

-- 
  Time is an illusion; lunchtime, doubly so.     |/\/\|           Rafal Boni
                   -- Ford Prefect               |\/\/|      
rafal%pobox.com@localhost
diff --git a/sys/dev/usb/uhidev.c b/sys/dev/usb/uhidev.c
index aa0b005..789313d 100644
--- a/sys/dev/usb/uhidev.c
+++ b/sys/dev/usb/uhidev.c
@@ -105,7 +105,7 @@ USB_ATTACH(uhidev)
        struct uhidev_attach_arg uha;
        device_t dev;
        struct uhidev *csc;
-       int size, nrepid, repid, repsz;
+       int maxinpktsize, size, nrepid, repid, repsz;
        int *repsizes;
        int i;
        void *desc;
@@ -137,6 +137,7 @@ USB_ATTACH(uhidev)
                (void)usbd_set_protocol(iface, 1);
 #endif
 
+       maxinpktsize = 0;
        sc->sc_iep_addr = sc->sc_oep_addr = -1;
        for (i = 0; i < id->bNumEndpoints; i++) {
                ed = usbd_interface2endpoint_descriptor(iface, i);
@@ -158,6 +159,7 @@ USB_ATTACH(uhidev)
 
                if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
                    (ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT) {
+                       maxinpktsize = UGETW(ed->wMaxPacketSize);
                        sc->sc_iep_addr = ed->bEndpointAddress;
                } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
                    (ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT) {
@@ -278,6 +280,19 @@ nomem:
                }
        }
        sc->sc_isize += nrepid != 1;    /* space for report ID */
+
+       /*
+        * Microsoft's wireless transceiver (sold to go with their
+        * wireless laser mice) needs to be able to send max-sized
+        * packets, since either the HID descriptors are incorrect
+        * or we don't know how to deal with them correctly and
+        * we calculate a too-small size.
+        */
+       if (uaa->vendor == USB_VENDOR_MICROSOFT && 
+           uaa->product == USB_PRODUCT_MICROSOFT_24GHZ_XCVR) {
+               sc->sc_isize = maxinpktsize;
+       }
+
        DPRINTF(("uhidev_attach: isize=%d\n", sc->sc_isize));
 
        uha.parent = sc;
@@ -475,7 +490,7 @@ uhidev_intr(usbd_xfer_handle xfer, usbd_private_handle 
addr, usbd_status status)
                    rep, scd, scd ? scd->sc_state : 0));
        if (!(scd->sc_state & UHIDEV_OPEN))
                return;
-       if (scd->sc_in_rep_size != cc) {
+       if (scd->sc_in_rep_size > cc) {
                printf("%s: bad input length %d != %d\n",
                       USBDEVNAME(sc->sc_dev), scd->sc_in_rep_size, cc);
                return;
diff --git a/sys/dev/usb/ums.c b/sys/dev/usb/ums.c
index 88baea2..5a65f57 100644
--- a/sys/dev/usb/ums.c
+++ b/sys/dev/usb/ums.c
@@ -63,6 +63,8 @@ __KERNEL_RCSID(0, "$NetBSD: ums.c,v 1.73 2008/05/24 16:40:58 
cube Exp $");
 #include <dev/wscons/wsconsio.h>
 #include <dev/wscons/wsmousevar.h>
 
+#define USB_DEBUG
+
 #ifdef USB_DEBUG
 #define DPRINTF(x)     if (umsdebug) logprintf x
 #define DPRINTFN(n,x)  if (umsdebug>(n)) logprintf x
@@ -86,7 +88,7 @@ int   umsdebug = 0;
 struct ums_softc {
        struct uhidev sc_hdev;
 
-       struct hid_location sc_loc_x, sc_loc_y, sc_loc_z, sc_loc_w;
+       struct hid_location sc_loc_x, sc_loc_y, sc_loc_z, sc_loc_t;
        struct hid_location sc_loc_btn[MAX_BUTTONS];
 
        int sc_enabled;
@@ -95,6 +97,7 @@ struct ums_softc {
 #define UMS_Z          0x01    /* z direction available */
 #define UMS_SPUR_BUT_UP        0x02    /* spurious button up events */
 #define UMS_REVZ       0x04    /* Z-axis is reversed */
+#define UMS_T          0x08    /* Tilt axis available */
 
        int nbuttons;
 
@@ -214,16 +217,18 @@ ums_attach(device_t parent, device_t self, void *aux)
                }
                /*
                 * We might have both a wheel and Z direction, if so put
-                * put the Z on the W coordinate.
+                * put the Z on the T coordinate.
                 */
                if (hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP,
                                                      HUG_Z),
-                       uha->reportid, hid_input, &sc->sc_loc_w, &flags)) {
+                          uha->reportid, hid_input, &sc->sc_loc_t, &flags)) {
                        if ((flags & MOUSE_FLAGS_MASK) != MOUSE_FLAGS) {
                                aprint_verbose("\n%s: Z report 0x%04x not "
                                    "supported\n",
                                       USBDEVNAME(sc->sc_hdev.sc_dev), flags);
-                               sc->sc_loc_w.size = 0;  /* Bad Z, ignore */
+                               sc->sc_loc_t.size = 0;  /* Bad Z, ignore */
+                       } else {
+                               sc->flags |= UMS_T;
                        }
                }
         } else if (hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP,
@@ -238,6 +243,27 @@ ums_attach(device_t parent, device_t self, void *aux)
                }
        }
 
+       /*
+        * The Microsoft Wireless Laser Mouse 6000 v2.0 reports a bad
+        * position for the wheel (loc 0 vs. loc 24) and reports the
+        * wheel tilt feature as Consumer:AC Pan (also at a bad loc 0,
+        * vs. loc 32).  Fix all that up here.
+        */
+       if (hid_locate(desc, size, HID_USAGE2(HUP_CONSUMER, HUC_AC_PAN),
+                     uha->reportid, hid_input, &sc->sc_loc_t, &flags)) {
+               if ((flags & MOUSE_FLAGS_MASK) == MOUSE_FLAGS) {
+                       if (sc->sc_loc_z.pos == 0)
+                               sc->sc_loc_z.pos = 24;
+                       if (sc->sc_loc_t.pos == 0)
+                               sc->sc_loc_t.pos = sc->sc_loc_z.pos + 8;
+
+                       sc->flags |= UMS_Z | UMS_T;
+               } else {
+                       aprint_verbose("\n%s: AC_Pan report 0x%04x not 
supported\n",
+                              USBDEVNAME(sc->sc_hdev.sc_dev), flags);
+                       sc->sc_loc_t.size = 0;  /* Bad tilt coord, ignore it */
+               }
+       }
 
        /* figure out the number of buttons */
        for (i = 1; i <= MAX_BUTTONS; i++)
@@ -246,9 +272,10 @@ ums_attach(device_t parent, device_t self, void *aux)
                        break;
        sc->nbuttons = i - 1;
 
-       aprint_normal(": %d button%s%s\n",
+       aprint_normal(": %d button%s%s%s\n",
            sc->nbuttons, sc->nbuttons == 1 ? "" : "s",
-           sc->flags & UMS_Z ? " and Z dir." : "");
+           sc->flags & UMS_T ? " with tilt" : "",
+           sc->flags & UMS_Z ? " and Z dir." : ".");
 
        for (i = 1; i <= sc->nbuttons; i++)
                hid_locate(desc, size, HID_USAGE2(HUP_BUTTON, i),
@@ -264,6 +291,9 @@ ums_attach(device_t parent, device_t self, void *aux)
        if (sc->flags & UMS_Z)
                DPRINTF(("ums_attach: Z\t%d/%d\n",
                         sc->sc_loc_z.pos, sc->sc_loc_z.size));
+       if (sc->flags & UMS_T)
+               DPRINTF(("ums_attach: T\t%d/%d\n",
+                        sc->sc_loc_t.pos, sc->sc_loc_t.size));
        for (i = 1; i <= sc->nbuttons; i++) {
                DPRINTF(("ums_attach: B%d\t%d/%d\n",
                         i, sc->sc_loc_btn[i-1].pos,sc->sc_loc_btn[i-1].size));
@@ -327,7 +357,7 @@ void
 ums_intr(struct uhidev *addr, void *ibuf, u_int len)
 {
        struct ums_softc *sc = (struct ums_softc *)addr;
-       int dx, dy, dz, dw;
+       int dx, dy, dz, dt;
        u_int32_t buttons = 0;
        int i;
        int s;
@@ -337,23 +367,23 @@ ums_intr(struct uhidev *addr, void *ibuf, u_int len)
        dx =  hid_get_data(ibuf, &sc->sc_loc_x);
        dy = -hid_get_data(ibuf, &sc->sc_loc_y);
        dz =  hid_get_data(ibuf, &sc->sc_loc_z);
-       dw =  hid_get_data(ibuf, &sc->sc_loc_w);
+       dt =  hid_get_data(ibuf, &sc->sc_loc_t);
        if (sc->flags & UMS_REVZ)
                dz = -dz;
        for (i = 0; i < sc->nbuttons; i++)
                if (hid_get_data(ibuf, &sc->sc_loc_btn[i]))
                        buttons |= (1 << UMS_BUT(i));
 
-       if (dx != 0 || dy != 0 || dz != 0 || dw != 0 ||
+       if (dx != 0 || dy != 0 || dz != 0 || dt != 0 ||
            buttons != sc->sc_buttons) {
                DPRINTFN(10, ("ums_intr: x:%d y:%d z:%d w:%d buttons:0x%x\n",
-                       dx, dy, dz, dw, buttons));
+                       dx, dy, dz, dt, buttons));
                sc->sc_buttons = buttons;
                if (sc->sc_wsmousedev != NULL) {
                        s = spltty();
                        wsmouse_input(sc->sc_wsmousedev,
                                        buttons,
-                                       dx, dy, dz, dw,
+                                       dx, dy, dz, dt,
                                        WSMOUSE_INPUT_DELTA);
                        splx(s);
                }
diff --git a/sys/dev/usb/usbdevs b/sys/dev/usb/usbdevs
index e2b00bf..2c13c33 100644
--- a/sys/dev/usb/usbdevs
+++ b/sys/dev/usb/usbdevs
@@ -1542,6 +1542,7 @@ product MICROSOFT XBOX_DVD_PLAYBACK       0x0284  Xbox 
DVD Movie Playback Kit
 product MICROSOFT XBOX_CONTROLLER_S10  0x0285  Xbox Controller S (1.0)
 product MICROSOFT XBOX_CONTROLLER_HUB  0x0288  Xbox Controller Hub
 product MICROSOFT XBOX_CONTROLLER_S12  0x0289  Xbox Controller S (1.2)
+product MICROSOFT 24GHZ_XCVR           0x071f  2.4GHz Transceiver V2.0
 
 /* Microtech products */
 product MICROTECH SCSIDB25     0x0004  USB-SCSI-DB25
diff --git a/sys/dev/usb/usbdevs.h b/sys/dev/usb/usbdevs.h
index 53372ec..6da5460 100644
--- a/sys/dev/usb/usbdevs.h
+++ b/sys/dev/usb/usbdevs.h
@@ -1,4 +1,4 @@
-/*     $NetBSD: usbdevs.h,v 1.515.4.1 2008/11/22 05:12:18 snj Exp $    */
+/*     $NetBSD$        */
 
 /*
  * THIS FILE IS AUTOMATICALLY GENERATED.  DO NOT EDIT.
@@ -1549,6 +1549,7 @@
 #define        USB_PRODUCT_MICROSOFT_XBOX_CONTROLLER_S10       0x0285          
/* Xbox Controller S (1.0) */
 #define        USB_PRODUCT_MICROSOFT_XBOX_CONTROLLER_HUB       0x0288          
/* Xbox Controller Hub */
 #define        USB_PRODUCT_MICROSOFT_XBOX_CONTROLLER_S12       0x0289          
/* Xbox Controller S (1.2) */
+#define        USB_PRODUCT_MICROSOFT_24GHZ_XCVR        0x071f          /* 
2.4GHz Transceiver V2.0 */
 
 /* Microtech products */
 #define        USB_PRODUCT_MICROTECH_SCSIDB25  0x0004          /* 
USB-SCSI-DB25 */
diff --git a/sys/dev/usb/usbdevs_data.h b/sys/dev/usb/usbdevs_data.h
index 6759cdf..bb2b02b 100644
--- a/sys/dev/usb/usbdevs_data.h
+++ b/sys/dev/usb/usbdevs_data.h
@@ -1,4 +1,4 @@
-/*     $NetBSD: usbdevs_data.h,v 1.516.4.1 2008/11/22 05:12:18 snj Exp $       
*/
+/*     $NetBSD$        */
 
 /*
  * THIS FILE IS AUTOMATICALLY GENERATED.  DO NOT EDIT.
@@ -4579,6 +4579,10 @@ const struct usb_product usb_products[] = {
            "Xbox Controller S (1.2)",
        },
        {
+           USB_VENDOR_MICROSOFT, USB_PRODUCT_MICROSOFT_24GHZ_XCVR,
+           "2.4GHz Transceiver V2.0",
+       },
+       {
            USB_VENDOR_MICROTECH, USB_PRODUCT_MICROTECH_SCSIDB25,
            "USB-SCSI-DB25",
        },
@@ -6823,4 +6827,4 @@ const struct usb_product usb_products[] = {
            "Prestige",
        },
 };
-const int usb_nproducts = 1241;
+const int usb_nproducts = 1242;


Home | Main Index | Thread Index | Old Index