summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiod Vallat <miod@cvs.openbsd.org>2008-05-08 13:57:44 +0000
committerMiod Vallat <miod@cvs.openbsd.org>2008-05-08 13:57:44 +0000
commitac949b5349a213e8d63562f5b3d3a95ad3b97f65 (patch)
tree836853190baf8edf6db8804369427bede2290556
parentcc17ce1e5648f199a7199e1b5620dd1ad7957013 (diff)
Add support for Microsoft Wireless Intellimouse, from FreeBSD. Not only does
this device bends the uhid specs backwards, it is also completely unusable for left-handed people due to its shape. Tested on actual hardware thanks to a donation from Maxim Belooussov.
-rw-r--r--sys/dev/usb/ums.c118
-rw-r--r--sys/dev/usb/usb_quirks.c10
-rw-r--r--sys/dev/usb/usb_quirks.h51
-rw-r--r--sys/dev/usb/usbhid.h3
4 files changed, 150 insertions, 32 deletions
diff --git a/sys/dev/usb/ums.c b/sys/dev/usb/ums.c
index 8bcf2edbe3a..84af4877961 100644
--- a/sys/dev/usb/ums.c
+++ b/sys/dev/usb/ums.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ums.c,v 1.26 2007/09/17 01:40:38 fgsch Exp $ */
+/* $OpenBSD: ums.c,v 1.27 2008/05/08 13:57:43 miod Exp $ */
/* $NetBSD: ums.c,v 1.60 2003/03/11 16:44:00 augustss Exp $ */
/*
@@ -80,11 +80,6 @@ int umsdebug = 0;
#define UMSUNIT(s) (minor(s))
-#define PS2LBUTMASK x01
-#define PS2RBUTMASK x02
-#define PS2MBUTMASK x04
-#define PS2BUTMASK 0x0f
-
#define MAX_BUTTONS 16 /* must not exceed size of sc_buttons */
struct ums_softc {
@@ -99,6 +94,9 @@ 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_W 0x08 /* w direction available */
+#define UMS_REVW 0x10 /* W-axis is reversed */
+#define UMS_LEADINGBYTE 0x20 /* Unknown leading byte */
int nbuttons;
@@ -166,7 +164,7 @@ ums_attach(struct device *parent, struct device *self, void *aux)
int size;
void *desc;
u_int32_t flags, quirks;
- int i;
+ int i, wheel, twheel;
struct hid_location loc_btn;
sc->sc_hdev.sc_intr = ums_intr;
@@ -178,6 +176,8 @@ ums_attach(struct device *parent, struct device *self, void *aux)
sc->flags |= UMS_REVZ;
if (quirks & UQ_SPUR_BUT_UP)
sc->flags |= UMS_SPUR_BUT_UP;
+ if (quirks & UQ_MS_LEADING_BYTE)
+ sc->flags |= UMS_LEADINGBYTE;
uhidev_get_report_desc(uha->parent, &desc, &size);
@@ -205,9 +205,22 @@ ums_attach(struct device *parent, struct device *self, void *aux)
return;
}
- /* Try the wheel as Z activator first */
- if (hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_WHEEL),
- uha->reportid, hid_input, &sc->sc_loc_z, &flags)) {
+ /*
+ * Try to guess the Z activator: check WHEEL, TWHEEL, and Z,
+ * in that order.
+ */
+
+ wheel = hid_locate(desc, size,
+ HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_WHEEL),
+ uha->reportid, hid_input, &sc->sc_loc_z, &flags);
+ if (wheel == 0)
+ twheel = hid_locate(desc, size,
+ HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_TWHEEL),
+ uha->reportid, hid_input, &sc->sc_loc_z, &flags);
+ else
+ twheel = 0;
+
+ if (wheel || twheel) {
if ((flags & MOUSE_FLAGS_MASK) != MOUSE_FLAGS) {
DPRINTF(("\n%s: Wheel report 0x%04x not supported\n",
sc->sc_hdev.sc_dev.dv_xname, flags));
@@ -230,6 +243,8 @@ ums_attach(struct device *parent, struct device *self, void *aux)
/* Bad Z coord, ignore it */
sc->sc_loc_w.size = 0;
}
+ else
+ sc->flags |= UMS_W;
}
} else if (hid_locate(desc, size,
HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Z),
@@ -243,6 +258,21 @@ ums_attach(struct device *parent, struct device *self, void *aux)
}
}
+ /*
+ * The Microsoft Wireless Intellimouse 2.0 reports its wheel
+ * using 0x0048 (I've called it HUG_TWHEEL) and seems to expect
+ * us to know that the byte after the wheel is the tilt axis.
+ * There are no other HID axis descriptors other than X, Y and
+ * TWHEEL, so we report TWHEEL on the W axis.
+ */
+ if (twheel) {
+ sc->sc_loc_w = sc->sc_loc_z;
+ sc->sc_loc_w.pos = sc->sc_loc_w.pos + 8;
+ sc->flags |= UMS_W | UMS_LEADINGBYTE;
+ /* Wheels need their axis reversed. */
+ sc->flags ^= UMS_REVW;
+ }
+
/* figure out the number of buttons */
for (i = 1; i <= MAX_BUTTONS; i++)
if (!hid_locate(desc, size, HID_USAGE2(HUP_BUTTON, i),
@@ -250,9 +280,40 @@ ums_attach(struct device *parent, struct device *self, void *aux)
break;
sc->nbuttons = i - 1;
- printf(": %d button%s%s\n",
- sc->nbuttons, sc->nbuttons == 1 ? "" : "s",
- sc->flags & UMS_Z ? " and Z dir." : "");
+ /*
+ * The Microsoft Wireless Notebook Optical Mouse seems to be in worse
+ * shape than the Wireless Intellimouse 2.0, as its X, Y, wheel, and
+ * all of its other button positions are all off. It also reports that
+ * it has two addional buttons and a tilt wheel.
+ */
+ if (quirks & UQ_MS_BAD_CLASS) {
+ /* UMS_LEADINGBYTE cleared on purpose */
+ sc->flags = UMS_Z | UMS_SPUR_BUT_UP;
+ sc->nbuttons = 3;
+ /* XXX change sc_hdev isize to 5? */
+ /* 1st byte of descriptor report contains garbage */
+ sc->sc_loc_x.pos = 16;
+ sc->sc_loc_y.pos = 24;
+ sc->sc_loc_z.pos = 32;
+ sc->sc_loc_btn[0].pos = 8;
+ sc->sc_loc_btn[1].pos = 9;
+ sc->sc_loc_btn[2].pos = 10;
+ }
+
+ printf(": %d button%s",
+ sc->nbuttons, sc->nbuttons <= 1 ? "" : "s");
+ switch (sc->flags & (UMS_Z | UMS_W)) {
+ case UMS_Z:
+ printf(", Z dir");
+ break;
+ case UMS_W:
+ printf(", W dir");
+ break;
+ case UMS_Z | UMS_W:
+ printf(", Z and W dir");
+ break;
+ }
+ printf("\n");
for (i = 1; i <= sc->nbuttons; i++)
hid_locate(desc, size, HID_USAGE2(HUP_BUTTON, i),
@@ -268,6 +329,9 @@ ums_attach(struct device *parent, struct device *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_W)
+ DPRINTF(("ums_attach: W\t%d/%d\n",
+ sc->sc_loc_w.pos, sc->sc_loc_w.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));
@@ -315,9 +379,10 @@ ums_detach(struct device *self, int flags)
}
void
-ums_intr(struct uhidev *addr, void *ibuf, u_int len)
+ums_intr(struct uhidev *addr, void *buf, u_int len)
{
struct ums_softc *sc = (struct ums_softc *)addr;
+ u_char *ibuf = (u_char *)buf;
int dx, dy, dz, dw;
u_int32_t buttons = 0;
int i;
@@ -325,12 +390,37 @@ ums_intr(struct uhidev *addr, void *ibuf, u_int len)
DPRINTFN(5,("ums_intr: len=%d\n", len));
+ /*
+ * The Microsoft Wireless Intellimouse 2.0 sends one extra leading
+ * byte of data compared to most USB mice. This byte frequently
+ * switches from 0x01 (usual state) to 0x02. It may be used to
+ * report non-standard events (such as battery life). However,
+ * at the same time, it generates a left click event on the
+ * button byte, where there shouldn't be any. We simply discard
+ * the packet in this case.
+ *
+ * This problem affects the MS Wireless Notebook Optical Mouse, too.
+ * However, the leading byte for this mouse is normally 0x11, and
+ * the phantom mouse click occurs when it's 0x14.
+ */
+ if (sc->flags & UMS_LEADINGBYTE) {
+ if (*ibuf++ == 0x02)
+ return;
+ /* else
+ len--; */
+ } else if (sc->flags & UMS_SPUR_BUT_UP) {
+ if (*ibuf == 0x14 || *ibuf == 0x15)
+ return;
+ }
+
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);
if (sc->flags & UMS_REVZ)
dz = -dz;
+ if (sc->flags & UMS_REVW)
+ dw = -dw;
for (i = 0; i < sc->nbuttons; i++)
if (hid_get_data(ibuf, &sc->sc_loc_btn[i]))
buttons |= (1 << UMS_BUT(i));
diff --git a/sys/dev/usb/usb_quirks.c b/sys/dev/usb/usb_quirks.c
index ec6122a7399..eb7729a1150 100644
--- a/sys/dev/usb/usb_quirks.c
+++ b/sys/dev/usb/usb_quirks.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: usb_quirks.c,v 1.35 2008/05/06 05:59:49 deraadt Exp $ */
+/* $OpenBSD: usb_quirks.c,v 1.36 2008/05/08 13:57:43 miod Exp $ */
/* $NetBSD: usb_quirks.c,v 1.45 2003/05/10 17:47:14 hamajima Exp $ */
/* $FreeBSD: src/sys/dev/usb/usb_quirks.c,v 1.30 2003/01/02 04:15:55 imp Exp $ */
@@ -144,6 +144,14 @@ const struct usbd_quirk_entry {
{ USB_VENDOR_MGE, USB_PRODUCT_MGE_UPS1, ANY, { UQ_BAD_HID }},
{ USB_VENDOR_MGE, USB_PRODUCT_MGE_UPS2, ANY, { UQ_BAD_HID }},
+ /* MS keyboards do weird things */
+ { USB_VENDOR_MICROSOFT, USB_PRODUCT_MICROSOFT_WLNOTEBOOK,
+ ANY, { UQ_MS_BAD_CLASS | UQ_MS_LEADING_BYTE }},
+ { USB_VENDOR_MICROSOFT, USB_PRODUCT_MICROSOFT_WLNOTEBOOK2,
+ ANY, { UQ_MS_BAD_CLASS | UQ_MS_LEADING_BYTE }},
+ { USB_VENDOR_MICROSOFT, USB_PRODUCT_MICROSOFT_WLINTELLIMOUSE,
+ ANY, { UQ_MS_LEADING_BYTE }},
+
/* SISPM devices */
{ USB_VENDOR_CYPRESS, USB_PRODUCT_CYPRESS_SISPM_OLD, ANY, { UQ_BAD_HID }},
{ USB_VENDOR_CYPRESS, USB_PRODUCT_CYPRESS_SISPM, ANY, { UQ_BAD_HID }},
diff --git a/sys/dev/usb/usb_quirks.h b/sys/dev/usb/usb_quirks.h
index 1abeb9f691c..2a3213efdd9 100644
--- a/sys/dev/usb/usb_quirks.h
+++ b/sys/dev/usb/usb_quirks.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: usb_quirks.h,v 1.10 2006/05/14 12:00:04 matthieu Exp $ */
+/* $OpenBSD: usb_quirks.h,v 1.11 2008/05/08 13:57:43 miod Exp $ */
/* $NetBSD: usb_quirks.h,v 1.20 2001/04/15 09:38:01 augustss Exp $ */
/* $FreeBSD: src/sys/dev/usb/usb_quirks.h,v 1.9 1999/11/12 23:31:03 n_hibma Exp $ */
@@ -41,21 +41,40 @@
struct usbd_quirks {
u_int32_t uq_flags; /* Device problems: */
-#define UQ_NO_SET_PROTO 0x0001 /* cannot handle SET PROTOCOL. */
-#define UQ_SWAP_UNICODE 0x0002 /* has some Unicode strings swapped. */
-#define UQ_MS_REVZ 0x0004 /* mouse has Z-axis reversed */
-#define UQ_NO_STRINGS 0x0008 /* string descriptors are broken. */
-#define UQ_BAD_ADC 0x0010 /* bad audio spec version number. */
-#define UQ_BUS_POWERED 0x0020 /* device is bus powered, despite claim */
-#define UQ_BAD_AUDIO 0x0040 /* device claims audio class, but isn't */
-#define UQ_SPUR_BUT_UP 0x0080 /* spurious mouse button up events */
-#define UQ_AU_NO_XU 0x0100 /* audio device has broken extension unit */
-#define UQ_POWER_CLAIM 0x0200 /* hub lies about power status */
-#define UQ_AU_NO_FRAC 0x0400 /* don't adjust for fractional samples */
-#define UQ_AU_INP_ASYNC 0x0800 /* input is async despite claim of adaptive */
-#define UQ_ASSUME_CM_OVER_DATA 0x1000 /* modem device breaks on cm over data */
-#define UQ_BROKEN_BIDIR 0x2000 /* printer has broken bidir mode */
-#define UQ_BAD_HID 0x4000 /* device claims uhid, but isn't */
+ /* cannot handle SET PROTOCOL. */
+#define UQ_NO_SET_PROTO 0x00000001
+ /* has some Unicode strings swapped. */
+#define UQ_SWAP_UNICODE 0x00000002
+ /* mouse has Z-axis reversed */
+#define UQ_MS_REVZ 0x00000004
+ /* string descriptors are broken. */
+#define UQ_NO_STRINGS 0x00000008
+ /* bad audio spec version number. */
+#define UQ_BAD_ADC 0x00000010
+ /* device is bus powered, despite claim */
+#define UQ_BUS_POWERED 0x00000020
+ /* device claims audio class, but isn't */
+#define UQ_BAD_AUDIO 0x00000040
+ /* spurious mouse button up events */
+#define UQ_SPUR_BUT_UP 0x00000080
+ /* audio device has broken extension unit */
+#define UQ_AU_NO_XU 0x00000100
+ /* hub lies about power status */
+#define UQ_POWER_CLAIM 0x00000200
+ /* don't adjust for fractional samples */
+#define UQ_AU_NO_FRAC 0x00000400
+ /* input is async despite claim of adaptive */
+#define UQ_AU_INP_ASYNC 0x00000800
+ /* modem device breaks on cm over data */
+#define UQ_ASSUME_CM_OVER_DATA 0x00001000
+ /* printer has broken bidir mode */
+#define UQ_BROKEN_BIDIR 0x00002000
+ /* device claims uhid, but isn't */
+#define UQ_BAD_HID 0x00004000
+ /* doesn't identify properly */
+#define UQ_MS_BAD_CLASS 0x00008000
+ /* mouse sends an unknown leading byte. */
+#define UQ_MS_LEADING_BYTE 0x00010000
};
extern const struct usbd_quirks usbd_no_quirk;
diff --git a/sys/dev/usb/usbhid.h b/sys/dev/usb/usbhid.h
index dad6a50b29b..386dfca10a9 100644
--- a/sys/dev/usb/usbhid.h
+++ b/sys/dev/usb/usbhid.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: usbhid.h,v 1.10 2007/09/01 17:06:26 xsa Exp $ */
+/* $OpenBSD: usbhid.h,v 1.11 2008/05/08 13:57:43 miod Exp $ */
/* $NetBSD: usbhid.h,v 1.11 2001/12/28 00:20:24 augustss Exp $ */
/* $FreeBSD: src/sys/dev/usb/usbhid.h,v 1.7 1999/11/17 22:33:51 n_hibma Exp $ */
@@ -124,6 +124,7 @@ typedef struct usb_hid_descriptor {
#define HUG_VBRY 0x0044
#define HUG_VBRZ 0x0045
#define HUG_VNO 0x0046
+#define HUG_TWHEEL 0x0048
#define HUG_SYSTEM_CONTROL 0x0080
#define HUG_SYSTEM_POWER_DOWN 0x0081
#define HUG_SYSTEM_SLEEP 0x0082