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

1992/1017/pc/kbd.c (diff list | history)

pc/kbd.c on 1991/0702
1991/0702    
#include	"u.h" 
1992/0321    
#include	"../port/lib.h" 
1991/0706    
#include	"mem.h" 
1991/0702    
#include	"dat.h" 
#include	"fns.h" 
1991/0703    
#include	"io.h" 
1992/1017    
#include	"../port/error.h" 
1991/0702    
 
1991/0731    
#include	<libg.h> 
#include	<gnot.h> 
#include	"screen.h" 
 
1991/0702    
enum { 
	Data=		0x60,	/* data port */ 
 
	Status=		0x64,	/* status port */ 
	 Inready=	0x01,	/*  input character ready */ 
	 Outbusy=	0x02,	/*  output busy */ 
1991/0730    
	 Sysflag=	0x04,	/*  system flag */ 
1991/0702    
	 Cmddata=	0x08,	/*  cmd==0, data==1 */ 
1991/0730    
	 Inhibit=	0x10,	/*  keyboard/mouse inhibited */ 
	 Minready=	0x20,	/*  mouse character ready */ 
	 Rtimeout=	0x40,	/*  general timeout */ 
1991/0731    
	 Parity=	0x80, 
1991/0702    
 
1991/0730    
	Cmd=		0x64,	/* command port (write only) */ 
 
1991/0703    
	Spec=	0x80, 
 
	PF=	Spec|0x20,	/* num pad function key */ 
	View=	Spec|0x00,	/* view (shift window up) */ 
1991/0731    
	KF=	Spec|0x40,	/* function key */ 
1991/0703    
	Shift=	Spec|0x60, 
	Break=	Spec|0x61, 
	Ctrl=	Spec|0x62, 
	Latin=	Spec|0x63, 
	Caps=	Spec|0x64, 
	Num=	Spec|0x65, 
1991/0911    
	Middle=	Spec|0x66, 
1992/0806    
	No=	0x00,		/* peter */ 
1991/0703    
 
1991/0731    
	Home=	KF|13, 
	Up=	KF|14, 
	Pgup=	KF|15, 
	Print=	KF|16, 
1991/0703    
	Left=	View, 
	Right=	View, 
	End=	'\r', 
	Down=	View, 
	Pgdown=	View, 
1991/0731    
	Ins=	KF|20, 
1991/0703    
	Del=	0x7F, 
1992/1017    
 
	Rbutton=4, 
	Mbutton=2, 
	Lbutton=1, 
1991/0702    
}; 
 
1991/0703    
uchar kbtab[] =  
1991/0702    
{ 
1991/0703    
[0x00]	No,	0x1b,	'1',	'2',	'3',	'4',	'5',	'6', 
1991/0702    
[0x08]	'7',	'8',	'9',	'0',	'-',	'=',	'\b',	'\t', 
1991/0703    
[0x10]	'q',	'w',	'e',	'r',	't',	'y',	'u',	'i', 
[0x18]	'o',	'p',	'[',	']',	'\n',	Ctrl,	'a',	's', 
[0x20]	'd',	'f',	'g',	'h',	'j',	'k',	'l',	';', 
[0x28]	'\'',	'`',	Shift,	'\\',	'z',	'x',	'c',	'v', 
1992/0806    
[0x30]	'b',	'n',	'm',	',',	'.',	'/',	Shift,	'*', 
1991/0911    
[0x38]	Latin,	' ',	Ctrl,	KF|1,	KF|2,	KF|3,	KF|4,	KF|5, 
1992/0806    
[0x40]	KF|6,	KF|7,	KF|8,	KF|9,	KF|10,	Num,	KF|12,	'7', 
[0x48]	'8',	'9',	'-',	'4',	'5',	'6',	'+',	'1', 
[0x50]	'2',	'3',	'0',	'.',	No,	No,	No,	KF|11, 
1991/0731    
[0x58]	KF|12,	No,	No,	No,	No,	No,	No,	No, 
1991/0702    
}; 
 
