NetBSD Problem Report #15359

Received: (qmail 12112 invoked from network); 25 Jan 2002 03:53:39 -0000
Message-Id: <200201250351.g0P3pQk00624@ged.plethora.net>
Date: Thu, 24 Jan 2002 21:51:26 -0600 (CST)
From: seebs <seebs@plethora.net>
Reply-To: seebs@plethora.net
To: gnats-bugs@gnats.netbsd.org
Subject: Extending intellimouse support to 5-button mice
X-Send-Pr-Version: 3.95

>Number:         15359
>Category:       kern
>Synopsis:       psmi driver *almost* supports 5-button mice
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    kern-bug-people
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Fri Jan 25 03:54:00 +0000 2002
>Closed-Date:    
>Last-Modified:  Sun Jan 04 08:32:54 +0000 2009
>Originator:     seebs
>Release:        NetBSD 1.5ZA
>Organization:

>Environment:
System: NetBSD ged.plethora.net 1.5ZA NetBSD 1.5ZA (GED) #17: Thu Jan 24 21:40:46 CST 2002 root@ged.plethora.net:/usr/src/sys/arch/i386/compile/GED i386
Architecture: i386
Machine: i386
>Description:
	The intellimouse protocol, as described by psm_intelli.c, consists
	of sending a mouse several rate change commands, and then checking to
	see if it now gives a specific unexpected response.  There is a
	further extension to this protocol, which provides support for
	5-button mice.  In this version of the protocol, the rate change
	commands and expected response are slightly different.

	It turns out to be easy to produce a godawful kluge that allows the
	extra buttons to be used.

>How-To-Repeat:
	Get a Kensington "expert mouse pro".
>Fix:
	Calling this a "fix" is like calling Windows "a good desktop
	environment".  However, it serves as a proof of concept; with this
	patch in place, my Kensington Expert Mouse generates buttons 0-4,
	instead of just 0-2, when I check its output with "od -x
	/dev/wsmouse".

	I am deeply offended by the enclosed code, but it appears to work.
	I suspect that, down a similar path, the psm driver could be modified
	to support all three of the likely mouse protocols; simply test for
	the 5-button form first (because these mice will, of course, respond
	correctly to the 3-button protocol), if that fails, try the 3-button
	protocol, if that fails, use the "standard" 3-button protocol which
	doesn't support the wheel.

	However, I'm too lazy to do this right, so I'll just send it in as
	effective documentation.  Someone wishing to know where these numbers
	came from might want to review:

	http://govschl.ndsu.nodak.edu/~achapwes/PICmicro/mouse/mouse.html

	which is where I got the protocol info.  Special thanks to a friend of
	a friend who pointed out that my laptop's BIOS was probably silently
	altering protocol messages from the external mouse to avoid
	"compatability problems".

*** psm_intelli.c.orig	Thu Jan 24 21:02:07 2002
--- psm_intelli.c	Thu Jan 24 21:40:35 2002
***************
*** 40,45 ****
--- 40,49 ----
  #include <dev/wscons/wsconsio.h>
  #include <dev/wscons/wsmousevar.h>

+ enum intellimouse_protocol {
+ 	BUTTONS_3, BUTTONS_5, BUTTONS_MAX
+ };
+ 
  struct pmsi_softc {		/* driver status information */
  	struct device sc_dev;

***************
*** 51,56 ****
--- 55,62 ----
  	int inputstate;
  	u_int buttons, oldbuttons;	/* mouse button status */
  	signed char dx, dy;
+ 	enum intellimouse_protocol protocol;
+ 	unsigned long bytes;

  	struct device *sc_wsmousedev;
  };
***************
*** 77,113 ****
  	pmsi_disable,
  };

! static int pmsi_setintellimode __P((pckbc_tag_t, pckbc_slot_t));

  static int
