plan 9 kernel history: overview | file list | diff list

2002/0503/pc/mouse.c (diff list | history)

pc/mouse.c on 1997/0327
1997/0327    
#include "u.h" 
#include "../port/lib.h" 
#include "mem.h" 
#include "dat.h" 
#include "fns.h" 
#include "../port/error.h" 
#include "io.h" 
 
1997/1101    
#define	Image	IMAGE 
#include <draw.h> 
#include <memdraw.h> 
1999/0119    
#include <cursor.h> 
1997/0327    
#include "screen.h" 
1997/1101    
 
/* 
 *  mouse types 
 */ 
enum 
{ 
	Mouseother=	0, 
	Mouseserial=	1, 
	MousePS2=	2, 
}; 
2002/0503    
 
static QLock mousectlqlock; 
1997/1101    
static int mousetype; 
2000/1012    
static int intellimouse; 
static int packetsize; 
static int resolution; 
static int accelerated; 
2001/1121    
static int mousehwaccel; 
1997/0327    
 
2001/1120    
enum 
{ 
	CMaccelerated, 
2001/1121    
	CMhwaccel, 
2001/1120    
	CMintellimouse, 
	CMlinear, 
	CMps2, 
	CMps2intellimouse, 
	CMres, 
	CMreset, 
	CMserial, 
}; 
 
static Cmdtab mousectlmsg[] = 
{ 
	CMaccelerated,		"accelerated",		0, 
2001/1121    
	CMhwaccel,		"hwaccel",		2, 
2001/1120    
	CMintellimouse,		"intellimouse",		1, 
	CMlinear,		"linear",		1, 
	CMps2,			"ps2",			1, 
	CMps2intellimouse,	"ps2intellimouse",	1, 
	CMres,			"res",			0, 
	CMreset,		"reset",		1, 
	CMserial,		"serial",		0, 
}; 
 
1997/0327    
/* 
 *  ps/2 mouse message is three bytes 
 * 
 *	byte 0 -	0 0 SDY SDX 1 M R L 
 *	byte 1 -	DX 
 *	byte 2 -	DY 
 * 
2000/0731    
 *  shift & right button is the same as middle button 
2000/1012    
 * 
 * Intellimouse and AccuPoint with extra buttons deliver 
 *	byte 3 -	00 or 01 or FF according to extra button state. 
 * extra buttons are mapped in this code to buttons 4 and 5. 
 * AccuPoint generates repeated events for these buttons; 
*  it and Intellimouse generate 'down' events only, so 
 * user-level code is required to generate button 'up' events 
 * if they are needed by the application. 
 * Also on laptops with AccuPoint AND external mouse, the 
 * controller may deliver 3 or 4 bytes according to the type 
 * of the external mouse; code must adapt. 
2001/0404    
 * 
 * On the NEC Versa series (and perhaps others?) we seem to 
 * lose a byte from the packet every once in a while, which 
 * means we lose where we are in the instruction stream. 
 * To resynchronize, if we get a byte more than two seconds 
 * after the previous byte, we assume it's the first in a packet. 
1997/0327    
 */ 
static void 
ps2mouseputc(int c, int shift) 
{ 
2000/1012    
	static short msg[4]; 
1997/0327    
	static int nb; 
2000/0716    
	static uchar b[] = {0, 1, 4, 5, 2, 3, 6, 7, 0, 1, 2, 3, 2, 3, 6, 7 }; 
2001/0404    
	static ulong lasttick; 
	ulong m; 
1997/0327    
	int buttons, dx, dy; 
2001/0404    
 
	/* 
	 * Resynchronize in stream with timing; see comment above. 
	 */ 
	m = MACHP(0)->ticks; 
	if(TK2SEC(m - lasttick) > 2) 
		nb = 0; 
	lasttick = m; 
1997/0327    
 
	/*  
	 *  check byte 0 for consistency 
	 */ 
	if(nb==0 && (c&0xc8)!=0x08) 
2000/1012    
		if(intellimouse && (c==0x00 || c==0x01 || c==0xFF)){ 
			/* last byte of 4-byte packet */ 
			packetsize = 4; 
			return; 
		} 
1997/0327    
 
	msg[nb] = c; 
2000/1012    
	if(++nb == packetsize){ 
1997/0327    
		nb = 0; 
		if(msg[0] & 0x10) 
			msg[1] |= 0xFF00; 
		if(msg[0] & 0x20) 
			msg[2] |= 0xFF00; 
 
		buttons = b[(msg[0]&7) | (shift ? 8 : 0)]; 
2000/1012    
		if(intellimouse && packetsize==4){ 
			if((msg[3]&0xc8) == 0x08){ 
				/* first byte of 3-byte packet */ 
				packetsize = 3; 
				msg[0] = msg[3]; 
				nb = 1; 
				/* fall through to emit previous packet */ 
			}else{ 
				/* the AccuPoint on the Toshiba 34[48]0CT encodes extra buttons as 4 and 5 */ 
				/* they repeat and don't release, however, so user-level timing code is required */ 
				if(msg[3] == 0xFF)  
					buttons |= 1<<3; 
				if(msg[3] == 0x01)  
					buttons |= 1<<4; 
			} 
		} 
1997/0327    
		dx = msg[1]; 
		dy = -msg[2]; 
2001/0527    
		mousetrack(dx, dy, buttons, TK2MS(MACHP(0)->ticks)); 
1997/0327    
	} 
	return; 
} 
 