1991/0703    
uchar kbtabshift[] = 
{ 
[0x00]	No,	0x1b,	'!',	'@',	'#',	'$',	'%',	'^', 
[0x08]	'&',	'*',	'(',	')',	'_',	'+',	'\b',	'\t', 
[0x10]	'Q',	'W',	'E',	'R',	'T',	'Y',	'U',	'I', 
[0x18]	'O',	'P',	'{',	'}',	'\n',	Ctrl,	'A',	'S', 
[0x20]	'D',	'F',	'G',	'H',	'J',	'K',	'L',	':', 
[0x28]	'"',	'~',	Shift,	'|',	'Z',	'X',	'C',	'V', 
1992/0806    
[0x30]	'B',	'N',	'M',	'<',	'>',	'?',	Shift,	'*', 
1991/0911    
[0x38]	Latin,	' ',	Ctrl,	KF|1,	KF|2,	KF|3,	KF|4,	KF|5, 
1992/0806    
[0x40]	KF|6,	KF|7,	KF|8,	KF|9,	KF|10,	Num,	KF|12,	'7', 
[0x48]	'8',	'9',	'-',	'4',	'5',	'6',	'+',	'1', 
[0x50]	'2',	'3',	'0',	'.',	No,	No,	No,	KF|11, 
1991/0731    
[0x58]	KF|12,	No,	No,	No,	No,	No,	No,	No, 
1991/0703    
}; 
 
uchar kbtabesc1[] = 
{ 
[0x00]	No,	No,	No,	No,	No,	No,	No,	No, 
[0x08]	No,	No,	No,	No,	No,	No,	No,	No, 
[0x10]	No,	No,	No,	No,	No,	No,	No,	No, 
1992/0806    
[0x18]	No,	No,	No,	No,	'\n',	Ctrl,	No,	No, 
1991/0703    
[0x20]	No,	No,	No,	No,	No,	No,	No,	No, 
1992/0806    
[0x28]	No,	No,	Shift,	No,	No,	No,	No,	No, 
[0x30]	No,	No,	No,	No,	No,	'/',	No,	Print, 
1991/0703    
[0x38]	Latin,	No,	No,	No,	No,	No,	No,	No, 
[0x40]	No,	No,	No,	No,	No,	No,	Break,	Home, 
1992/0806    
[0x48]	Up,	Pgup,	No,	Left,	No,	Right,	No,	End, 
[0x50]	Down,	Pgdown,	Ins,	Del,	No,	No,	No,	No, 
1991/0703    
[0x58]	No,	No,	No,	No,	No,	No,	No,	No, 
}; 
 
1991/0905    
/* 
 *  keyboard input q 
 */ 
1991/0703    
KIOQ	kbdq; 
1991/0905    
 
1991/0911    
static int mousebuttons; 
1992/0811    
static int keybuttons; 
1992/1015    
static uchar ccc; 
1992/1017    
static int mousetype; 
static int mouseport; 
static int shift; 
1991/0911    
 
1991/0905    
 
1992/0904    
enum 
{ 
1992/1015    
	/* controller command byte */ 
	Cscs1=		(1<<6),		/* scan code set 1 */ 
	Cmousedis=	(1<<5),		/* mouse disable */ 
	Ckbddis=	(1<<4),		/* kbd disable */ 
	Csf=		(1<<2),		/* system flag */ 
	Cmouseint=	(1<<1),		/* mouse interrupt enable */ 
	Ckbdint=	(1<<0),		/* kbd interrupt enable */ 
 
1992/0904    
	/* what kind of mouse */ 
	Mouseother=	0, 
	Mouseserial=	1, 
	MousePS2=	2, 
}; 
1991/0703    
 
1992/1017    
static void	kbdintr(Ureg*); 
static int	ps2mouseputc(IOQ*, int); 
static int	m3mouseputc(IOQ*, int); 
1992/1015    
 
1991/0803    
/* 
 *  wait for output no longer busy 
 */ 
static int 
outready(void) 
1991/0731    
{ 
1991/0803    
	int tries; 
 
1992/1015    
	for(tries = 0; (inb(Status) & Outbusy); tries++){ 
		if(tries > 500) 
1991/0803    
			return -1; 
1992/1015    
		delay(2); 
	} 
1991/0803    
	return 0; 
} 
 