! pmsi_setintellimode(tag, slot)
  	pckbc_tag_t tag;
  	pckbc_slot_t slot;
  {
  	u_char cmd[2], resp[1];
! 	int i, res;
! 	static u_char rates[] = {200, 200, 80};

! 	cmd[0] = PMS_SET_SAMPLE;
! 	for (i = 0; i < 3; i++) {
! 		cmd[1] = rates[i];
! 		res = pckbc_poll_cmd(tag, slot, cmd, 2, 0, 0, 0);
  		if (res)
  			return (res);
  	}
! 
! 	cmd[0] = PMS_SEND_DEV_ID;
! 	res = pckbc_poll_cmd(tag, slot, cmd, 1, 1, resp, 0);
! 	if (res)
! 		return (res);
! 	if (resp[0] != 3) {
! #ifdef DEBUG
! 		printf("pmsiprobe: resp[0] -> %d [expected 3]\n", resp[0]);
! #endif
! 		return (ENXIO);
! 	}
! 
! 	return (0);
  }

  int
--- 83,129 ----
  	pmsi_disable,
  };

! static int pmsi_setintellimode __P((struct pmsi_softc *, pckbc_tag_t, pckbc_slot_t));

  static int
! pmsi_setintellimode(sc, tag, slot)
! 	struct pmsi_softc *sc;
  	pckbc_tag_t tag;
  	pckbc_slot_t slot;
  {
  	u_char cmd[2], resp[1];
! 	int i, p, res;
! 	struct {
! 		int rates[3];
! 		int response;
! 		enum intellimouse_protocol protocol;
! 	} protocols[] = {
! 		{ { 200, 200, 80 }, 4, BUTTONS_5 },
! 		{ { 200, 100, 80 }, 3, BUTTONS_3 },
! 	};
! 
! 	for (p = 0; p < sizeof(protocols)/sizeof(protocols[0]); ++p) {
! 
! 		cmd[0] = PMS_SET_SAMPLE;
! 		for (i = 0; i < 3; i++) {
! 			cmd[1] = protocols[p].rates[i];
! 			res = pckbc_poll_cmd(tag, slot, cmd, 2, 0, 0, 0);
! 			if (res)
! 				return (res);
! 		}

! 		cmd[0] = PMS_SEND_DEV_ID;
! 		res = pckbc_poll_cmd(tag, slot, cmd, 1, 1, resp, 0);
  		if (res)
  			return (res);
+ 		if (resp[0] != protocols[p].response) {
+ 			printf("pmsiprobe [protocol %d]: resp[0] -> %d [expected %d]\n", p, resp[0], protocols[p].response);
+ 		}
+ 		if (sc)
+ 			sc->protocol = protocols[p].protocol;
+ 		return 0;
  	}
! 	return ENXIO;
  }

  int
***************
*** 148,154 ****
  		return (0);
  	}

! 	if ((res = pmsi_setintellimode(pa->pa_tag, pa->pa_slot))) {
  #ifdef DEBUG
  		printf("pmsiprobe: intellimode -> %d\n", res);
  #endif
--- 164,170 ----
  		return (0);
  	}

! 	if ((res = pmsi_setintellimode(0, pa->pa_tag, pa->pa_slot))) {
  #ifdef DEBUG
  		printf("pmsiprobe: intellimode -> %d\n", res);
  #endif
***************
*** 186,192 ****
  		return;
  	}
  #endif
! 	res = pmsi_setintellimode(pa->pa_tag, pa->pa_slot);
  #ifdef DEBUG
  	if (res) {
  		printf("pmsiattach: error setting intelli mode\n");
--- 202,208 ----
  		return;
  	}
  #endif
