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

2002/0411/pc/kbd.c (diff list | history)

2002/0411/sys/src/9/pc/kbd.c:1,4392002/0417/sys/src/9/pc/kbd.c:1,453 (short | long | prev | next)
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    
 
enum { 
1997/0327    
	Data=		0x60,		/* data port */ 
1991/0702    
 
1997/0327    
	Status=		0x64,		/* status port */ 
	 Inready=	0x01,		/*  input character ready */ 
	 Outbusy=	0x02,		/*  output busy */ 
	 Sysflag=	0x04,		/*  system flag */ 
	 Cmddata=	0x08,		/*  cmd==0, data==1 */ 
	 Inhibit=	0x10,		/*  keyboard/mouse inhibited */ 
	 Minready=	0x20,		/*  mouse character ready */ 
	 Rtimeout=	0x40,		/*  general timeout */ 
1991/0731    
	 Parity=	0x80, 
1991/0702    
 
1997/0327    
	Cmd=		0x64,		/* command port (write only) */ 
1991/0730    
 
1997/0327    
	Spec=		0x80, 
1993/0915    
 
1997/0327    
	PF=		Spec|0x20,	/* num pad function key */ 
	View=		Spec|0x00,	/* view (shift window up) */ 
1999/1005    
	KF=		0xF000,	/* function key (begin Unicode private space) */ 
1997/0327    
	Shift=		Spec|0x60, 
	Break=		Spec|0x61, 
	Ctrl=		Spec|0x62, 
	Latin=		Spec|0x63, 
	Caps=		Spec|0x64, 
	Num=		Spec|0x65, 
	Middle=		Spec|0x66, 
	No=		0x00,		/* peter */ 
1991/0703    
 
1997/0327    
	Home=		KF|13, 
	Up=		KF|14, 
	Pgup=		KF|15, 
	Print=		KF|16, 
1999/1005    
	Left=		KF|17, 
	Right=		KF|18, 
1997/0327    
	End=		'\r', 
	Down=		View, 
1999/1005    
	Pgdown=		KF|19, 
1997/0327    
	Ins=		KF|20, 
	Del=		0x7F, 
1999/1207    
	Scroll=		KF|21, 
1991/0702    
}; 
 
2000/0107    
/* 
 * The codes at 0x79 and 0x81 are produed by the PFU Happy Hacking keyboard. 
 * A 'standard' keyboard doesn't produce anything above 0x58. 
 */ 
1999/1005    
Rune 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, 
1999/1207    
[0x40]	KF|6,	KF|7,	KF|8,	KF|9,	KF|10,	Num,	Scroll,	'7', 
1992/0806    
[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, 
1998/1006    
[0x60]	No,	No,	No,	No,	No,	No,	No,	No, 
[0x68]	No,	No,	No,	No,	No,	No,	No,	No, 
[0x70]	No,	No,	No,	No,	No,	No,	No,	No, 
2000/0107    
[0x78]	No,	View,	No,	Up,	No,	No,	No,	No, 
1991/0702    
}; 
 