/* 
 *  wait for input 
 */ 
static int 
inready(void) 
{ 
	int tries; 
 
1992/1015    
	for(tries = 0; !(inb(Status) & Inready); tries++){ 
		if(tries > 500) 
1991/0803    
			return -1; 
1992/1015    
		delay(2); 
	} 
1991/0803    
	return 0; 
} 
 
/* 
 *  send a command to the mouse 
 */ 
static int 
mousecmd(int cmd) 
{ 
1991/0731    
	unsigned int c; 
1991/0803    
	int tries; 
1991/0731    
 
1991/0904    
	c = 0; 
1992/1015    
	tries = 0; 
1991/0904    
	do{ 
1992/1015    
		if(tries++ > 5) 
			break; 
		if(outready() < 0) 
1992/1016    
			break; 
1992/1015    
		outb(Cmd, 0xD4); 
		if(outready() < 0) 
1992/1016    
			break; 
1992/1015    
		outb(Data, cmd); 
		if(outready() < 0) 
1992/1016    
			break; 
1992/1015    
		if(inready() < 0) 
1992/1016    
			break; 
1992/1015    
		c = inb(Data); 
1992/1016    
	} while(c == 0xFE || c == 0); 
1992/1015    
	if(c != 0xFA){ 
		print("mouse returns %2.2ux to the %2.2ux command\n", c, cmd); 
1991/0803    
		return -1; 
1992/1015    
	} 
1991/0803    
	return 0; 
1991/0731    
} 
 
1991/1210    
/* 
 *  ask 8042 to enable the use of address bit 20 
 */ 
1991/0703    
void 
1991/1210    
i8042a20(void) 
{ 
1992/1015    
	outready(); 
1991/1210    
	outb(Cmd, 0xD1); 
	outready(); 
	outb(Data, 0xDF); 
	outready(); 
} 
 
1992/0902    
/* 
 *  ask 8042 to reset the machine 
 */ 
1991/1210    
void 
1992/0902    
i8042reset(void) 
{ 
1992/1013    
	/* 
	 *  this works for dhog 
	 */ 
1992/0902    
	outready(); 
1992/1013    
	outb(Cmd, 0xFE);	/* pulse reset line */ 
	outready(); 
	/* 
	 *  this is the old IBM way 
	 */ 
	outready(); 
1992/0902    
	outb(Cmd, 0xD1); 
	outready(); 
1992/1013    
	outb(Data, 0xDE);	/* set reset line high */ 
1992/0902    
	outready(); 
} 
 
void 
1991/0703    
kbdinit(void) 
{ 
1992/0711    
	int c; 
1991/0730    
 
1991/0716    
	setvec(Kbdvec, kbdintr); 
1992/1017    
	bigcursor(); 
1991/0730    
 
	/* wait for a quiescent controller */ 
	while((c = inb(Status)) & (Outbusy | Inready)) 
		if(c & Inready) 
			inb(Data); 
 
1992/1015    
	/* get current controller command byte */ 
	outb(Cmd, 0x20); 
	if(inready() < 0){ 
		print("kbdinit: can't read ccc\n"); 
		ccc = 0; 
	} else 
		ccc = inb(Data); 
 
1992/0904    
	/* enable kbd xfers and interrupts */ 
1992/1015    
	ccc &= ~Ckbddis; 
	ccc |= Csf | Ckbdint | Cscs1; 
	if(outready() < 0) 
		print("kbd init failed\n"); 
1992/0904    
	outb(Cmd, 0x60); 
	if(outready() < 0) 
		print("kbd init failed\n"); 
1992/1015    
	outb(Data, ccc); 
	outready(); 
1992/0904    
} 
1992/0408    
 
1992/0904    
/* 
 *  setup a serial mouse 
 */ 
1992/1017    
static void 
serialmouse(int port, char *type, int setspeed) 
1992/0904    
{ 
1992/1016    
	if(mousetype) 
1992/1017    
		error(Emouseset); 
1992/0811    
 
1992/0904    
	/* set up /dev/eia0 as the mouse */ 
1992/1017    
	uartspecial(port, 0, &mouseq, setspeed ? 1200 : 0); 
	if(type && *type == 'M') 
		mouseq.putc = m3mouseputc; 
	mouseport = port; 
1992/0904    
	mousetype = Mouseserial; 
} 
1992/0408    
 