! 	res = pmsi_setintellimode(sc, pa->pa_tag, pa->pa_slot);
  #ifdef DEBUG
  	if (res) {
  		printf("pmsiattach: error setting intelli mode\n");
***************
*** 240,246 ****
  	if (res)
  		printf("pmsi_enable: command error\n");

! 	if ((res = pmsi_setintellimode(sc->sc_kbctag, sc->sc_kbcslot))) {
  #ifdef DEBUG
  		printf("pmsi_enable: intellimode -> %d\n", res);
  #endif
--- 256,262 ----
  	if (res)
  		printf("pmsi_enable: command error\n");

! 	if ((res = pmsi_setintellimode(sc, sc->sc_kbctag, sc->sc_kbcslot))) {
  #ifdef DEBUG
  		printf("pmsi_enable: intellimode -> %d\n", res);
  #endif
***************
*** 336,341 ****
--- 352,359 ----
  #define PS2LBUTMASK 0x01
  #define PS2RBUTMASK 0x02
  #define PS2MBUTMASK 0x04
+ #define PS2_4BUTMASK 0x10
+ #define PS2_5BUTMASK 0x20

  void pmsiinput(vsc, data)
  void *vsc;
***************
*** 353,358 ****
--- 371,377 ----
  	switch (sc->inputstate) {

  	case 0:
+ 		sc->bytes = (data << 24);
  		if ((data & 0xc0) == 0) { /* no ovfl, bit 3 == 1 too? */
  			sc->buttons = ((data & PS2LBUTMASK) ? 0x1 : 0) |
  			    ((data & PS2MBUTMASK) ? 0x2 : 0) |
***************
*** 362,367 ****
--- 381,387 ----
  		break;

  	case 1:
+ 		sc->bytes |= (data << 16);
  		sc->dx = data;
  		/* Bounding at -127 avoids a bug in XFree86. */
  		sc->dx = (sc->dx == -128) ? -127 : sc->dx;
***************
*** 369,384 ****
  		break;

  	case 2:
  		sc->dy = data;
  		sc->dy = (sc->dy == -128) ? -127 : sc->dy;
  		++sc->inputstate;
  		break;

  	case 3:
  		dz = data;
! 		dz = (dz == -128) ? -127 : dz;
  		sc->inputstate = 0;

  		changed = (sc->buttons ^ sc->oldbuttons);
  		sc->oldbuttons = sc->buttons;

--- 389,421 ----
  		break;

  	case 2:
+ 		sc->bytes |= (data << 8);
  		sc->dy = data;
  		sc->dy = (sc->dy == -128) ? -127 : sc->dy;
  		++sc->inputstate;
  		break;

  	case 3:
+ 		sc->bytes |= data;
  		dz = data;
! 		dz &= 0xf;
! 		if (sc->protocol == BUTTONS_5) {
! 		  if (dz & 0x8)
! 		    dz -= 16;
! 		  if (data & PS2_4BUTMASK)
! 		    sc->buttons |= 0x8;
! 		  if (data & PS2_5BUTMASK)
! 		    sc->buttons |= 0x10;
! 		} else {
! 		  if (dz == -128)
! 		    dz = -127;
! 		}
  		sc->inputstate = 0;

+ #if 0
+ 		/* used only for debugging protocol */
+ 		printf("psmi: packet 0x%08lx\n", sc->bytes);
+ #endif
  		changed = (sc->buttons ^ sc->oldbuttons);
  		sc->oldbuttons = sc->buttons;

>Release-Note:
>Audit-Trail:
State-Changed-From-To: open->feedback
State-Changed-By: dholland@NetBSD.org
State-Changed-When: Sun, 30 Nov 2008 09:40:14 +0000
State-Changed-Why:
psm_intelli.c was removed years ago - is a patch needed in the current pms(4)
driver? If so, can you merge this? :-/


State-Changed-From-To: feedback->open
State-Changed-By: dholland@NetBSD.org
State-Changed-When: Sun, 30 Nov 2008 10:07:07 +0000
State-Changed-Why:
Update submitter's address...


State-Changed-From-To: open->feedback
State-Changed-By: dholland@NetBSD.org
State-Changed-When: Sun, 30 Nov 2008 10:07:28 +0000
State-Changed-Why:
...and try again:

psm_intelli.c was removed years ago - is a patch needed in the current pms(4)
driver? If so, can you merge this? :-/


State-Changed-From-To: feedback->open
State-Changed-By: dholland@NetBSD.org
State-Changed-When: Sun, 04 Jan 2009 08:32:54 +0000
State-Changed-Why:
Submitter says he no longer has the hardware.


>Unformatted:

NetBSD Home
NetBSD PR Database Search

(Contact us) $NetBSD: query-full-pr,v 1.39 2013/11/01 18:47:49 spz Exp $
$NetBSD: gnats_config.sh,v 1.8 2006/05/07 09:23:38 tsutsui Exp $
Copyright © 1994-2007 The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.