kern/70607: [patch] Add Support for USB Microsoft Intellimouse (possibly others)

Matt Wright matt at consultmatt.co.uk
Mon Nov 8 02:50:33 PST 2004


The following reply was made to PR kern/70607; it has been noted by GNATS.

From: Matt Wright <matt at consultmatt.co.uk>
To: freebsd-gnats-submit at FreeBSD.org, amistry at am-productions.biz
Cc:  
Subject: Re: kern/70607: [patch] Add Support for USB Microsoft Intellimouse
 (possibly others)
Date: Mon, 08 Nov 2004 10:41:18 +0000

 Further to the patch that Anish posted here is a patch that removes bugs 
 2 and 3 which Mark noticed.
 
 If you need any explanation there is a fairly detailed explanation of 
 the patch, well at least the method I used to debug it, at:
 
 http://www.consultmatt.co.uk/freebsd/intellimouse.php
 
 Regards,
 
 Matt
 
 --- sys/dev/usb/usbhid.h.orig	Mon Sep 20 00:59:48 2004
 +++ sys/dev/usb/usbhid.h	Mon Sep 20 02:14:40 2004
 @@ -123,6 +123,7 @@
   #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
 --- sys/sys/mouse.h.orig	Fri Jul 30 01:59:40 2004
 +++ sys/sys/mouse.h	Tue Sep 21 00:42:37 2004
 @@ -58,6 +58,7 @@
       int     dx;			/* x movement */
       int     dy;			/* y movement */
       int     dz;			/* z movement */
 +    int     dt;			/* left right tilt axis */
   } mousestatus_t;
 
   /* button */
 --- sys/dev/usb/ums.c.orig	Mon Aug 16 00:39:18 2004
 +++ sys/dev/usb/ums.c	Tue Sep 21 00:47:52 2004
 @@ -104,7 +104,7 @@
   	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 @@
 
   	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 @@
   			  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 @@
   	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 @@
   		}
   	}
 
 +	/* 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_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 @@
   {
   	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 @@
   		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 @@
   		 * 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 @@
   	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 @@
   	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 @@
   	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 @@
   		*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;


More information about the freebsd-usb mailing list