1992/0904    
/* 
 *  set up a ps2 mouse 
 */ 
1992/1017    
static void 
ps2mouse(void) 
1992/0904    
{ 
1992/1015    
	int x; 
1992/0904    
 
1992/1017    
	if(mousetype) 
		error(Emouseset); 
1992/0904    
 
	/* enable kbd/mouse xfers and interrupts */ 
1992/1017    
	setvec(Mousevec, kbdintr); 
1992/1015    
	x = splhi(); 
	ccc &= ~Cmousedis; 
	ccc |= Cmouseint; 
	if(outready() < 0) 
		print("mouse init failed\n"); 
1992/0904    
	outb(Cmd, 0x60); 
	if(outready() < 0) 
1992/1015    
		print("mouse init failed\n"); 
	outb(Data, ccc); 
1992/0904    
	if(outready() < 0) 
1992/1015    
		print("mouse init failed\n"); 
1992/0904    
	outb(Cmd, 0xA8); 
1992/1015    
	if(outready() < 0) 
		print("mouse init failed\n"); 
1992/0904    
 
	/* make mouse streaming, enabled */ 
1992/1017    
	mousecmd(0xEA); 
1992/0904    
	mousecmd(0xF4); 
1992/1015    
	splx(x); 
 
1992/0904    
	mousetype = MousePS2; 
1992/0825    
} 
 
/* 
1992/1017    
 *  ps/2 mouse message is three bytes 
1991/0731    
 * 
 *	byte 0 -	0 0 SDY SDX 1 M R L 
 *	byte 1 -	DX 
 *	byte 2 -	DY 
1992/0918    
 * 
 *  shift & left button is the same as middle button 
1991/0731    
 */ 
1992/1015    
static int 
1992/1017    
ps2mouseputc(IOQ *q, int c) 
1991/0731    
{ 
	static short msg[3]; 
	static int nb; 
1992/0918    
	static uchar b[] = {0, 1, 4, 5, 2, 3, 6, 7, 0, 1, 2, 5, 2, 3, 6, 7 }; 
1991/0731    
	extern Mouseinfo mouse; 
 
1992/1015    
	USED(q);		/* not */ 
1991/0731    
	/*  
	 *  check byte 0 for consistency 
	 */ 
	if(nb==0 && (c&0xc8)!=0x08) 
1992/1015    
		return 0; 
1991/0731    
 
	msg[nb] = c; 
	if(++nb == 3){ 
		nb = 0; 
		if(msg[0] & 0x10) 
			msg[1] |= 0xFF00; 
		if(msg[0] & 0x20) 
			msg[2] |= 0xFF00; 
 
1992/0918    
		mousebuttons = b[(msg[0]&7) | (shift ? 8 : 0)]; 
1992/0811    
		mouse.newbuttons = mousebuttons | keybuttons; 
1991/0731    
		mouse.dx = msg[1]; 
		mouse.dy = -msg[2]; 
		mouse.track = 1; 
1991/0823    
		spllo();		/* mouse tracking kills uart0 */ 
1991/0731    
		mouseclock(); 
	} 
1992/1015    
	return 0; 
1991/0703    
} 
 
/* 
1992/1017    
 *  microsoft 3 button, 7 bit bytes 
 * 
 *	byte 0 -	1  L  R Y7 Y6 X7 X6 
 *	byte 1 -	0 X5 X4 X3 X2 X1 X0 
 *	byte 2 -	0 Y5 Y4 Y3 Y2 Y1 Y0 
 *	byte 3 -	0  M  x  x  x  x  x	(optional) 
 * 
 *  shift & left button is the same as middle button (for 2 button mice) 
 */ 