1999/1005    
Rune kbtabshift[] = 
1991/0703    
{ 
[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, 
1999/1207    
[0x40]	KF|6,	KF|7,	KF|8,	KF|9,	KF|10,	Num,	Scroll,	'7', 
1992/0806    
[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, 
1998/1006    
[0x60]	No,	No,	No,	No,	No,	No,	No,	No, 
[0x68]	No,	No,	No,	No,	No,	No,	No,	No, 
[0x70]	No,	No,	No,	No,	No,	No,	No,	No, 
2000/0107    
[0x78]	No,	Up,	No,	Up,	No,	No,	No,	No, 
1991/0703    
}; 
 
1999/1005    
Rune kbtabesc1[] = 
1991/0703    
{ 
[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, 
1998/1006    
[0x60]	No,	No,	No,	No,	No,	No,	No,	No, 
[0x68]	No,	No,	No,	No,	No,	No,	No,	No, 
[0x70]	No,	No,	No,	No,	No,	No,	No,	No, 
2000/0107    
[0x78]	No,	Up,	No,	No,	No,	No,	No,	No, 
1991/0703    
}; 
 
1992/0904    
enum 
{ 
1992/1015    
	/* controller command byte */ 
	Cscs1=		(1<<6),		/* scan code set 1 */ 
1997/0327    
	Cauxdis=	(1<<5),		/* mouse disable */ 
1992/1015    
	Ckbddis=	(1<<4),		/* kbd disable */ 
	Csf=		(1<<2),		/* system flag */ 
1997/0327    
	Cauxint=	(1<<1),		/* mouse interrupt enable */ 
1992/1015    
	Ckbdint=	(1<<0),		/* kbd interrupt enable */ 
1992/0904    
}; 
1991/0703    
 
1997/0327    
static Lock i8042lock; 
static uchar ccc; 
static void (*auxputc)(int, int); 
 
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; 
} 
 
/* 
1992/0902    
 *  ask 8042 to reset the machine 
 */ 
1991/1210    
void 
1992/0902    
i8042reset(void) 
{ 
1997/1101    
	ushort *s = KADDR(0x472); 
1994/0923    
	int i, x; 
1994/0826    
 
	*s = 0x1234;		/* BIOS warm-boot flag */ 
 
1992/1013    
	/* 
1997/0327    
	 *  newer reset the machine command 
1992/1013    
	 */ 
1992/0902    
	outready(); 
1997/0327    
	outb(Cmd, 0xFE); 
1992/1013    
	outready(); 
1994/0923    
 
1992/1013    
	/* 
1994/0923    
	 *  Pulse it by hand (old somewhat reliable) 
1992/1013    
	 */ 
1994/0923    
	x = 0xDF; 
	for(i = 0; i < 5; i++){ 
		x ^= 1; 
		outready(); 
		outb(Cmd, 0xD1); 
		outready(); 
		outb(Data, x);	/* toggle reset */ 
		delay(100); 
	} 
1992/0902    
} 
 
1997/0327    
int 
i8042auxcmd(int cmd) 
1992/0904    
{ 
1997/0327    
	unsigned int c; 
	int tries; 
1992/0811    
 
1997/0327    
	c = 0; 
	tries = 0; 
1992/1020    
 
1997/0327    
	ilock(&i8042lock); 
	do{ 
		if(tries++ > 2) 
			break; 
		if(outready() < 0) 
			break; 
		outb(Cmd, 0xD4); 
		if(outready() < 0) 
			break; 
		outb(Data, cmd); 
		if(outready() < 0) 
			break; 
		if(inready() < 0) 
			break; 
		c = inb(Data); 
	} while(c == 0xFE || c == 0); 
	iunlock(&i8042lock); 
1992/0408    
 
1997/0327    
	if(c != 0xFA){ 
		print("i8042: %2.2ux returned to the %2.2ux command\n", c, cmd); 
		return -1; 
1993/1124    
	} 
	return 0; 
} 
 
1992/0904    
/* 
1993/1124    
 *  keyboard interrupt 
1992/0904    
 */ 
1992/1017    
static void 
1997/0327    
i8042intr(Ureg*, void*) 
1992/0904    
{ 
1994/0503    
	int s, c, i; 
1991/0703    
	static int esc1, esc2; 
1997/0327    
	static int alt, caps, ctl, num, shift; 
1994/0503    
	static int collecting, nk; 
1999/1005    
	static Rune kc[5]; 
1991/0703    
	int keyup; 
1991/0702    
 
1991/0703    
	/* 
1991/0731    
	 *  get status 
1991/0703    
	 */ 
1997/0327    
	lock(&i8042lock); 
1991/0730    
	s = inb(Status); 
1997/0327    
	if(!(s&Inready)){ 
		unlock(&i8042lock); 
1993/1124    
		return; 
1997/0327    
	} 
1991/0731    
 
	/* 
	 *  get the character 
	 */ 
1991/0703    
	c = inb(Data); 
1997/0327    
	unlock(&i8042lock); 
1991/0730    
 
	/* 
1997/0327    
	 *  if it's the aux port... 
1991/0730    
	 */ 
	if(s & Minready){ 
1997/0327    
		if(auxputc != nil) 
			auxputc(c, shift); 
1993/1124    
		return; 
1991/0730    
	} 
1991/0703    
 
	/* 
	 *  e0's is the first of a 2 character sequence 
	 */ 
	if(c == 0xe0){ 
		esc1 = 1; 
1993/1124    
		return; 
1991/0703    
	} else if(c == 0xe1){ 
		esc2 = 2; 
1993/1124    
		return; 
1991/0703    
	} 
 
1991/0822    
	keyup = c&0x80; 
	c &= 0x7f; 
	if(c > sizeof kbtab){ 
1998/0207    
		c |= keyup; 
		if(c != 0xFF)	/* these come fairly often: CAPSLOCK U Y */ 
			print("unknown key %ux\n", c); 
1993/1124    
		return; 
1991/0822    
	} 
 
1991/0703    
	if(esc1){ 
		c = kbtabesc1[c]; 
		esc1 = 0; 
	} else if(esc2){ 
		esc2--; 
1993/1124    
		return; 
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){ 
1995/0330    
		case Latin: 
			alt = 0; 
			break; 
1991/0703    
		case Shift: 
1997/0327    
			shift = 0; 
1991/0703    
			break; 
		case Ctrl: 
			ctl = 0; 
			break; 
		} 
1993/1124    
		return; 
1991/0703    
	} 
 
	/* 
 	 *  normal character 
	 */ 
1999/1005    
	if(!(c & (Spec|KF))){ 
1995/0330    
		if(ctl){ 
			if(alt && c == Del) 
				exit(0); 
1991/0703    
			c &= 0x1f; 
1995/0330    
		} 
1994/0503    
		if(!collecting){ 
1993/1113    
			kbdputc(kbdq, c); 
1994/0503    
			return; 
1991/0703    
		} 
1994/0503    
		kc[nk++] = c; 
		c = latin1(kc, nk); 
		if(c < -1)	/* need more keystrokes */ 
			return; 
		if(c != -1)	/* valid sequence */ 
			kbdputc(kbdq, c); 
		else	/* dump characters */ 
			for(i=0; i<nk; i++) 
				kbdputc(kbdq, kc[i]); 
		nk = 0; 
		collecting = 0; 
1993/1124    
		return; 
1991/0703    
	} else { 
		switch(c){ 
		case Caps: 
			caps ^= 1; 
1993/1124    
			return; 
1991/0703    
		case Num: 
			num ^= 1; 
1993/1124    
			return; 
1991/0703    
		case Shift: 
1997/0327    
			shift = 1; 
1993/1124    
			return; 
1991/0703    
		case Latin: 
1995/0330    
			alt = 1; 
1994/0503    
			collecting = 1; 
			nk = 0; 
2002/0417    
			/* 
			 * VMware uses Ctl-Alt as the key combination 
			 * to make the VM give up keyboard and mouse focus. 
			 * This has the unfortunate side effect that when you 
			 * come back into focus, Plan 9 thinks you want to type 
			 * a compose sequence (you just typed alt).  
			 * 
			 * As a clusmy hack around this, we look for ctl-alt 
			 * and don't treat it as the start of a compose sequence. 
			 */ 
			if(!ctl){ 
				collecting = 1; 
				nk = 0; 
			} 
1993/1124    
			return; 
1991/0703    
		case Ctrl: 
2002/0417    
			collecting = 0; 
			nk = 0; 
1991/0703    
			ctl = 1; 
1993/1124    
			return; 
1991/0703    
		} 
	} 
1993/1113    
	kbdputc(kbdq, c); 
1992/0222    
} 
 
1997/0327    
void 
i8042auxenable(void (*putc)(int, int)) 
1993/1124    
{ 
1997/0327    
	char *err = "i8042: aux init failed\n"; 
1993/1124    
 
1997/0327    
	/* enable kbd/aux xfers and interrupts */ 
	ccc &= ~Cauxdis; 
	ccc |= Cauxint; 
1993/1124    
 
1997/0327    
	ilock(&i8042lock); 
1993/1124    
	if(outready() < 0) 
1997/0327    
		print(err); 
	outb(Cmd, 0x60);			/* write control register */ 
1993/1124    
	if(outready() < 0) 
1997/0327    
		print(err); 
1993/1124    
	outb(Data, ccc); 
	if(outready() < 0) 
1997/0327    
		print(err); 
	outb(Cmd, 0xA8);			/* auxilliary device enable */ 
1994/0317    
	if(outready() < 0){ 
1997/0327    
		iunlock(&i8042lock); 
1994/0317    
		return; 
	} 
1997/0327    
	auxputc = putc; 
1999/0819    
	intrenable(IrqAUX, i8042intr, 0, BUSUNKNOWN, "kbdaux"); 
1997/0327    
	iunlock(&i8042lock); 
1993/1124    
} 
 
1992/0222    
void 
1993/1124    
kbdinit(void) 
1993/0915    
{ 
1993/1124    
	int c; 
1993/0915    
 
1993/1124    
	/* wait for a quiescent controller */ 
	while((c = inb(Status)) & (Outbusy | Inready)) 
		if(c & Inready) 
			inb(Data); 
 
	/* get current controller command byte */ 
	outb(Cmd, 0x20); 
	if(inready() < 0){ 
		print("kbdinit: can't read ccc\n"); 
		ccc = 0; 
	} else 
		ccc = inb(Data); 
 
	/* enable kbd xfers and interrupts */ 
1994/0322    
	/* disable mouse */ 
1993/1124    
	ccc &= ~Ckbddis; 
1997/0327    
	ccc |= Csf | Ckbdint | Cscs1; 
1993/1124    
	if(outready() < 0) 
		print("kbd init failed\n"); 
	outb(Cmd, 0x60); 
	if(outready() < 0) 
		print("kbd init failed\n"); 
	outb(Data, ccc); 
	outready(); 
2002/0411    
} 
 
void 
kbdenable(void) 
{ 
	kbdq = qopen(4*1024, 0, 0, 0); 
	if(kbdq == nil) 
		panic("kbdinit"); 
	qnoblock(kbdq, 1); 
 
	ioalloc(Data, 1, 0, "kbd"); 
	ioalloc(Cmd, 1, 0, "kbd"); 
 
	intrenable(IrqKBD, i8042intr, 0, BUSUNKNOWN, "kbd"); 
1991/0703    
} 


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