Subject: kern/41: Suggestion: Incorporate new PS/2 mouse driver
To: None <gnats-admin>
From: None <jarle@darling.idt.unit.no>
List: netbsd-bugs
Date: 12/15/1993 03:05:10
>Number:         41
>Category:       kern
>Synopsis:       The old PS/2 mouse driver is buggy.  Replace!
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    gnats-admin (Kernel Bug People)
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Wed Dec 15 03:05:07 1993
>Originator:     Jarle Greipsland
>Organization:
Free Hardware Foundation, UnLtd
>Release:
>Environment:
Intel PW/GX, NetBSD-current, kernel
System: NetBSD darling.idt.unit.no 0.9a DARLING#7 i386

>Description:
The default PS/2 mouse driver coming with NetBSD )0.9 and current) is
buggy.  This has been experienced by myself.  Some time ago someone posted
an updated driver on the Net.  I grabbed it and incorporated it into my
system and have been happy since (oh well, at least my mouse works).

I would therefore like you to consider it for incorporation into the
default distribution.  Again, I have not had any problems with it, but
others may have... Also, I didn't write it so I don't want any credits :-)

>How-To-Repeat:
Try the default driver with a PS/2 type mouse.
>Fix:
Apply the diffs:
*** pms.c	Sun Nov  7 10:08:03 1993
--- pms.c.new	Thu Nov 18 19:33:40 1993
***************
*** 19,24 ****
   * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   *
!  *	$Id: pms.c,v 1.8 1993/11/02 23:59:34 mycroft Exp $
   */
  
--- 19,47 ----
   * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  */
+ 
+ /*
+  *  Ported to 386bsd Oct 17, 1992 
+  *  Sandi Donno, Computer Science, University of Cape Town, South Africa
+  *  Please send bug reports to sandi@cs.uct.ac.za
+  *
+  *  Thanks are also due to Rick Macklem, rick@snowhite.cis.uoguelph.ca -
+  *  although I was only partially successful in getting the alpha release
+  *  of his "driver for the Logitech and ATI Inport Bus mice for use with 
+  *  386bsd and the X386 port" to work with my Microsoft mouse, I nevertheless 
+  *  found his code to be an invaluable reference when porting this driver 
+  *  to 386bsd.
+  *
+  *  Further modifications for latest 386BSD+patchkit and port to NetBSD,
+  *  Andrew Herbert <andrew@werple.apana.org.au> - 8 June 1993
+  *
+  *  Cloned from the Microsoft Bus Mouse driver, also by Erik Forsberg, by
+  *  Andrew Herbert - 12 June 1993 
   *
!  *  Modified for PS/2 mouse by Charles Hannum <mycroft@ai.mit.edu>
!  *  - 13 June 1993
!  *
!  *  Modified for PS/2 AUX mouse by Shoji Yuen <yuen@nuie.nagoya-u.ac.jp>
!  *  - 24 October 1993
   */
  
***************
*** 45,48 ****
--- 68,75 ----
  #include "i386/isa/isa_device.h"
  
+ #ifdef 0
+ #include "syslog.h"		/* For debugging */
+ #endif
+ 
  #define DATA	0       /* Offset for data port, read-write */
  #define CNTRL	4       /* Offset for control port, write-only */
***************
*** 50,69 ****
  
  /* status bits */
! #define	PMS_OBUF_FULL	0x21
! #define	PMS_IBUF_FULL	0x02
  
  /* controller commands */
  #define	PMS_INT_ENABLE	0x47	/* enable controller interrupts */
  #define	PMS_INT_DISABLE	0x65	/* disable controller interrupts */
! #define	PMS_AUX_DISABLE	0xa7	/* enable auxiliary port */
! #define	PMS_AUX_ENABLE	0xa8	/* disable auxiliary port */
! #define	PMS_MAGIC_1	0xa9	/* XXX */
! #define	PMS_MAGIC_2	0xaa	/* XXX */
! 
! /* mouse commands */
! #define	PMS_SET_SCALE11	0xe6	/* set scaling 1:1 */
! #define	PMS_SET_SCALE21 0xe7	/* set scaling 2:1 */
  #define	PMS_SET_RES	0xe8	/* set resolution */