static int 
m3mouseputc(IOQ *q, int c) 
{ 
	static uchar msg[3]; 
	static int nb; 
	static uchar b[] = { 0, 4, 1, 5, 0, 4, 3, 7 }; 
	extern Mouseinfo mouse; 
 
	USED(q);		/* not */ 
 
	/*  
	 *  check bit 6 for consistency 
	 */ 
	if(nb==0){ 
		if((c&0x40) != 0){ 
			/* must be 4th (M button) byte */ 
			mousebuttons = (mousebuttons & ~Mbutton) | ((c&0x2)?Mbutton:0); 
			mouse.newbuttons = mousebuttons | keybuttons; 
			mouse.dx = 0; 
			mouse.dy = 0; 
			mouse.track = 0; 
			mouseclock(); 
			return 0; 
		} 
	} 
	msg[nb] = c; 
	if(++nb == 3){ 
		nb = 0; 
		mousebuttons = b[(msg[0]>>4)&3 | (shift ? 4 : 0)]; 
		mouse.newbuttons = mousebuttons | keybuttons; 
		mouse.dx = (((msg[0]&3)<<7) | msg[1]) - 128; 
		mouse.dy = (((msg[0]&0xc)<<5) | msg[2]) - 128; 
		mouse.track = 1; 
		mouseclock(); 
	} 
	return 0; 
} 
 
/* 
 *  set/change mouse configuration 
 */ 
void 
mousectl(char *arg) 
{ 
	int n, x; 
	char *field[3]; 
 
	n = getfields(arg, field, 3, ' '); 
	if(n < 1) 
		return; 
	if(strncmp(field[0], "serial", 6) == 0){ 
		if(n > 1) 
			serialmouse(atoi(field[1]), field[2], 0); 
		else 
			serialmouse(atoi(field[0]+6), 0, 1); 
	} else if(strcmp(field[0], "ps2") == 0){ 
		ps2mouse(); 
	} else if(strcmp(field[0], "accelerated") == 0){ 
		switch(mousetype){ 
		case MousePS2: 
			x = splhi(); 
			mousecmd(0xE7); 
			splx(x); 
			break; 
		} 
	} else if(strcmp(field[0], "linear") == 0){ 
		switch(mousetype){ 
		case MousePS2: 
			x = splhi(); 
			mousecmd(0xE6); 
			splx(x); 
			break; 
		} 
	} else if(strcmp(field[0], "res") == 0){ 
		if(n < 2) 
			n = 1; 
		else 
			n = atoi(field[1]); 
		switch(mousetype){ 
		case MousePS2: 
			x = splhi(); 
			mousecmd(0xE8); 
			mousecmd(n); 
			splx(x); 
			break; 
		} 
	} 
} 
 
/* 
1991/0911    
 *  Ctrl key used as middle button pressed 
 */ 
static void 
1992/0811    
mbon(int val) 
1991/0911    
{ 
1992/0811    
	keybuttons |= val; 
	mouse.newbuttons = mousebuttons | keybuttons; 
1991/0911    
	mouse.dx = 0; 
	mouse.dy = 0; 
	mouse.track = 1; 
	spllo();		/* mouse tracking kills uart0 */ 
	mouseclock(); 
} 
1992/0811    
static void 
mboff(int val) 
{ 
	keybuttons &= ~val; 
	mouse.newbuttons = mousebuttons | keybuttons; 
	mouse.dx = 0; 
	mouse.dy = 0; 
	mouse.track = 1; 
	spllo();		/* mouse tracking kills uart0 */ 
	mouseclock(); 
} 
1991/0911    
 
/* 
1991/0703    
 *  keyboard interrupt 
 */ 