/* 
 *  set up a ps2 mouse 
 */ 
static void 
ps2mouse(void) 
{ 
	if(mousetype == MousePS2) 
		return; 
 
	i8042auxenable(ps2mouseputc); 
	/* make mouse streaming, enabled */ 
	i8042auxcmd(0xEA); 
	i8042auxcmd(0xF4); 
 
	mousetype = MousePS2; 
2000/1012    
	packetsize = 3; 
2001/1121    
	mousehwaccel = 1; 
1997/0327    
} 
 
2001/1121    
/* 
 * The PS/2 Trackpoint multiplexor on the IBM Thinkpad T23 ignores 
 * acceleration commands.  It is supposed to pass them on 
 * to the attached device, but my Logitech mouse is simply 
 * not behaving any differently.  For such devices, we allow 
 * the user to use "hwaccel off" to tell us to back off to 
 * software acceleration even if we're using the PS/2 port. 
 * (Serial mice are always software accelerated.) 
 * For more information on the Thinkpad multiplexor, see 
 * http://wwwcssrv.almaden.ibm.com/trackpoint/ 
 */ 
1999/0225    
static void 
setaccelerated(int x) 
{ 
	accelerated = x; 
2001/1121    
	if(mousehwaccel){ 
		switch(mousetype){ 
		case MousePS2: 
			i8042auxcmd(0xE7); 
			return; 
		} 
1999/0225    
	} 
2001/1121    
	mouseaccelerate(x); 
1999/0225    
} 
 
static void 
setlinear(void) 
{ 
	accelerated = 0; 
2001/1121    
	if(mousehwaccel){ 
		switch(mousetype){ 
		case MousePS2: 
			i8042auxcmd(0xE6); 
			return; 
		} 
1999/0225    
	} 
2001/1121    
	mouseaccelerate(0); 
1999/0225    
} 
 
static void 
setres(int n) 
{ 
	resolution = n; 
	switch(mousetype){ 
	case MousePS2: 
		i8042auxcmd(0xE8); 
		i8042auxcmd(n); 
		break; 
	} 
} 
 
static void 
setintellimouse(void) 
{ 
	intellimouse = 1; 
2000/1012    
	packetsize = 4; 
1999/0225    
	switch(mousetype){ 
	case MousePS2: 
		i8042auxcmd(0xF3);	/* set sample */ 
		i8042auxcmd(0xC8); 
		i8042auxcmd(0xF3);	/* set sample */ 
		i8042auxcmd(0x64); 
		i8042auxcmd(0xF3);	/* set sample */ 
		i8042auxcmd(0x50); 
		break; 
	} 
} 
 
static void 
resetmouse(void) 
{ 
2000/1012    
	packetsize = 3; 
1999/0225    
	switch(mousetype){ 
	case MousePS2: 
		i8042auxcmd(0xF6); 
		i8042auxcmd(0xEA);	/* streaming */ 
		i8042auxcmd(0xE8);	/* set resolution */ 
		i8042auxcmd(3); 
		i8042auxcmd(0xF4);	/* enabled */ 
		break; 
	} 
} 
 
1997/0327    
void 
2001/1120    
mousectl(Cmdbuf *cb) 
1997/0327    
{ 
2001/1120    
	Cmdtab *ct; 
 
2002/0503    
	qlock(&mousectlqlock); 
	if(waserror()){ 
		qunlock(&mousectlqlock); 
		nexterror(); 
	} 
 
2001/1120    
	ct = lookupcmd(cb, mousectlmsg, nelem(mousectlmsg)); 
	switch(ct->index){ 
	case CMaccelerated: 
		setaccelerated(cb->nf == 1 ? 1 : atoi(cb->f[1])); 
		break; 
	case CMintellimouse: 
		setintellimouse(); 
		break; 
	case CMlinear: 
		setlinear(); 
		break; 
	case CMps2: 
1997/0327    
		ps2mouse(); 
2001/1120    
		break; 
	case CMps2intellimouse: 
1999/0225    
		ps2mouse(); 
		setintellimouse(); 
2001/1120    
		break; 
	case CMres: 
		if(cb->nf >= 2) 
			setres(atoi(cb->f[1])); 
		else 
			setres(1); 
		break; 
	case CMreset: 
1999/0225    
		resetmouse(); 
		if(accelerated) 
			setaccelerated(accelerated); 
		if(resolution) 
			setres(resolution); 
		if(intellimouse) 
			setintellimouse(); 
2001/1120    
		break; 
	case CMserial: 
2002/0503    
		if(mousetype == Mouseserial) 
			error(Emouseset); 
 
		if(cb->nf > 2 && *cb->f[2] == 'M') 
			i8250mouse(cb->f[1], m3mouseputc, 0); 
		else 
			i8250mouse(cb->f[1], mouseputc, cb->nf == 1); 
 
		mousetype = Mouseserial; 
		packetsize = 3; 
2001/1120    
		break; 
2001/1121    
	case CMhwaccel: 
		if(strcmp(cb->f[1], "on")==0) 
			mousehwaccel = 1; 
		else if(strcmp(cb->f[1], "off")==0) 
			mousehwaccel = 0; 
		else 
			cmderror(cb, "bad mouse control message"); 
1998/0417    
	} 
2002/0503    
 
	qunlock(&mousectlqlock); 
	poperror(); 
1997/0327    
} 


source code copyright © 1990-2005 Lucent Technologies; see license
Plan 9 distribution
comments to russ cox (rsc@swtch.com)