! #define	PMS_GET_SCALE	0xe9	/* get scaling factor */
  #define	PMS_SET_STREAM	0xea	/* set streaming mode */
  #define	PMS_SET_SAMPLE	0xf3	/* set sampling rate */
--- 77,94 ----
  
  /* status bits */
! #define	PMS_OUTPUT_ACK	0x02	/* output acknowledge */
! /*#define	PMS_OUTPUT_ACK	0x21	/* output acknowledge */
  
  /* controller commands */
+ #define	PMS_ENABLE	0xa8	/* enable auxiliary port */
+ #define	PMS_DISABLE	0xa7	/* disable auxiliary port */
  #define	PMS_INT_ENABLE	0x47	/* enable controller interrupts */
  #define	PMS_INT_DISABLE	0x65	/* disable controller interrupts */
! 
! /* m+use commands */
! #define PMS_SET_SCALE11	0xe6	/* set 1:1 scaling */
! #define PMS_SET_SCALE21 0xe7	/* set 2:1 scaling */
  #define	PMS_SET_RES	0xe8	/* set resolution */
! #define	PMS_GET_SCALE	0xe9	/* set scaling factor */
  #define	PMS_SET_STREAM	0xea	/* set streaming mode */
  #define	PMS_SET_SAMPLE	0xf3	/* set sampling rate */
***************
*** 92,96 ****
--- 117,125 ----
  static struct pms_softc {	/* Driver status information */
  	struct ringbuf inq;	/* Input queue */
+ #ifdef NetBSD
  	struct selinfo rsel;
+ #else
+ 	pid_t	rsel;		/* Process selecting for Input */
+ #endif
  	unsigned char state;	/* Mouse driver state */
  	unsigned char status;	/* Mouse button status */
***************
*** 104,134 ****
  struct isa_driver pmsdriver = { pmsprobe, pmsattach, "pms" };
  
! static inline void pms_flush(int ioport)
! {
! 	u_char c;
! 	while (c = inb(ioport+STATUS) & 0x03)
! 		if ((c & PMS_OBUF_FULL) == PMS_OBUF_FULL)
! 			(void) inb(ioport+DATA);
! }
  
! static inline void pms_dev_cmd(int ioport, u_char value)
  {
! 	pms_flush(ioport);
! 	outb(ioport+CNTRL, 0xd4);
! 	pms_flush(ioport);
! 	outb(ioport+DATA, value);
  }
  
! static inline void pms_aux_cmd(int ioport, u_char value)
  {
! 	pms_flush(ioport);
! 	outb(ioport+CNTRL, value);
! }
! 
! static inline void pms_pit_cmd(int ioport, u_char value)
! {
! 	pms_flush(ioport);
  	outb(ioport+CNTRL, 0x60);
! 	pms_flush(ioport);
  	outb(ioport+DATA, value);
  }
--- 133,151 ----
  struct isa_driver pmsdriver = { pmsprobe, pmsattach, "pms" };
  
! #define AUX_PORT 0x60		/* AUX_PORT base (S.Yuen) */
  
! static void pms_write_dev(int inport, u_char value)
  {
! 	pms_poll_status();
! 	outb(inport+CNTRL, 0xd4);
! 	pms_poll_status();
! 	outb(inport+DATA,value);
  }
  
! static inline void pms_command(int ioport, u_char value)
  {
! 	pms_poll_status();
  	outb(ioport+CNTRL, 0x60);
! 	pms_poll_status();
  	outb(ioport+DATA, value);
  }
***************
*** 136,151 ****
  int pmsprobe(struct isa_device *dvp)
  {
! 	int unit = dvp->id_unit;
! 	int ioport = dvp->id_iobase;
! 	u_char c;
  
! 	pms_dev_cmd(ioport, PMS_RESET);
! 	pms_aux_cmd(ioport, PMS_MAGIC_1);
! 	pms_aux_cmd(ioport, PMS_MAGIC_2);
  	c = inb(ioport+DATA);
! 	pms_pit_cmd(ioport, PMS_INT_DISABLE);
! 	if (c & 0x04)
! 		return 0;
! 	return 1;
  }
  
--- 153,175 ----
  int pmsprobe(struct isa_device *dvp)
  {
! 	/* XXX: Needs a real probe routine. */
! 
! 	int ioport,c,unit;
  
! 	ioport=dvp->id_iobase;
! 	unit=dvp->id_unit;
! 	pms_write_dev(ioport,0xff); /* Reset aux device */
! 	pms_poll_status();
! 	outb(ioport+CNTRL,0xa9);
! 	pms_poll_status();
! 	outb(ioport+CNTRL,0xaa);
  	c = inb(ioport+DATA);
! 	if(c&0x04) {
! 		printf("PS/2 AUX mouse is not found\n");
! 		pms_command(ioport,0x65);
! 		pmsaddr[unit] = 0;	/* Device not found */
! 		return(0);}
! 	printf("PS/2 AUX mouse found.  Installing driver\n");
! 	return (1);
  }
  
***************
*** 157,179 ****
  
  	/* Save I/O base address */
  	pmsaddr[unit] = ioport;
  
! 	/* Disable mouse interrupts and initialize */
! 	pms_pit_cmd(ioport, PMS_INT_DISABLE);
! 	pms_aux_cmd(ioport, PMS_AUX_ENABLE);
! 	pms_dev_cmd(ioport, PMS_DEV_ENABLE);
! 	pms_dev_cmd(ioport, PMS_SET_RES);
! 	pms_dev_cmd(ioport, 3);		/* 8 counts/mm */
! 	pms_dev_cmd(ioport, PMS_SET_SCALE21);
! 	pms_dev_cmd(ioport, PMS_SET_SAMPLE);
! 	pms_dev_cmd(ioport, 100);	/* 100 samples/sec */
! 	pms_dev_cmd(ioport, PMS_SET_STREAM);
! 	pms_dev_cmd(ioport, PMS_DEV_DISABLE);
! 	pms_aux_cmd(ioport, PMS_AUX_DISABLE);
  
- 	/* Setup initial driver state */
  	sc->state = 0;
  
  	/* Done */
  	return(0);
  }