1992/0222    
int 
kbdintr0(void) 
1991/0703    
{ 
1992/0711    
	int s, c, i, nk; 
1991/0703    
	static int esc1, esc2; 
	static int caps; 
	static int ctl; 
	static int num; 
1991/1211    
	static int lstate; 
	static uchar kc[5]; 
1991/0703    
	int keyup; 
1991/0702    
 
1991/0703    
	/* 
1991/0731    
	 *  get status 
1991/0703    
	 */ 
1991/0730    
	s = inb(Status); 
1991/0731    
	if(!(s&Inready)) 
		return -1; 
 
	/* 
	 *  get the character 
	 */ 
1991/0703    
	c = inb(Data); 
1991/0730    
 
	/* 
	 *  if it's the mouse... 
	 */ 
	if(s & Minready){ 
1992/1017    
		ps2mouseputc(&mouseq, c); 
1991/0731    
		return 0; 
1991/0730    
	} 
1991/0703    
 
	/* 
	 *  e0's is the first of a 2 character sequence 
	 */ 
	if(c == 0xe0){ 
		esc1 = 1; 
1991/0731    
		return 0; 
1991/0703    
	} else if(c == 0xe1){ 
		esc2 = 2; 
1991/0731    
		return 0; 
1991/0703    
	} 
 
1991/0822    
	keyup = c&0x80; 
	c &= 0x7f; 
	if(c > sizeof kbtab){ 
		print("unknown key %ux\n", c|keyup); 
		return 0; 
	} 
 
1991/0703    
	if(esc1){ 
		c = kbtabesc1[c]; 
		esc1 = 0; 
	} else if(esc2){ 
		esc2--; 
1991/0731    
		return 0; 
1991/0703    
	} else if(shift) 
		c = kbtabshift[c]; 
	else 
		c = kbtab[c]; 
 
	if(caps && c<='z' && c>='a') 
		c += 'A' - 'a'; 
 
	/* 
	 *  keyup only important for shifts 
	 */ 
	if(keyup){ 
		switch(c){ 
		case Shift: 
			shift = 0; 
			break; 
		case Ctrl: 
			ctl = 0; 
			break; 
1992/0811    
		case KF|1: 
1992/1017    
			mboff(Rbutton); 
1991/0911    
			break; 
1992/0811    
		case KF|2: 
1992/1017    
			mboff(Mbutton); 
1992/0811    
			break; 
		case KF|3: 
1992/1017    
			mboff(Lbutton); 
1992/0811    
			break; 
1991/0703    
		} 
1991/0731    
		return 0; 
1991/0703    
	} 
 
	/* 
 	 *  normal character 
	 */ 
	if(!(c & Spec)){ 
		if(ctl) 
			c &= 0x1f; 
		switch(lstate){ 
		case 1: 
1991/1211    
			kc[0] = c; 
1991/0703    
			lstate = 2; 
1991/1211    
			if(c == 'X') 
				lstate = 3; 
			break; 
1991/0703    
		case 2: 
1991/1211    
			kc[1] = c; 
			c = latin1(kc); 
			nk = 2; 
		putit: 
1991/0703    
			lstate = 0; 
1991/1211    
			if(c != -1) 
				kbdputc(&kbdq, c); 
			else for(i=0; i<nk; i++) 
				kbdputc(&kbdq, kc[i]); 
			break; 
		case 3: 
		case 4: 
		case 5: 
			kc[lstate-2] = c; 
			lstate++; 
			break; 
		case 6: 
			kc[4] = c; 
			c = unicode(kc); 
			nk = 5; 
			goto putit; 
1991/0703    
		default: 
1991/1211    
			kbdputc(&kbdq, c); 
1991/0703    
			break; 
		} 
1991/1211    
		return 0; 
1991/0703    
	} else { 
		switch(c){ 
		case Caps: 
			caps ^= 1; 
1991/0731    
			return 0; 
1991/0703    
		case Num: 
			num ^= 1; 
1991/0731    
			return 0; 
1991/0703    
		case Shift: 
			shift = 1; 
1991/0731    
			return 0; 
1991/0703    
		case Latin: 
			lstate = 1; 
1991/0731    
			return 0; 
1991/0703    
		case Ctrl: 
			ctl = 1; 
1991/0911    
			return 0; 
1992/0811    
		case KF|1: 
1992/1017    
			mbon(Rbutton); 
1992/0811    
			return 0; 
		case KF|2: 
1992/1017    
			mbon(Mbutton); 
1992/0811    
			return 0; 
		case KF|3: 
1992/1017    
			mbon(Lbutton); 
1991/0731    
			return 0; 
1991/0703    
		} 
	} 
	kbdputc(&kbdq, c); 
1991/0731    
	return 0; 
1992/0222    
} 
 
void 
kbdintr(Ureg *ur) 
{ 
1992/0711    
	USED(ur); 
1992/0222    
	kbdintr0(); 
1991/0703    
} 


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