From: fcawth@wam.umd.edu (Alfred B. Cawthorne)
Subject: [386bsd] bus mouse driver
Originator: fcawth@rac2.wam.umd.edu
Organization: University of Maryland at College Park
Date: Mon, 7 Sep 1992 15:22:30 GMT


Here is the second version of my logitech bus mouse driver.  I use it with
X386 with good results.  It requires no modification of the X386 code so
you can use it with the binaries that are floating around.  Please send
any fixes, etc... to fcawth@delphi.umd.edu

                                            Fred.
cut here.---------------

# This is a shell archive.  Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file".  Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
#	README
#	mse.c
#	mse.h
#	tst.c
#
echo x - README
sed 's/^X//' >README << 'END-of-README'
XThis is a simple bus mouse driver I wrote so I could use my logitech bus
Xmouse with X386.  The standard disclaimer applies to this code.  USE AT 
XYOUR OWN RISK!!!  This is not a finished product, and I don't have lots of time
Xto make it really nice.  I just wanted to use my mouse with X386! 
X
XVersion 0.1: First attempt, non interrupt driven.  This version worked ok, but
X certain operations (like moving the scrollbar) were slow because the mouse 
X port did not get read fast enough.  
X
XVersion 0.2: Still not as nice as I'd like it, but it works much better than
X the first version.  A buffer was added which stores mouse values when the 
X mouse card interrupts.  I am not sure why, but buttons need to be posted 
X twice to be recognized correctly by X386.  I noticed that I would have to
X move my cheapo serial mouse for the buttons to get recognized, so I suspect
X that this is a feature of X386.  The buffering in this version is very
X primative.
X
XFuture:  Write a nifty circular queue for the mouse data, and don't reset
X after each read.  
X
XInstallation Instructions:
X
X1. copy the files mse.c and mse.h into the /sys/i386/isa directory.
X
X2. add the line:
Xdevice	mse0	at isa? port 0x23c irq9 vector mseintr
Xto your system's config file.
X(Note: the port's address can be changed in the mse.h file)
X
X3. add the line:
Xi386/isa/mse.c		optional mse device-driver
Xto  /sys/i386/conf/files.i386
X
X4. add this to /sys/i386/i386/conf.c
X
X#include "mse.h"
X#if NMSE >0
Xint mseioctl(),mseopen(),mseclose(),mseread(),msewrite();
X#else
Xdefine mseiocntl enxio
Xdefine mseclose enxio
Xdefine mseread enxio
Xdefine msewrite enxio
Xdefine mseopen enxio
X#endif
X
X5. change an entry in the cdevsw array (conf.c) to read:
X
X          { mseopen,      mseclose,       mseread,        msewrite,               
X          mseioctl,     nullop,         nullop,         NULL,
X          seltrue,      enodev,         enodev },
X
X(Note that the position of this determines the major device # of the driver)
X( a hex number to the right of each entry is given so you don't even have to 
X  count )
X6. Make the driver special file:
Xmknod /dev/mouse c <major> 0
X
X7. To use it with X386, add the line:
XBusMouse	"/dev/mouse"
Xto the Xconfig file and comment out all the serial mouse related stuff.
X
XNow, it should work.  I included a test program I used when writing this.
X
XSend any questions or comments to fcawth@delphi.umd.edu. 
END-of-README
echo x - mse.c
sed 's/^X//' >mse.c << 'END-of-mse.c'
X/* 386bsd logitech Bus Mouse driver   Fred Cawthorne 8/25/92                 */
X/* This is a BETA release (at best) as it is my first attempt at programming */
X/* a bsd device driver.  It is intended to be a simple but usable bus mouse  */
X/* driver.  I have tested this with the binary X386 release from agate, and  */
X/* it seems to work fine.  This driver gives the user two ways of accessing  */
X/* the mouse.  IOCTLS probabally involve less overhead than READ's but the   */
X/* mseread routine was included for compatibility with X386.                 */ 
X/* Please send any improvements, suggestions, etc to fcawth@delphi.umd.edu   */
X
X
X/*  Version 0.2  Interrupt driven version */
X/* Permission is given to copy, modify, and use this code in any way you see */
X/* fit.  I assume no responsibility for the problems this code could cause.  */
X/* The only thing I know is that it works for me, it may or not work for you.*/
X
X
X#include "mse.h"
X
X#include "param.h"
X#include "ioctl.h"
X#include "conf.h"
X#include "uio.h"
X#include "kernel.h"
X
X#include "i386/isa/isa_device.h"
Xstatic char mse_buffer[193];
Xstatic int mse_bufptr;
Xint 	mseprobe(), mseattach(),  msestart(), mseparam();
Xstruct	isa_driver msedriver = {
X	mseprobe, mseattach, "mse"
X};
X
Xmseprobe(dev)
Xstruct isa_device *dev;
X{
X/*hack for now, if your bus mouse doesn't like this, find out what its sig. is*/
X/* we need a good way of finding out if it is really there but I don't have   */
X/* any hardware documentation for the mouse */
Xif (inb(SIGNATURE_PORT)==0)
X		return(1);
Xelse return(0);
X}
X
X
Xint
Xmseattach(isdp)
Xstruct isa_device *isdp;
X{
X outb (CONTROL,0);
X/*	outb(CONTROL, MOUSEDEFAULT);
X	outb(PORTC, PORTC_DISABLE_INTERRUPTS); */
Xprintf (" sig=%d",inb(SIGNATURE_PORT));
Xreturn (1);
X}
X
Xmseopen(dev_t dev, int flag, int mode, struct proc *p)
X{
X	outb(CONTROL, MOUSEDEFAULT);
Xmse_bufptr=0; 
X	outb(PORTC, PORTC_ENABLE_INTERRUPTS);
X        
Xreturn(0);
X}
X
Xmseclose(dev, flag, mode, p)
X	dev_t dev;
X	int flag, mode;
X	struct proc *p;
X{
X        outb(CONTROL, 0);
X	outb(PORTC, PORTC_DISABLE_INTERRUPTS);
Xreturn(0);
X}
X 
Xmseintr(unit)
X{
Xstruct mousedat mouse_dat;
Xint i;
Xstatic int oldbut;
Xstatic int buttonpress = 0;
X
Xoutb(PORTC, PORTC_DISABLE_INTERRUPTS);
X	                outb(PORTC, READ_X_LOW);
X			mouse_dat.deltax = inb(PORTA) & 0xf;
X			outb(PORTC, READ_X_HIGH);
X			mouse_dat.deltax |= (inb(PORTA) & 0xf) << 4;
X
X			outb(PORTC, READ_Y_LOW );
X			mouse_dat.deltay = inb(PORTA) & 0xf;
X			outb(PORTC, READ_Y_HIGH);
X			i = inb(PORTA);
Xoutb(PORTC, PORTC_DISABLE_INTERRUPTS);
X			mouse_dat.deltay |= (i & 0xf) << 4;
X			mouse_dat.buttons = (i >> 5)|0x80;
X            if((char)(mouse_dat.deltay)==(-128)) (char)mouse_dat.deltay++; 
X          if ((char)(mouse_dat.deltay)!=0) mouse_dat.deltay=-mouse_dat.deltay; 
X           if((char)(mouse_dat.deltax)==(-128)) (char)mouse_dat.deltax++; 
Xif ((mouse_dat.deltax!=0)||(mouse_dat.deltay!=0)||(mouse_dat.buttons!=oldbut))
X{ 
Xif (buttonpress>1 ) {
Xoldbut=mouse_dat.buttons;
Xbuttonpress=0; }
Xelse {
Xbuttonpress++;
Xoldbut=0; }
X
Xmse_buffer[mse_bufptr++]=(char)mouse_dat.buttons;
Xmse_buffer[mse_bufptr++]=(char)mouse_dat.deltax;
Xmse_buffer[mse_bufptr++]=(char)mouse_dat.deltay; 
Xif (mse_bufptr>191) mse_bufptr=(189); 
X/*printf ("mse_bufptr=%d\n",mse_bufptr++);  
Xprintf ("MOUSEINTR called dx=%d dy=%d but=%d\n",mouse_dat.deltax,mouse_dat.deltay,mouse_dat.buttons);
X*/
X}
Xoutb(PORTC,PORTC_ENABLE_INTERRUPTS);
X
X}
Xmseioctl(dev, cmd, data, flag)
X	dev_t dev;
X        int cmd,flag;
X        struct mousedat* data;
X{ int i;
Xregister struct mousedat mouse_dat;
X switch(cmd) {
X	case MIOGETDATA:outb(PORTC, READ_X_LOW);
X			mouse_dat.deltax = inb(PORTA) & 0xf;
X			outb(PORTC, READ_X_HIGH);
X			mouse_dat.deltax |= (inb(PORTA) & 0xf) << 4;
X
X			outb(PORTC, READ_Y_LOW );
X			mouse_dat.deltay = inb(PORTA) & 0xf;
X			outb(PORTC, READ_Y_HIGH);
X			i = inb(PORTA);
X			mouse_dat.deltay |= (i & 0xf) << 4;
X			mouse_dat.buttons = i >> 5;
X(struct mousedat *)data->buttons=(7-(mouse_dat.buttons));
X(struct mousedat *)data->deltax=mouse_dat.deltax;
X(struct mousedat *)data->deltay=mouse_dat.deltay;
Xreturn(0);
X			break;
X
X	default:	return(EFAULT);
X			break;
X	}
Xreturn(0);
X}
X
Xmsestart(tp)
X	register struct mousedat *tp;
X{
X}
X
Xmseread (dev,uio,flag)
X struct uio *uio;
X dev_t dev;
Xint flag;
X
X{ 
Xint ptr;
Xif (mse_bufptr!=0)
Xfor (ptr=0; ptr<mse_bufptr; ptr++ ) {
X/*printf ("mse_buffer[%d]=%d,",ptr,mse_buffer[ptr]);  */
Xif ((uio->uio_resid)>3) {
X   ureadc((char)mse_buffer[ptr++],uio);
X   ureadc((char)mse_buffer[ptr++],uio);
X   ureadc((char)mse_buffer[ptr],uio);
X       }
X}
Xmse_bufptr=0;
Xreturn(0);
X}
X
Xmsewrite(dev,uio,flag) 
Xdev_t dev;
Xstruct uio *uio;
X{}
X
END-of-mse.c
echo x - mse.h
sed 's/^X//' >mse.h << 'END-of-mse.h'
X/*	mouse.h:	header file for Logitech Bus Mouse driver	*/
X
X#ifndef MOUSE_H
X#define MOUSE_H
X
X/* #define USE_INTS	/* Should the driver use interrupts? */
X
X#define	PORTA	0x23c		/*	1100		*/
X#define	SIGNATURE_PORT	0x23d	/*	1101		*/
X#define	PORTC	0x23e		/*	1110		*/
X#define	CONTROL	0x23f		/*	1111		*/
X
X#define	SETMODE		0x80	/*	1xxx xxxx	*/
X	/* Group A */
X#define M_AMODE0	0x00	/*	x00x xxxx	*/
X#define M_AMODE1	0x20	/*	x01x xxxx	*/
X#define M_AMODE2	0x40	/*	x10x xxxx	*/
X#define M_AIN		0x10	/*	xxx1 xxxx	*/
X#define M_AOUT		0x00	/*	xxx0 xxxx	*/
X#define M_CUIN		0x08	/*	xxxx 1xxx	*/
X#define M_CUOUT		0x00	/*	xxxx 0xxx	*/
X	/* Group B */
X#define M_BMODE0	0x00	/*	xxxx x0xx	*/
X#define M_BMODE1	0x04	/*	xxxx x1xx	*/
X#define M_BIN		0x02	/*	xxxx xx1x	*/
X#define M_BOUT		0x00	/*	xxxx xx0x	*/
X#define M_CLIN		0x01	/*	xxxx xxx1	*/
X#define M_CLOUT		0x00	/*	xxxx xxx0	*/
X
X#define MOUSEDEFAULT	(SETMODE|M_AMODE0|M_AIN)	/* 1001 0000 */
X
X#define	READ_X_LOW	0x80	/*	1000 0000	*/
X#define	READ_X_HIGH	0xa0	/*	1010 0000	*/
X#define	READ_Y_LOW	0xc0	/*	1100 0000	*/
X#define	READ_Y_HIGH	0xe0	/*	1110 0000	*/
X
X#define	PORTC_ENABLE_INTERRUPTS		0x80	/*	1000 0000	*/
X#define	PORTC_DISABLE_INTERRUPTS	0x10	/*	0000 0000	*/
X
Xstruct	mousedat { 
X	unsigned char buttons; 
X	char deltax,deltay;
X};
X
X/* IOCTLS */
X#define	MIOGETDATA	((sizeof(struct mousedat*)<<16)|('M'<<8) | 0x01 |0x40000000)	/* get mouse data */
X
X#endif
X
END-of-mse.h
echo x - tst.c
sed 's/^X//' >tst.c << 'END-of-tst.c'
X
X/*
X	Test program for Mouse Driver
X DON'T use this while you are using the mouse under X windows or it will
X    get confused...
X*/
X
X#include <sys/file.h>
X#include <sys/ioctl.h>
X#include <sys/types.h>
X#include "mse.h"
X
Xint     mousefd;
X
X
Xmain()
X{
X struct mousedat	new,old;
X int xpos, ypos;
X
X	old.deltax = old.deltay = old.buttons = 1;
X
X	if ((mousefd = open("/dev/mouse",O_RDWR,0)) == -1) {
X		perror("open of mouse device");
X		exit(1);
X	}
Xwhile (1)  readmouse(&new);
X
Xold.buttons=0;
X	xpos = ypos = 1;
X	while (old.buttons != 7) {	/* press all 3 buttons to quit */
X		readmouse(&new);
X	if ((new.deltax!=0)||(new.deltay!=0)||(new.buttons!=old.buttons)){	
X			xpos += new.deltax; ypos += new.deltay;
X		        printf("X=%03d Y=%03d  Buttons=%c%c%c\n", xpos, ypos,
X				   new.buttons & 4 ? '*' : ' ',
X				      new.buttons & 2 ? '*' : ' ',
X				         new.buttons & 1 ? '*' : ' ' );
X                        old.buttons=new.buttons;
X                        old.deltax=new.deltax;
X                        old.deltay=new.deltay;
X		}
X	}
X}
X
Xreadmouse( md )
Xregister struct mousedat *md;
X{
Xint i;
Xchar buf[1024];
Xint len = 10;
X/*	if ((ioctl(mousefd,MIOGETDATA,md)) == -1) {  
X		perror("IOCTL failed on /dev/mouse");
X		exit(2);
X	} */
X/* some printfs to see if everything's OK */
X
X/*printf ("deltax=%d deltay=%d buttons=%d \n",md->deltax,md->deltay,md->buttons); */
Xlen=read(mousefd,&buf,64);
Xfor (i=0; i<len ; i++)
Xprintf ("len=%d buf[%d]=%d  \n",len,i,buf[i]);
Xsleep(1); 
X}
X
END-of-tst.c
exit