--- 181,211 ----
  
  	/* Save I/O base address */
+ 
  	pmsaddr[unit] = ioport;
  
! 	/* Disable mouse interrupts */
! 
! 	pms_poll_status();
! 	outb(ioport+CNTRL, PMS_ENABLE);
! #ifdef 0
! 	pms_write(ioport, PMS_SET_RES);
! 	pms_write(ioport, 0x03);	/* 8 counts/mm */
! 	pms_write(ioport, PMS_SET_SCALE);
! 	pms_write(ioport, 0x02);	/* 2:1 */
! 	pms_write(ioport, PMS_SET_SCALE21);
! 	pms_write(ioport, PMS_SET_SAMPLE);
! 	pms_write(ioport, 0x64);	/* 100 samples/sec */
! 	pms_write(ioport, PMS_SET_STREAM);
! #endif
! 	pms_poll_status();
! 	outb(ioport+CNTRL, PMS_DISABLE);
! 	pms_command(ioport, PMS_INT_DISABLE);
! 
! 	/* Setup initial state */
  
  	sc->state = 0;
  
  	/* Done */
+ 
  	return(0);
  }
***************
*** 186,197 ****
--- 218,232 ----
  
  	/* Validate unit number */
+ 
  	if (unit >= NPMS)
  		return(ENXIO);
  
  	/* Get device data */
+ 
  	sc = &pms_softc[unit];
  	ioport = pmsaddr[unit];
  
  	/* If device does not exist */
+ 
  	if (ioport == 0)
  		return(ENXIO);
***************
*** 202,206 ****
--- 237,248 ----
  
  	/* Initialize state */
+ 
  	sc->state |= OPEN;
+ #ifdef NetBSD
+ 	sc->rsel.si_pid = 0;
+ 	sc->rsel.si_coll = 0;
+ #else
+ 	sc->rsel = 0;
+ #endif
  	sc->status = 0;
  	sc->button = 0;
***************
*** 209,223 ****
  
  	/* Allocate and initialize a ring buffer */
  	sc->inq.count = sc->inq.first = sc->inq.last = 0;
  
  	/* Enable Bus Mouse interrupts */
