summaryrefslogtreecommitdiffstats
path: root/sys/dev/usb
diff options
context:
space:
mode:
authorjulian <julian@FreeBSD.org>2004-12-12 05:34:20 +0000
committerjulian <julian@FreeBSD.org>2004-12-12 05:34:20 +0000
commitb8473b1c5d50db71ae6a97b93cc838b59a7c93b0 (patch)
tree7ea56d4ceeb8ddb387dac95a5477bcf6e2bd5d4e /sys/dev/usb
parentdc4ceb7b98dfd15a2cfe0e1853513eab05a79eee (diff)
downloadFreeBSD-src-b8473b1c5d50db71ae6a97b93cc838b59a7c93b0.zip
FreeBSD-src-b8473b1c5d50db71ae6a97b93cc838b59a7c93b0.tar.gz
Add support for USB Microsoft Intellimouse
PR: kern/70607 Submitted by: Matt Wright <matt@consultmatt.co.uk> MFC after: 1 week
Diffstat (limited to 'sys/dev/usb')
-rw-r--r--sys/dev/usb/ums.c71
-rw-r--r--sys/dev/usb/usbhid.h1
2 files changed, 51 insertions, 21 deletions
diff --git a/sys/dev/usb/ums.c b/sys/dev/usb/ums.c
index ff9ab5a..75b8c7c 100644
--- a/sys/dev/usb/ums.c
+++ b/sys/dev/usb/ums.c
@@ -104,7 +104,7 @@ struct ums_softc {
u_char *sc_ibuf;
u_int8_t sc_iid;
int sc_isize;
- struct hid_location sc_loc_x, sc_loc_y, sc_loc_z;
+ struct hid_location sc_loc_x, sc_loc_y, sc_loc_z, sc_loc_t;
struct hid_location *sc_loc_btn;
usb_callout_t callout_handle; /* for spurious button ups */
@@ -114,6 +114,7 @@ struct ums_softc {
int flags; /* device configuration */
#define UMS_Z 0x01 /* z direction available */
+#define UMS_T 0x02 /* aa direction available (tilt) */
#define UMS_SPUR_BUT_UP 0x02 /* spurious button up events */
int nbuttons;
#define MAX_BUTTONS 7 /* chosen because sc_buttons is u_char */
@@ -140,7 +141,7 @@ Static void ums_intr(usbd_xfer_handle xfer,
usbd_private_handle priv, usbd_status status);
Static void ums_add_to_queue(struct ums_softc *sc,
- int dx, int dy, int dz, int buttons);
+ int dx, int dy, int dz, int dt, int buttons);
Static void ums_add_to_queue_timeout(void *priv);
Static int ums_enable(void *);
@@ -269,6 +270,8 @@ USB_ATTACH(ums)
if (hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Z),
hid_input, &sc->sc_loc_z, &flags) ||
hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_WHEEL),
+ hid_input, &sc->sc_loc_z, &flags) ||
+ hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_TWHEEL),
hid_input, &sc->sc_loc_z, &flags)) {
if ((flags & MOUSE_FLAGS_MASK) != MOUSE_FLAGS) {
sc->sc_loc_z.size = 0; /* Bad Z coord, ignore it */
@@ -277,6 +280,17 @@ USB_ATTACH(ums)
}
}
+ /* The Microsoft Wireless Intellimouse 2.0 reports it's wheel
+ * using 0x0048 (i've called it HUG_TWHEEL) and seems to expect
+ * you 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 */
+ if (hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_TWHEEL),
+ hid_input, &sc->sc_loc_t, &flags)) {
+ sc->sc_loc_t.pos = sc->sc_loc_t.pos + 8;
+ sc->flags |= UMS_T;
+ }
+
/* figure out the number of buttons */
for (i = 1; i <= MAX_BUTTONS; i++)
if (!hid_locate(desc, size, HID_USAGE2(HUP_BUTTON, i),
@@ -290,8 +304,9 @@ USB_ATTACH(ums)
USB_ATTACH_ERROR_RETURN;
}
- printf("%s: %d buttons%s\n", USBDEVNAME(sc->sc_dev),
- sc->nbuttons, sc->flags & UMS_Z? " and Z dir." : "");
+ printf("%s: %d buttons%s%s.\n", USBDEVNAME(sc->sc_dev),
+ sc->nbuttons, sc->flags & UMS_Z? " and Z dir" : "",
+ sc->flags & UMS_T?" and a TILT dir": "");
for (i = 1; i <= sc->nbuttons; i++)
hid_locate(desc, size, HID_USAGE2(HUP_BUTTON, i),
@@ -408,15 +423,15 @@ ums_intr(xfer, addr, status)
{
struct ums_softc *sc = addr;
u_char *ibuf;
- int dx, dy, dz;
+ int dx, dy, dz, dt;
u_char buttons = 0;
int i;
#define UMS_BUT(i) ((i) < 3 ? (((i) + 2) % 3) : (i))
DPRINTFN(5, ("ums_intr: sc=%p status=%d\n", sc, status));
- DPRINTFN(5, ("ums_intr: data = %02x %02x %02x\n",
- sc->sc_ibuf[0], sc->sc_ibuf[1], sc->sc_ibuf[2]));
+ DPRINTFN(5, ("ums_intr: data = %02x %02x %02x %02x %02x %02x\n",
+ sc->sc_ibuf[0], sc->sc_ibuf[1], sc->sc_ibuf[2], sc->sc_ibuf[3], sc->sc_ibuf[4], sc->sc_ibuf[5]));
if (status == USBD_CANCELLED)
return;
@@ -425,32 +440,44 @@ ums_intr(xfer, addr, status)
DPRINTF(("ums_intr: status=%d\n", status));
if (status == USBD_STALLED)
usbd_clear_endpoint_stall_async(sc->sc_intrpipe);
- return;
+ if(status != USBD_IOERROR)
+ return;
}
ibuf = sc->sc_ibuf;
if (sc->sc_iid) {
- if (*ibuf++ != sc->sc_iid)
- return;
+ ibuf++;
}
+ /* The M$ Wireless Intellimouse 2.0 sends 1 extra leading byte of
+ * data compared to most USB mice. This byte frequently switches
+ * from 0x01 (usual state) to 0x02. I assume it is to allow
+ * extra, non-standard, reporting (say battery-life). However
+ * at the same time it generates a left-click message on the button
+ * byte which causes spurious left-click's where there shouldn't be.
+ * This should sort that. */
+ if ((sc->sc_ibuf != ibuf) && (sc->sc_ibuf[0] == 0x02))
+ 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);
+ dt = -hid_get_data(ibuf, &sc->sc_loc_t);
for (i = 0; i < sc->nbuttons; i++)
if (hid_get_data(ibuf, &sc->sc_loc_btn[i]))
buttons |= (1 << UMS_BUT(i));
- if (dx || dy || dz || (sc->flags & UMS_Z)
+ if (dx || dy || dz || dt || (sc->flags & UMS_Z)
|| buttons != sc->status.button) {
- DPRINTFN(5, ("ums_intr: x:%d y:%d z:%d buttons:0x%x\n",
- dx, dy, dz, buttons));
+ DPRINTFN(5, ("ums_intr: x:%d y:%d z:%d aa:%d buttons:0x%x\n",
+ dx, dy, dz, dt, buttons));
sc->status.button = buttons;
sc->status.dx += dx;
sc->status.dy += dy;
sc->status.dz += dz;
-
+ sc->status.dt += dt;
+
/* Discard data in case of full buffer */
if (sc->qcount == sizeof(sc->qbuf)) {
DPRINTF(("Buffer full, discarded packet"));
@@ -466,13 +493,13 @@ ums_intr(xfer, addr, status)
* In any other case we delete the timeout event.
*/
if (sc->flags & UMS_SPUR_BUT_UP &&
- dx == 0 && dy == 0 && dz == 0 && buttons == 0) {
+ dx == 0 && dy == 0 && dz == 0 && dt == 0 && buttons == 0) {
usb_callout(sc->callout_handle, MS_TO_TICKS(50 /*msecs*/),
ums_add_to_queue_timeout, (void *) sc);
} else {
usb_uncallout(sc->callout_handle,
ums_add_to_queue_timeout, (void *) sc);
- ums_add_to_queue(sc, dx, dy, dz, buttons);
+ ums_add_to_queue(sc, dx, dy, dz, dt, buttons);
}
}
}
@@ -484,12 +511,12 @@ ums_add_to_queue_timeout(void *priv)
int s;
s = splusb();
- ums_add_to_queue(sc, 0, 0, 0, 0);
+ ums_add_to_queue(sc, 0, 0, 0, 0, 0);
splx(s);
}
Static void
-ums_add_to_queue(struct ums_softc *sc, int dx, int dy, int dz, int buttons)
+ums_add_to_queue(struct ums_softc *sc, int dx, int dy, int dz, int dt, int buttons)
{
/* Discard data in case of full buffer */
if (sc->qhead+sc->mode.packetsize > sizeof(sc->qbuf)) {
@@ -503,6 +530,8 @@ ums_add_to_queue(struct ums_softc *sc, int dx, int dy, int dz, int buttons)
if (dy < -256) dy = -256;
if (dz > 126) dz = 126;
if (dz < -128) dz = -128;
+ if (dt > 126) dt = 126;
+ if (dt < -128) dt = -128;
sc->qbuf[sc->qhead] = sc->mode.syncmask[1];
sc->qbuf[sc->qhead] |= ~buttons & MOUSE_MSC_BUTTONS;
@@ -550,7 +579,7 @@ ums_enable(v)
sc->qhead = sc->qtail = 0;
sc->status.flags = 0;
sc->status.button = sc->status.obutton = 0;
- sc->status.dx = sc->status.dy = sc->status.dz = 0;
+ sc->status.dx = sc->status.dy = sc->status.dz = sc->status.dt = 0;
callout_handle_init((struct callout_handle *)&sc->callout_handle);
@@ -807,10 +836,10 @@ ums_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, usb_proc_ptr p)
*status = sc->status;
sc->status.obutton = sc->status.button;
sc->status.button = 0;
- sc->status.dx = sc->status.dy = sc->status.dz = 0;
+ sc->status.dx = sc->status.dy = sc->status.dz = sc->status.dt = 0;
splx(s);
- if (status->dx || status->dy || status->dz)
+ if (status->dx || status->dy || status->dz || status->dt)
status->flags |= MOUSE_POSCHANGED;
if (status->button != status->obutton)
status->flags |= MOUSE_BUTTONSCHANGED;
diff --git a/sys/dev/usb/usbhid.h b/sys/dev/usb/usbhid.h
index fbc1704..416aec3 100644
--- a/sys/dev/usb/usbhid.h
+++ b/sys/dev/usb/usbhid.h
@@ -123,6 +123,7 @@ typedef struct usb_hid_descriptor {
#define HUG_VBRY 0x0044
#define HUG_VBRZ 0x0045
#define HUG_VNO 0x0046
+#define HUG_TWHEEL 0x0048 // M$ Wireless Intellimouse Wheel
#define HUG_SYSTEM_CONTROL 0x0080
#define HUG_SYSTEM_POWER_DOWN 0x0081
#define HUG_SYSTEM_SLEEP 0x0082
OpenPOWER on IntegriCloud