! 	pms_aux_cmd(ioport, PMS_AUX_ENABLE);
! 	pms_pit_cmd(ioport, PMS_INT_ENABLE);
! 	pms_dev_cmd(ioport, PMS_DEV_ENABLE);
  
  	/* Successful open */
  	return(0);
  }
  
  int pmsclose(dev_t dev, int flag, int fmt, struct proc *p)
  {
--- 251,278 ----
  
  	/* Allocate and initialize a ring buffer */
+ 
  	sc->inq.count = sc->inq.first = sc->inq.last = 0;
  
  	/* Enable Bus Mouse interrupts */
! 
! 	pms_write_dev(ioport, PMS_DEV_ENABLE);
! 	pms_poll_status();
! 	outb(ioport+CNTRL, PMS_ENABLE);
! 	pms_command(ioport, PMS_INT_ENABLE);
  
  	/* Successful open */
+ 
  	return(0);
  }
  
+ int pms_poll_status() /* 24 Oct. 1993 */
+ {
+ 
+ 	while(inb(AUX_PORT+STATUS)&0x03) {
+ 		if(inb(AUX_PORT+STATUS) & 0x2 == 0x2)
+ 			inb(AUX_PORT+DATA);}
+ }
+ 		
+ 
  int pmsclose(dev_t dev, int flag, int fmt, struct proc *p)
  {
***************
*** 226,229 ****
--- 281,285 ----
  
  	/* Get unit and associated info */
+ 
  	unit = PMSUNIT(dev);
  	sc = &pms_softc[unit];
***************
*** 231,242 ****
  
  	/* Disable further mouse interrupts */
! 	pms_dev_cmd(ioport, PMS_DEV_DISABLE);
! 	pms_pit_cmd(ioport, PMS_INT_DISABLE);
! 	pms_aux_cmd(ioport, PMS_AUX_DISABLE);
  
  	/* Complete the close */
  	sc->state &= ~OPEN;
  
  	/* close is almost always successful */
  	return(0);
  }
--- 287,301 ----
  
  	/* Disable further mouse interrupts */
! 
! 	pms_command(ioport,PMS_INT_DISABLE);
! 	pms_poll_status();
! 	outb(ioport+CNTRL,PMS_DISABLE );
  
  	/* Complete the close */
+ 
  	sc->state &= ~OPEN;
  
  	/* close is almost always successful */
+ 
  	return(0);
  }
***************
*** 252,258 ****
--- 311,319 ----
  
  	/* Get device information */
+ 
  	sc = &pms_softc[PMSUNIT(dev)];
  
  	/* Block until mouse activity occured */
+ 
  	s = spltty();
  	while (sc->inq.count == 0) {
***************
*** 270,273 ****
--- 331,335 ----
  
  	/* Transfer as many chunks as possible */
+ 
  	while (sc->inq.count > 0 && uio->uio_resid > 0) {
  		length = min(sc->inq.count, uio->uio_resid);
***************
*** 276,279 ****
--- 338,342 ----
  
  		/* Remove a small chunk from input queue */
+ 
  		if (sc->inq.first + length >= MSBSZ) {
  			bcopy(&sc->inq.queue[sc->inq.first], 
***************
*** 289,292 ****
--- 352,356 ----
  
  		/* Copy data to user process */
+ 
  		error = uiomove(buffer, length, uio);
  		if (error)
***************
*** 297,300 ****
--- 361,365 ----
  
  	/* Allow interrupts again */
+ 
  	splx(s);
  	return(error);
***************
*** 308,314 ****
--- 373,381 ----
  
  	/* Get device information */
+ 
  	sc = &pms_softc[PMSUNIT(dev)];
  
  	/* Perform IOCTL command */
+ 
  	switch (cmd) {
  
***************
*** 316,322 ****
--- 383,391 ----
  
  		/* Don't modify info while calculating */
+ 
  		s = spltty();
  
  		/* Build mouse status octet */
+ 
  		info.status = sc->status;
  		if (sc->x || sc->y)
***************
*** 324,327 ****
--- 393,397 ----
  
  		/* Encode X and Y motion as good as we can */
+ 
  		if (sc->x > 127)
  			info.xmotion = 127;
***************
*** 339,342 ****
--- 409,413 ----
  
  		/* Reset historical information */
+ 
  		sc->x = 0;
  		sc->y = 0;
***************
*** 344,347 ****
--- 415,419 ----
  
  		/* Allow interrupts and copy result buffer */
+ 
  		splx(s);
  		error = copyout(&info, addr, sizeof(struct mouseinfo));
***************
*** 354,357 ****
--- 426,430 ----
  
  	/* Return error code */
+ 
  	return(error);
  }
***************
*** 362,428 ****
  	struct pms_softc *sc = &pms_softc[unit];
  	int ioport = pmsaddr[unit];
- 	static int state = 0;
- 	static char buttons, dx, dy;
- 	char changed;
- 
- 	switch (state) {
- 
- 	case 0:
- 		buttons = inb(ioport + DATA);
- 		if (!(buttons & 0xc0))
- 			++state;
- 		break;
- 
- 	case 1:
- 		dx = inb(ioport + DATA);
- 		++state;
- 		break;
- 
- 	case 2:
- 		dy = inb(ioport + DATA);
- 		state = 0;
- 
- 		if (buttons & 0x10)
- 			dx -= 256;
- 		if (buttons & 0x20)
- 			dy -= 256;
- 
- 		if (dx == -128)
- 			dx = -127;
- 		if (dy == -128)
- 			dy = 127;
- 		else
- 			dy = -dy;
- 
- 		buttons = ~(((buttons&1) << 2) | (buttons&3));
- 
- 		changed = buttons ^ sc->button;
- 		sc->button = buttons;
- 		sc->status = buttons | (sc->status & ~BUTSTATMASK) | (changed << 3);
- 
- 		/* Update accumulated movements */
- 		sc->x += dx;
- 		sc->y += dy;
- 
- 		/* If device in use and a change occurred... */
- 		if (sc->state & OPEN && (dx || dy || changed)) {
- 			sc->inq.queue[sc->inq.last++] = 0x40 |
- 							(buttons ^ BUTSTATMASK);
- 			sc->inq.queue[sc->inq.last++ % MSBSZ] = dx;
- 			sc->inq.queue[sc->inq.last++ % MSBSZ] = dy;
- 			sc->inq.queue[sc->inq.last++ % MSBSZ] = 0;
- 			sc->inq.queue[sc->inq.last++ % MSBSZ] = 0;
- 			sc->inq.last = sc->inq.last % MSBSZ;
- 			sc->inq.count += 5;
- 
- 			if (sc->state & ASLP) {
- 				sc->state &= ~ASLP;
- 				wakeup((caddr_t)sc);
- 			}
- 			selwakeup(&sc->rsel);
- 		}
  
! 		break;
  	}
  }
  
--- 435,453 ----
  	struct pms_softc *sc = &pms_softc[unit];
  	int ioport = pmsaddr[unit];
  
! 	sc->inq.queue[sc->inq.last++ % MSBSZ] = inb(ioport+DATA);
! 	sc->inq.count++;
! 	if (sc -> state & ASLP) {
! 		sc->state &= ~ASLP;
! 		wakeup((caddr_t)sc);
  	}
+ #ifdef NetBSD
+ 	selwakeup(&sc->rsel);
+ #else
+ 	if (sc->rsel) {
+ 		selwakeup(sc->rsel, 0);
+ 		sc->rsel = 0;
+ 	}
+ #endif
  }
  
***************
*** 433,445 ****
--- 458,476 ----
  
  	/* Silly to select for output */
+ 
  	if (rw == FWRITE)
  		return(0);
  
  	/* Return true if a mouse event available */
+ 
  	s = spltty();
  	if (sc->inq.count)
  		ret = 1;
  	else {
+ #ifdef NetBSD
  		selrecord(p, &sc->rsel);
+ #else
+ 		sc->rsel = p->p_pid;
+ #endif
  		ret = 0;
  	}

>Audit-Trail:
>Unformatted:

------------------------------------------------------------------------------