xref: /csrg-svn/sys/hp/dev/hil.c (revision 43316)
141480Smckusick /*
241480Smckusick  * Copyright (c) 1988 University of Utah.
341480Smckusick  * Copyright (c) 1990 The Regents of the University of California.
441480Smckusick  * All rights reserved.
541480Smckusick  *
641480Smckusick  * This code is derived from software contributed to Berkeley by
741480Smckusick  * the Systems Programming Group of the University of Utah Computer
841480Smckusick  * Science Department.
941480Smckusick  *
1041480Smckusick  * %sccs.include.redist.c%
1141480Smckusick  *
1241480Smckusick  * from: Utah $Hdr: hil.c 1.33 89/12/22$
1341480Smckusick  *
14*43316Smckusick  *	@(#)hil.c	7.3 (Berkeley) 06/20/90
1541480Smckusick  */
1641480Smckusick 
1741480Smckusick #include "param.h"
1841480Smckusick #include "conf.h"
1941480Smckusick #include "user.h"
2041480Smckusick #include "proc.h"
2141480Smckusick #include "ioctl.h"
2241480Smckusick #include "file.h"
2341480Smckusick #include "tty.h"
2441480Smckusick #include "systm.h"
2541480Smckusick #include "uio.h"
2641480Smckusick #include "kernel.h"
2741480Smckusick #include "mapmem.h"
2841480Smckusick 
2941480Smckusick #include "hilreg.h"
3041480Smckusick #include "hilioctl.h"
3141480Smckusick #include "hilvar.h"
3241480Smckusick #include "kbdmap.h"
3341480Smckusick 
3441480Smckusick #include "machine/cpu.h"
3541480Smckusick 
3641480Smckusick struct	hilloop	hil0;
3741480Smckusick struct	_hilbell default_bell = { BELLDUR, BELLFREQ };
3841480Smckusick 
3941480Smckusick #ifdef MAPMEM
4041480Smckusick int	hilqfork(), hilqvfork(), hilqexit();
4141480Smckusick struct	mapmemops hilqops = { hilqfork, hilqvfork, hilqexit, hilqexit };
4241480Smckusick #endif
4341480Smckusick 
4441480Smckusick #ifdef DEBUG
4541480Smckusick int 	hildebug = 0;
4641480Smckusick #define HDB_FOLLOW	0x01
4741480Smckusick #define HDB_MMAP	0x02
4841480Smckusick #define HDB_MASK	0x04
4941480Smckusick #define HDB_CONFIG	0x08
5041480Smckusick #define HDB_KEYBOARD	0x10
5141480Smckusick #define HDB_IDMODULE	0x20
5241480Smckusick #define HDB_EVENTS	0x80
5341480Smckusick #endif
5441480Smckusick 
5542360Smckusick /* symbolic sleep message strings */
5642360Smckusick char hilin[] = "hilin";
5742360Smckusick 
5841480Smckusick hilinit()
5941480Smckusick {
6041480Smckusick   	register struct hilloop *hilp = &hil0;	/* XXX */
6141480Smckusick 	register int i;
6241480Smckusick 
6341480Smckusick 	/*
6441480Smckusick 	 * Initialize loop information
6541480Smckusick 	 */
6641480Smckusick 	hilp->hl_addr = HILADDR;
6741480Smckusick 	hilp->hl_cmdending = FALSE;
6841480Smckusick 	hilp->hl_actdev = hilp->hl_cmddev = 0;
6941480Smckusick 	hilp->hl_cmddone = FALSE;
7041480Smckusick 	hilp->hl_cmdbp = hilp->hl_cmdbuf;
7141480Smckusick 	hilp->hl_pollbp = hilp->hl_pollbuf;
7241480Smckusick 	hilp->hl_kbddev = 0;
7341480Smckusick 	hilp->hl_kbdlang = KBD_DEFAULT;
7441480Smckusick 	hilp->hl_kbdflags = 0;
7541480Smckusick 	/*
7641480Smckusick 	 * Clear all queues and device associations with queues
7741480Smckusick 	 */
7841480Smckusick 	for (i = 0; i < NHILQ; i++) {
7941480Smckusick 		hilp->hl_queue[i].hq_eventqueue = NULL;
8041480Smckusick 		hilp->hl_queue[i].hq_procp = NULL;
8141480Smckusick 		hilp->hl_queue[i].hq_devmask = 0;
8241480Smckusick 	}
8341480Smckusick 	for (i = 0; i < NHILD; i++)
8441480Smckusick 		hilp->hl_device[i].hd_qmask = 0;
8541480Smckusick 	hilp->hl_device[HILLOOPDEV].hd_flags = (HIL_ALIVE|HIL_PSEUDO);
8641480Smckusick 	/*
8741480Smckusick 	 * Reset the loop hardware, and collect keyboard/id info
8841480Smckusick 	 */
8941480Smckusick 	hilreset(hilp);
9041480Smckusick 	hilinfo(hilp);
9141480Smckusick 	kbdenable();
9241480Smckusick }
9341480Smckusick 
9441480Smckusick hilopen(dev, flags)
9541480Smckusick 	dev_t dev;
9641480Smckusick {
97*43316Smckusick 	struct proc *p = u.u_procp;		/* XXX */
9841480Smckusick   	register struct hilloop *hilp = &hil0;	/* XXX */
9941480Smckusick 	register struct hilloopdev *dptr;
10041480Smckusick 	u_char device = HILUNIT(dev);
10141480Smckusick 
10241480Smckusick #ifdef DEBUG
10341480Smckusick 	if (hildebug & HDB_FOLLOW)
104*43316Smckusick 		printf("hilopen(%d): device %x\n", p->p_pid, device);
10541480Smckusick #endif
10641480Smckusick 
10741480Smckusick 	if ((hilp->hl_device[HILLOOPDEV].hd_flags & HIL_ALIVE) == 0)
10841480Smckusick 		return(ENXIO);
10941480Smckusick 
11041480Smckusick 	dptr = &hilp->hl_device[device];
11141480Smckusick 	if ((dptr->hd_flags & HIL_ALIVE) == 0)
11241480Smckusick 		return(ENODEV);
11341480Smckusick 
11441480Smckusick 	/*
11541480Smckusick 	 * Pseudo-devices cannot be read, nothing more to do.
11641480Smckusick 	 */
11741480Smckusick 	if (dptr->hd_flags & HIL_PSEUDO)
11841480Smckusick 		return(0);
11941480Smckusick 
12041480Smckusick 	/*
12141480Smckusick 	 * Open semantics:
12241480Smckusick 	 * 1.	Open devices have only one of HIL_READIN/HIL_QUEUEIN.
12341480Smckusick 	 * 2.	HPUX processes always get read syscall interface and
12441480Smckusick 	 *	must have exclusive use of the device.
12541480Smckusick 	 * 3.	BSD processes default to shared queue interface.
12641480Smckusick 	 *	Multiple processes can open the device.
12741480Smckusick 	 */
128*43316Smckusick 	if (p->p_flag & SHPUX) {
12941480Smckusick 		if (dptr->hd_flags & (HIL_READIN|HIL_QUEUEIN))
13041480Smckusick 			return(EBUSY);
13141480Smckusick 		dptr->hd_flags |= HIL_READIN;
13241480Smckusick 	} else {
13341480Smckusick 		if (dptr->hd_flags & HIL_READIN)
13441480Smckusick 			return(EBUSY);
13541480Smckusick 		dptr->hd_flags |= HIL_QUEUEIN;
13641480Smckusick 	}
13741480Smckusick 	if (flags & FNDELAY)
13841480Smckusick 		dptr->hd_flags |= HIL_NOBLOCK;
13941480Smckusick 	/*
14041480Smckusick 	 * It is safe to flush the read buffer as we are guarenteed
14141480Smckusick 	 * that no one else is using it.
14241480Smckusick 	 */
14341480Smckusick 	ndflush(&dptr->hd_queue, dptr->hd_queue.c_cc);
14441480Smckusick 
14541480Smckusick 	send_hil_cmd(hilp->hl_addr, HIL_INTON, NULL, 0, NULL);
14641480Smckusick 	/*
14741480Smckusick 	 * Opened the keyboard, put in raw mode.
14841480Smckusick 	 */
14941480Smckusick 	(void) splhil();
15041480Smckusick 	if (device == hilp->hl_kbddev) {
15141480Smckusick 		u_char mask = 0;
15241480Smckusick 		send_hil_cmd(hilp->hl_addr, HIL_WRITEKBDSADR, &mask, 1, NULL);
15341480Smckusick 		hilp->hl_kbdflags |= KBD_RAW;
15441480Smckusick #ifdef DEBUG
15541480Smckusick 		if (hildebug & HDB_KEYBOARD)
15641480Smckusick 			printf("hilopen: keyboard %d raw\n", hilp->hl_kbddev);
15741480Smckusick #endif
15841480Smckusick 	}
15941480Smckusick 	(void) spl0();
16041480Smckusick 	return (0);
16141480Smckusick }
16241480Smckusick 
16341480Smckusick /* ARGSUSED */
16441480Smckusick hilclose(dev, flags)
16541480Smckusick 	dev_t dev;
16641480Smckusick {
167*43316Smckusick 	struct proc *p = u.u_procp;		/* XXX */
16841480Smckusick   	register struct hilloop *hilp = &hil0;	/* XXX */
16941480Smckusick 	register struct hilloopdev *dptr;
17041480Smckusick 	register int i;
17141480Smckusick 	u_char device = HILUNIT(dev);
17241480Smckusick 	char mask, lpctrl;
17341480Smckusick 
17441480Smckusick #ifdef DEBUG
17541480Smckusick 	if (hildebug & HDB_FOLLOW)
176*43316Smckusick 		printf("hilclose(%d): device %x\n", p->p_pid, device);
17741480Smckusick #endif
17841480Smckusick 
17941480Smckusick 	dptr = &hilp->hl_device[device];
18041480Smckusick 	if (device && (dptr->hd_flags & HIL_PSEUDO))
18141480Smckusick 		return (0);
18241480Smckusick 
183*43316Smckusick 	if ((p->p_flag & SHPUX) == 0) {
18441480Smckusick 		/*
18541480Smckusick 		 * If this is the loop device,
18641480Smckusick 		 * free up all queues belonging to this process.
18741480Smckusick 		 */
18841480Smckusick 		if (device == 0) {
18941480Smckusick 			for (i = 0; i < NHILQ; i++)
190*43316Smckusick 				if (hilp->hl_queue[i].hq_procp == p)
19141480Smckusick 					(void) hilqfree(i);
19241480Smckusick 		} else {
19341480Smckusick 			mask = ~hildevmask(device);
19441480Smckusick 			(void) splhil();
19541480Smckusick 			for (i = 0; i < NHILQ; i++)
196*43316Smckusick 				if (hilp->hl_queue[i].hq_procp == p) {
19741480Smckusick 					dptr->hd_qmask &= ~hilqmask(i);
19841480Smckusick 					hilp->hl_queue[i].hq_devmask &= mask;
19941480Smckusick 				}
20041480Smckusick 			(void) spl0();
20141480Smckusick 		}
20241480Smckusick 	}
20341480Smckusick 	/*
20441480Smckusick 	 * Always flush the read buffer
20541480Smckusick 	 */
20641480Smckusick 	dptr->hd_flags &= ~(HIL_QUEUEIN|HIL_READIN|HIL_NOBLOCK);
20741480Smckusick 	ndflush(&dptr->hd_queue, dptr->hd_queue.c_cc);
20841480Smckusick 	/*
20941480Smckusick 	 * Set keyboard back to cooked mode when closed.
21041480Smckusick 	 */
21141480Smckusick 	(void) splhil();
21241480Smckusick 	if (device && device == hilp->hl_kbddev) {
21341480Smckusick 		mask = 1 << (hilp->hl_kbddev - 1);
21441480Smckusick 		send_hil_cmd(hilp->hl_addr, HIL_WRITEKBDSADR, &mask, 1, NULL);
21541480Smckusick 		hilp->hl_kbdflags &= ~(KBD_RAW|KBD_AR1|KBD_AR2);
21641480Smckusick 		/*
21741480Smckusick 		 * XXX: We have had trouble with keyboards remaining raw
21841480Smckusick 		 * after close due to the LPC_KBDCOOK bit getting cleared
21941480Smckusick 		 * somewhere along the line.  Hence we check and reset
22041480Smckusick 		 * LPCTRL if necessary.
22141480Smckusick 		 */
22241480Smckusick 		send_hil_cmd(hilp->hl_addr, HIL_READLPCTRL, NULL, 0, &lpctrl);
22341480Smckusick 		if ((lpctrl & LPC_KBDCOOK) == 0) {
22441480Smckusick 			printf("hilclose: bad LPCTRL %x, reset to %x\n",
22541480Smckusick 			       lpctrl, lpctrl|LPC_KBDCOOK);
22641480Smckusick 			lpctrl |= LPC_KBDCOOK;
22741480Smckusick 			send_hil_cmd(hilp->hl_addr, HIL_WRITELPCTRL,
22841480Smckusick 					&lpctrl, 1, NULL);
22941480Smckusick 		}
23041480Smckusick #ifdef DEBUG
23141480Smckusick 		if (hildebug & HDB_KEYBOARD)
23241480Smckusick 			printf("hilclose: keyboard %d cooked\n",
23341480Smckusick 			       hilp->hl_kbddev);
23441480Smckusick #endif
23541480Smckusick 		kbdenable();
23641480Smckusick 	}
23741480Smckusick 	(void) spl0();
23841480Smckusick 	return (0);
23941480Smckusick }
24041480Smckusick 
24141480Smckusick /*
24241480Smckusick  * Read interface to HIL device.
24341480Smckusick  */
24441480Smckusick hilread(dev, uio)
24541480Smckusick 	dev_t dev;
24641480Smckusick 	register struct uio *uio;
24741480Smckusick {
24841480Smckusick 	struct hilloop *hilp = &hil0;		/* XXX */
24941480Smckusick 	register struct hilloopdev *dptr;
25041480Smckusick 	register int cc;
25141480Smckusick 	u_char device = HILUNIT(dev);
25241480Smckusick 	char buf[HILBUFSIZE];
25341480Smckusick 	int error;
25441480Smckusick 
25541480Smckusick #if 0
25641480Smckusick 	/*
25741480Smckusick 	 * XXX: Don't do this since HP-UX doesn't.
25841480Smckusick 	 *
25941480Smckusick 	 * Check device number.
26041480Smckusick 	 * This check is necessary since loop can reconfigure.
26141480Smckusick 	 */
26241480Smckusick 	if (device > hilp->hl_maxdev)
26341480Smckusick 		return(ENODEV);
26441480Smckusick #endif
26541480Smckusick 
26641480Smckusick 	dptr = &hilp->hl_device[device];
26741480Smckusick 	if ((dptr->hd_flags & HIL_READIN) == 0)
26841480Smckusick 		return(ENODEV);
26941480Smckusick 
27041480Smckusick 	(void) splhil();
27141480Smckusick 	while (dptr->hd_queue.c_cc == 0) {
27241480Smckusick 		if (dptr->hd_flags & HIL_NOBLOCK) {
27341480Smckusick 			spl0();
27441480Smckusick 			return(EWOULDBLOCK);
27541480Smckusick 		}
27641480Smckusick 		dptr->hd_flags |= HIL_ASLEEP;
27742360Smckusick 		if (error = tsleep((caddr_t)dptr, TTIPRI | PCATCH, hilin, 0)) {
27842360Smckusick 			(void) spl0();
27942360Smckusick 			return (error);
28042360Smckusick 		}
28141480Smckusick 	}
28241480Smckusick 	(void) spl0();
28341480Smckusick 
28441480Smckusick 	error = 0;
28541480Smckusick 	while (uio->uio_resid > 0 && error == 0) {
28641480Smckusick 		cc = hilq_to_b(&dptr->hd_queue, buf,
28741480Smckusick 			       MIN(uio->uio_resid, HILBUFSIZE));
28841480Smckusick 		if (cc <= 0)
28941480Smckusick 			break;
29041480Smckusick 		error = uiomove(buf, cc, uio);
29141480Smckusick 	}
29241480Smckusick 	return(error);
29341480Smckusick }
29441480Smckusick 
29541480Smckusick hilioctl(dev, cmd, data, flag)
29641480Smckusick 	dev_t dev;
29741480Smckusick 	caddr_t data;
29841480Smckusick {
299*43316Smckusick 	struct proc *p = u.u_procp;		/* XXX */
30041480Smckusick 	register struct hilloop *hilp = &hil0;	/* XXX */
30141480Smckusick 	char device = HILUNIT(dev);
30241480Smckusick 	struct hilloopdev *dptr;
30341480Smckusick 	register int i;
30441480Smckusick 	u_char hold;
30541480Smckusick 	int error;
30641480Smckusick 
30741480Smckusick #ifdef DEBUG
30841480Smckusick 	if (hildebug & HDB_FOLLOW)
30941480Smckusick 		printf("hilioctl(%d): dev %x cmd %x\n",
310*43316Smckusick 		       p->p_pid, device, cmd);
31141480Smckusick #endif
31241480Smckusick 
31341480Smckusick 	dptr = &hilp->hl_device[device];
31441480Smckusick 	if ((dptr->hd_flags & HIL_ALIVE) == 0)
31541480Smckusick 		return (ENODEV);
31641480Smckusick 
31741480Smckusick 	/*
31841480Smckusick 	 * Don't allow hardware ioctls on virtual devices.
31941480Smckusick 	 * Note that though these are the BSD names, they have the same
32041480Smckusick 	 * values as the HP-UX equivalents so we catch them as well.
32141480Smckusick 	 */
32241480Smckusick 	if (dptr->hd_flags & HIL_PSEUDO) {
32341480Smckusick 		switch (cmd) {
32441480Smckusick 		case HILIOCSC:
32541480Smckusick 		case HILIOCID:
32641480Smckusick 		case HILIOCRN:
32741480Smckusick 		case HILIOCRS:
32841480Smckusick 		case HILIOCED:
32941480Smckusick 			return(ENODEV);
33041480Smckusick 
33141480Smckusick 		/*
33241480Smckusick 		 * XXX: should also return ENODEV but HP-UX compat
33341480Smckusick 		 * breaks if we do.  They work ok right now because
33441480Smckusick 		 * we only recognize one keyboard on the loop.  This
33541480Smckusick 		 * will have to change if we remove that restriction.
33641480Smckusick 		 */
33741480Smckusick 		case HILIOCAROFF:
33841480Smckusick 		case HILIOCAR1:
33941480Smckusick 		case HILIOCAR2:
34041480Smckusick 			break;
34141480Smckusick 
34241480Smckusick 		default:
34341480Smckusick 			break;
34441480Smckusick 		}
34541480Smckusick 	}
34641480Smckusick 
34741480Smckusick #ifdef HPUXCOMPAT
348*43316Smckusick 	if (p->p_flag & SHPUX)
34941480Smckusick 		return(hpuxhilioctl(dev, cmd, data, flag));
35041480Smckusick #endif
35141480Smckusick 
35241480Smckusick 	hilp->hl_cmdbp = hilp->hl_cmdbuf;
35341480Smckusick 	bzero((caddr_t)hilp->hl_cmdbuf, HILBUFSIZE);
35441480Smckusick 	hilp->hl_cmddev = device;
35541480Smckusick 	error = 0;
35641480Smckusick 	switch (cmd) {
35741480Smckusick 
35841480Smckusick 	case HILIOCSBP:
35941480Smckusick 		/* Send four data bytes to the tone gererator. */
36041480Smckusick 		send_hil_cmd(hilp->hl_addr, HIL_STARTCMD, data, 4, NULL);
36141480Smckusick 		/* Send the trigger beeper command to the 8042. */
36241480Smckusick 		send_hil_cmd(hilp->hl_addr, (cmd & 0xFF), NULL, 0, NULL);
36341480Smckusick 		break;
36441480Smckusick 
36541480Smckusick 	case HILIOCRRT:
36641480Smckusick 		/* Transfer the real time to the 8042 data buffer */
36741480Smckusick 		send_hil_cmd(hilp->hl_addr, (cmd & 0xFF), NULL, 0, NULL);
36841480Smckusick 		/* Read each byte of the real time */
36941480Smckusick 		for (i = 0; i < 5; i++) {
37041480Smckusick 			send_hil_cmd(hilp->hl_addr, HIL_READTIME + i, NULL,
37141480Smckusick 					0, &hold);
37241480Smckusick 			data[4-i] = hold;
37341480Smckusick 		}
37441480Smckusick 		break;
37541480Smckusick 
37641480Smckusick 	case HILIOCRT:
37741480Smckusick 		for (i = 0; i < 4; i++) {
37841480Smckusick 			send_hil_cmd(hilp->hl_addr, (cmd & 0xFF) + i,
37941480Smckusick 					NULL, 0, &hold);
38041480Smckusick 			data[i] = hold;
38141480Smckusick 		}
38241480Smckusick 		break;
38341480Smckusick 
38441480Smckusick 	case HILIOCID:
38541480Smckusick 	case HILIOCSC:
38641480Smckusick 	case HILIOCRN:
38741480Smckusick 	case HILIOCRS:
38841480Smckusick 	case HILIOCED:
38941480Smckusick 	  	send_hildev_cmd(hilp, device, (cmd & 0xFF));
39041480Smckusick 		bcopy(hilp->hl_cmdbuf, data, hilp->hl_cmdbp-hilp->hl_cmdbuf);
39141480Smckusick 	  	break;
39241480Smckusick 
39341480Smckusick         case HILIOCAROFF:
39441480Smckusick         case HILIOCAR1:
39541480Smckusick         case HILIOCAR2:
39641480Smckusick 		if (hilp->hl_kbddev) {
39741480Smckusick 			hilp->hl_cmddev = hilp->hl_kbddev;
39841480Smckusick 			send_hildev_cmd(hilp, hilp->hl_kbddev, (cmd & 0xFF));
39941480Smckusick 			hilp->hl_kbdflags &= ~(KBD_AR1|KBD_AR2);
40041480Smckusick 			if (cmd == HILIOCAR1)
40141480Smckusick 				hilp->hl_kbdflags |= KBD_AR1;
40241480Smckusick 			else if (cmd == HILIOCAR2)
40341480Smckusick 				hilp->hl_kbdflags |= KBD_AR2;
40441480Smckusick 		}
40541480Smckusick 		break;
40641480Smckusick 
40741480Smckusick 	case HILIOCBEEP:
40841480Smckusick 		hilbeep(hilp, (struct _hilbell *)data);
40941480Smckusick 		break;
41041480Smckusick 
41141480Smckusick 	case FIONBIO:
41241480Smckusick 		dptr = &hilp->hl_device[device];
41341480Smckusick 		if (*(int *)data)
41441480Smckusick 			dptr->hd_flags |= HIL_NOBLOCK;
41541480Smckusick 		else
41641480Smckusick 			dptr->hd_flags &= ~HIL_NOBLOCK;
41741480Smckusick 		break;
41841480Smckusick 
41941480Smckusick 	/*
42041480Smckusick 	 * FIOASYNC must be present for FIONBIO above to work!
42141480Smckusick 	 * (See fcntl in kern_descrip.c).
42241480Smckusick 	 */
42341480Smckusick 	case FIOASYNC:
42441480Smckusick 		break;
42541480Smckusick 
42641480Smckusick         case HILIOCALLOCQ:
42741480Smckusick 		error = hilqalloc((struct hilqinfo *)data);
42841480Smckusick 		break;
42941480Smckusick 
43041480Smckusick         case HILIOCFREEQ:
43141480Smckusick 		error = hilqfree(((struct hilqinfo *)data)->qid);
43241480Smckusick 		break;
43341480Smckusick 
43441480Smckusick         case HILIOCMAPQ:
43541480Smckusick 		error = hilqmap(*(int *)data, device);
43641480Smckusick 		break;
43741480Smckusick 
43841480Smckusick         case HILIOCUNMAPQ:
43941480Smckusick 		error = hilqunmap(*(int *)data, device);
44041480Smckusick 		break;
44141480Smckusick 
44241480Smckusick 	case HILIOCHPUX:
44341480Smckusick 		dptr = &hilp->hl_device[device];
44441480Smckusick 		dptr->hd_flags |= HIL_READIN;
44541480Smckusick 		dptr->hd_flags &= ~HIL_QUEUEIN;
44641480Smckusick 		break;
44741480Smckusick 
44841480Smckusick         case HILIOCRESET:
44941480Smckusick 	        hilreset(hilp);
45041480Smckusick 		break;
45141480Smckusick 
45241480Smckusick #ifdef DEBUG
45341480Smckusick         case HILIOCTEST:
45441480Smckusick 		hildebug = *(int *) data;
45541480Smckusick 		break;
45641480Smckusick #endif
45741480Smckusick 
45841480Smckusick         default:
45941480Smckusick 		error = EINVAL;
46041480Smckusick 		break;
46141480Smckusick 
46241480Smckusick 	}
46341480Smckusick 	hilp->hl_cmddev = 0;
46441480Smckusick 	return(error);
46541480Smckusick }
46641480Smckusick 
46741480Smckusick #ifdef HPUXCOMPAT
46841480Smckusick /* ARGSUSED */
46941480Smckusick hpuxhilioctl(dev, cmd, data, flag)
47041480Smckusick 	dev_t dev;
47141480Smckusick 	caddr_t data;
47241480Smckusick {
47341480Smckusick 	register struct hilloop *hilp = &hil0;	/* XXX */
47441480Smckusick 	char device = HILUNIT(dev);
47541480Smckusick 	struct hilloopdev *dptr;
47641480Smckusick 	register int i;
47741480Smckusick 	u_char hold;
47841480Smckusick 
47941480Smckusick 	hilp->hl_cmdbp = hilp->hl_cmdbuf;
48041480Smckusick 	bzero((caddr_t)hilp->hl_cmdbuf, HILBUFSIZE);
48141480Smckusick 	hilp->hl_cmddev = device;
48241480Smckusick 	switch (cmd) {
48341480Smckusick 
48441480Smckusick 	case HILSC:
48541480Smckusick 	case HILID:
48641480Smckusick 	case HILRN:
48741480Smckusick 	case HILRS:
48841480Smckusick 	case HILED:
48941480Smckusick 	case HILP1:
49041480Smckusick 	case HILP2:
49141480Smckusick 	case HILP3:
49241480Smckusick 	case HILP4:
49341480Smckusick 	case HILP5:
49441480Smckusick 	case HILP6:
49541480Smckusick 	case HILP7:
49641480Smckusick 	case HILP:
49741480Smckusick 	case HILA1:
49841480Smckusick 	case HILA2:
49941480Smckusick 	case HILA3:
50041480Smckusick 	case HILA4:
50141480Smckusick 	case HILA5:
50241480Smckusick 	case HILA6:
50341480Smckusick 	case HILA7:
50441480Smckusick 	case HILA:
50541480Smckusick 		send_hildev_cmd(hilp, device, (cmd & 0xFF));
50641480Smckusick 		bcopy(hilp->hl_cmdbuf, data, hilp->hl_cmdbp-hilp->hl_cmdbuf);
50741480Smckusick 	  	break;
50841480Smckusick 
50941480Smckusick         case HILDKR:
51041480Smckusick         case HILER1:
51141480Smckusick         case HILER2:
51241480Smckusick 		if (hilp->hl_kbddev) {
51341480Smckusick 			hilp->hl_cmddev = hilp->hl_kbddev;
51441480Smckusick 			send_hildev_cmd(hilp, hilp->hl_kbddev, (cmd & 0xFF));
51541480Smckusick 			hilp->hl_kbdflags &= ~(KBD_AR1|KBD_AR2);
51641480Smckusick 			if (cmd == HILIOCAR1)
51741480Smckusick 				hilp->hl_kbdflags |= KBD_AR1;
51841480Smckusick 			else if (cmd == HILIOCAR2)
51941480Smckusick 				hilp->hl_kbdflags |= KBD_AR2;
52041480Smckusick 		}
52141480Smckusick 		break;
52241480Smckusick 
52341480Smckusick 	case EFTSBP:
52441480Smckusick 		/* Send four data bytes to the tone gererator. */
52541480Smckusick 		send_hil_cmd(hilp->hl_addr, HIL_STARTCMD, data, 4, NULL);
52641480Smckusick 		/* Send the trigger beeper command to the 8042. */
52741480Smckusick 		send_hil_cmd(hilp->hl_addr, (cmd & 0xFF), NULL, 0, NULL);
52841480Smckusick 		break;
52941480Smckusick 
53041480Smckusick 	case EFTRRT:
53141480Smckusick 		/* Transfer the real time to the 8042 data buffer */
53241480Smckusick 		send_hil_cmd(hilp->hl_addr, (cmd & 0xFF), NULL, 0, NULL);
53341480Smckusick 		/* Read each byte of the real time */
53441480Smckusick 		for (i = 0; i < 5; i++) {
53541480Smckusick 			send_hil_cmd(hilp->hl_addr, HIL_READTIME + i, NULL,
53641480Smckusick 					0, &hold);
53741480Smckusick 			data[4-i] = hold;
53841480Smckusick 		}
53941480Smckusick 		break;
54041480Smckusick 
54141480Smckusick 	case EFTRT:
54241480Smckusick 		for (i = 0; i < 4; i++) {
54341480Smckusick 			send_hil_cmd(hilp->hl_addr, (cmd & 0xFF) + i,
54441480Smckusick 					NULL, 0, &hold);
54541480Smckusick 			data[i] = hold;
54641480Smckusick 		}
54741480Smckusick 		break;
54841480Smckusick 
54941480Smckusick         case EFTRLC:
55041480Smckusick         case EFTRCC:
55141480Smckusick 		send_hil_cmd(hilp->hl_addr, (cmd & 0xFF), NULL, 0, &hold);
55241480Smckusick 		*data = hold;
55341480Smckusick 		break;
55441480Smckusick 
55541480Smckusick         case EFTSRPG:
55641480Smckusick         case EFTSRD:
55741480Smckusick         case EFTSRR:
55841480Smckusick 		send_hil_cmd(hilp->hl_addr, (cmd & 0xFF), data, 1, NULL);
55941480Smckusick 		break;
56041480Smckusick 
56141480Smckusick 	case EFTSBI:
56241480Smckusick 		hilbeep(hilp, (struct _hilbell *)data);
56341480Smckusick 		break;
56441480Smckusick 
56541480Smckusick 	case FIONBIO:
56641480Smckusick 		dptr = &hilp->hl_device[device];
56741480Smckusick 		if (*(int *)data)
56841480Smckusick 			dptr->hd_flags |= HIL_NOBLOCK;
56941480Smckusick 		else
57041480Smckusick 			dptr->hd_flags &= ~HIL_NOBLOCK;
57141480Smckusick 		break;
57241480Smckusick 
57341480Smckusick 	case FIOASYNC:
57441480Smckusick 		break;
57541480Smckusick 
57641480Smckusick         default:
57741480Smckusick 		hilp->hl_cmddev = 0;
57841480Smckusick 		return(EINVAL);
57941480Smckusick 	}
58041480Smckusick 	hilp->hl_cmddev = 0;
58141480Smckusick 	return(0);
58241480Smckusick }
58341480Smckusick #endif
58441480Smckusick 
58541480Smckusick /*
58641480Smckusick  * XXX: the mmap inteface for HIL devices should be rethought.
58741480Smckusick  * We used it only briefly in conjuntion with shared queues
58841480Smckusick  * (instead of HILIOCMAPQ ioctl).  Perhaps mmap()ing a device
58941480Smckusick  * should give a single queue per process.
59041480Smckusick  */
59141480Smckusick /* ARGSUSED */
59241480Smckusick hilmap(dev, off, prot)
59341480Smckusick 	dev_t dev;
59441480Smckusick 	register int off;
59541480Smckusick {
596*43316Smckusick 	struct proc *p = u.u_procp;		/* XXX */
59741480Smckusick #ifdef MMAP
59841480Smckusick 	register struct hilloop *hilp = &hil0;	/* XXX */
59941480Smckusick 	register struct hiliqueue *qp;
60041480Smckusick 	register int qnum;
60141480Smckusick 
60241480Smckusick 	/*
60341480Smckusick 	 * Only allow mmap() on loop device
60441480Smckusick 	 */
60541480Smckusick 	if (HILUNIT(dev) != 0 || off >= NHILQ*sizeof(HILQ))
60641480Smckusick 		return(-1);
60741480Smckusick 	/*
60841480Smckusick 	 * Determine which queue we want based on the offset.
60941480Smckusick 	 * Queue must belong to calling process.
61041480Smckusick 	 */
61141480Smckusick 	qp = &hilp->hl_queue[off / sizeof(HILQ)];
612*43316Smckusick 	if (qp->hq_procp != p)
61341480Smckusick 		return(-1);
61441480Smckusick 
61541480Smckusick 	off %= sizeof(HILQ);
61641480Smckusick 	return(kvtop((u_int)qp->hq_eventqueue + off) >> PGSHIFT);
61741480Smckusick #endif
61841480Smckusick }
61941480Smckusick 
62041480Smckusick /*ARGSUSED*/
62141480Smckusick hilselect(dev, rw)
62241480Smckusick 	dev_t dev;
62341480Smckusick {
624*43316Smckusick 	struct proc *p = u.u_procp;		/* XXX */
62541480Smckusick 	register struct hilloop *hilp = &hil0;	/* XXX */
62641480Smckusick 	register struct hilloopdev *dptr;
62741480Smckusick 	register struct hiliqueue *qp;
62841480Smckusick 	register int mask;
62941480Smckusick 	int s, device;
63041480Smckusick 
63141480Smckusick 	if (rw == FWRITE)
63241480Smckusick 		return (1);
63341480Smckusick 	device = HILUNIT(dev);
63441480Smckusick 
63541480Smckusick 	/*
63641480Smckusick 	 * Read interface.
63741480Smckusick 	 * Return 1 if there is something in the queue, 0 ow.
63841480Smckusick 	 */
63941480Smckusick 	dptr = &hilp->hl_device[device];
64041480Smckusick 	if (dptr->hd_flags & HIL_READIN) {
64141480Smckusick 		s = splhil();
64241480Smckusick 		if (dptr->hd_queue.c_cc) {
64341480Smckusick 			splx(s);
64441480Smckusick 			return (1);
64541480Smckusick 		}
64641480Smckusick 		if (dptr->hd_selr &&
64741480Smckusick 		    dptr->hd_selr->p_wchan == (caddr_t)&selwait)
64841480Smckusick 			dptr->hd_flags |= HIL_SELCOLL;
64941480Smckusick 		else
650*43316Smckusick 			dptr->hd_selr = p;
65141480Smckusick 		splx(s);
65241480Smckusick 		return (0);
65341480Smckusick 	}
65441480Smckusick 
65541480Smckusick 	/*
65641480Smckusick 	 * Make sure device is alive and real (or the loop device).
65741480Smckusick 	 * Note that we do not do this for the read interface.
65841480Smckusick 	 * This is primarily to be consistant with HP-UX.
65941480Smckusick 	 */
66041480Smckusick 	if (device && (dptr->hd_flags & (HIL_ALIVE|HIL_PSEUDO)) != HIL_ALIVE)
66141480Smckusick 		return (1);
66241480Smckusick 
66341480Smckusick 	/*
66441480Smckusick 	 * Select on loop device is special.
66541480Smckusick 	 * Check to see if there are any data for any loop device
66641480Smckusick 	 * provided it is associated with a queue belonging to this user.
66741480Smckusick 	 */
66841480Smckusick 	if (device == 0)
66941480Smckusick 		mask = -1;
67041480Smckusick 	else
67141480Smckusick 		mask = hildevmask(device);
67241480Smckusick 	/*
67341480Smckusick 	 * Must check everybody with interrupts blocked to prevent races.
67441480Smckusick 	 */
67541480Smckusick 	s = splhil();
67641480Smckusick 	for (qp = hilp->hl_queue; qp < &hilp->hl_queue[NHILQ]; qp++)
677*43316Smckusick 		if (qp->hq_procp == p && (mask & qp->hq_devmask) &&
67841480Smckusick 		    qp->hq_eventqueue->hil_evqueue.head !=
67941480Smckusick 		    qp->hq_eventqueue->hil_evqueue.tail) {
68041480Smckusick 			splx(s);
68141480Smckusick 			return (1);
68241480Smckusick 		}
68341480Smckusick 
68441480Smckusick 	if (dptr->hd_selr && dptr->hd_selr->p_wchan == (caddr_t)&selwait)
68541480Smckusick 		dptr->hd_flags |= HIL_SELCOLL;
68641480Smckusick 	else
687*43316Smckusick 		dptr->hd_selr = p;
68841480Smckusick 	splx(s);
68941480Smckusick 	return (0);
69041480Smckusick }
69141480Smckusick 
69241480Smckusick hilint()
69341480Smckusick {
69441480Smckusick 	struct hilloop *hilp = &hil0;		/* XXX */
69541480Smckusick 	register struct hil_dev *hildevice = hilp->hl_addr;
69641480Smckusick 	u_char c, stat;
69741480Smckusick 
69841480Smckusick 	stat = hildevice->hil_stat;
69941480Smckusick 	c = hildevice->hil_data;		/* clears interrupt */
70041480Smckusick 	hil_process_int(stat, c);
70141480Smckusick }
70241480Smckusick 
70341480Smckusick #include "ite.h"
70441480Smckusick 
70541480Smckusick hil_process_int(stat, c)
70641480Smckusick 	register u_char stat, c;
70741480Smckusick {
70841480Smckusick   	register struct hilloop *hilp;
70941480Smckusick 
71041480Smckusick #ifdef DEBUG
71141480Smckusick 	if (hildebug & HDB_EVENTS)
71241480Smckusick 		printf("hilint: %x %x\n", stat, c);
71341480Smckusick #endif
71441480Smckusick 
71541480Smckusick 	/* the shift enables the compiler to generate a jump table */
71641480Smckusick 	switch ((stat>>HIL_SSHIFT) & HIL_SMASK) {
71741480Smckusick 
71841480Smckusick #if NITE > 0
71941480Smckusick 	case HIL_KEY:
72041480Smckusick 	case HIL_SHIFT:
72141480Smckusick 	case HIL_CTRL:
72241480Smckusick 	case HIL_CTRLSHIFT:
72341480Smckusick 		itefilter(stat, c);
72441480Smckusick 		return;
72541480Smckusick #endif
72641480Smckusick 
72741480Smckusick 	case HIL_STATUS:			/* The status info. */
72841480Smckusick 		hilp = &hil0;			/* XXX */
72941480Smckusick 		if (c & HIL_ERROR) {
73041480Smckusick 		  	hilp->hl_cmddone = TRUE;
73141480Smckusick 			if (c == HIL_RECONFIG)
73241480Smckusick 				hilconfig(hilp);
73341480Smckusick 			break;
73441480Smckusick 		}
73541480Smckusick 		if (c & HIL_COMMAND) {
73641480Smckusick 		  	if (c & HIL_POLLDATA)	/* End of data */
73741480Smckusick 				hilevent(hilp);
73841480Smckusick 			else			/* End of command */
73941480Smckusick 			  	hilp->hl_cmdending = TRUE;
74041480Smckusick 			hilp->hl_actdev = 0;
74141480Smckusick 		} else {
74241480Smckusick 		  	if (c & HIL_POLLDATA) {	/* Start of polled data */
74341480Smckusick 			  	if (hilp->hl_actdev != 0)
74441480Smckusick 					hilevent(hilp);
74541480Smckusick 				hilp->hl_actdev = (c & HIL_DEVMASK);
74641480Smckusick 				hilp->hl_pollbp = hilp->hl_pollbuf;
74741480Smckusick 			} else {		/* Start of command */
74841480Smckusick 				if (hilp->hl_cmddev == (c & HIL_DEVMASK)) {
74941480Smckusick 					hilp->hl_cmdbp = hilp->hl_cmdbuf;
75041480Smckusick 					hilp->hl_actdev = 0;
75141480Smckusick 				}
75241480Smckusick 			}
75341480Smckusick 		}
75441480Smckusick 	        return;
75541480Smckusick 
75641480Smckusick 	case HIL_DATA:
75741480Smckusick 		hilp = &hil0;			/* XXX */
75841480Smckusick 		if (hilp->hl_actdev != 0)	/* Collecting poll data */
75941480Smckusick 			*hilp->hl_pollbp++ = c;
76041480Smckusick 		else if (hilp->hl_cmddev != 0)  /* Collecting cmd data */
76141480Smckusick 			if (hilp->hl_cmdending) {
76241480Smckusick 				hilp->hl_cmddone = TRUE;
76341480Smckusick 				hilp->hl_cmdending = FALSE;
76441480Smckusick 			} else
76541480Smckusick 				*hilp->hl_cmdbp++ = c;
76641480Smckusick 		return;
76741480Smckusick 
76841480Smckusick 	case 0:		/* force full jump table */
76941480Smckusick 	default:
77041480Smckusick 		return;
77141480Smckusick 	}
77241480Smckusick }
77341480Smckusick 
77441480Smckusick #if defined(DEBUG) && !defined(PANICBUTTON)
77541480Smckusick #define PANICBUTTON
77641480Smckusick #endif
77741480Smckusick 
77841480Smckusick /*
77941480Smckusick  * Optimized macro to compute:
78041480Smckusick  *	eq->head == (eq->tail + 1) % eq->size
78141480Smckusick  * i.e. has tail caught up with head.  We do this because 32 bit long
78241480Smckusick  * remaidering is expensive (a function call with our compiler).
78341480Smckusick  */
78441480Smckusick #define HQFULL(eq)	(((eq)->head?(eq)->head:(eq)->size) == (eq)->tail+1)
78541480Smckusick #define HQVALID(eq) \
78641480Smckusick 	((eq)->size == HEVQSIZE && (eq)->tail >= 0 && (eq)->tail < HEVQSIZE)
78741480Smckusick 
78841480Smckusick hilevent(hilp)
78941480Smckusick 	struct hilloop *hilp;
79041480Smckusick {
79141480Smckusick 	register struct hilloopdev *dptr = &hilp->hl_device[hilp->hl_actdev];
79241480Smckusick 	register int len, mask, qnum;
79341480Smckusick 	register u_char *cp, *pp;
79441480Smckusick 	register HILQ *hq;
79541480Smckusick 	struct timeval ourtime;
79641480Smckusick 	hil_packet *proto;
79741480Smckusick 	int s, len0;
79841480Smckusick 	long tenths;
79941480Smckusick 
80041480Smckusick #ifdef PANICBUTTON
80141480Smckusick 	static int first;
80241480Smckusick 	extern int panicbutton;
80341480Smckusick 
80441480Smckusick 	cp = hilp->hl_pollbuf;
80541480Smckusick 	if (panicbutton && (*cp & HIL_KBDDATA)) {
80641480Smckusick 		if (*++cp == 0x4E)
80741480Smckusick 			first = 1;
80841480Smckusick 		else if (first && *cp == 0x46 && !panicstr)
80941480Smckusick 			panic("are we having fun yet?");
81041480Smckusick 		else
81141480Smckusick 			first = 0;
81241480Smckusick 	}
81341480Smckusick #endif
81441480Smckusick #ifdef DEBUG
81541480Smckusick 	if (hildebug & HDB_EVENTS) {
81641480Smckusick 		printf("hilevent: dev %d pollbuf: ", hilp->hl_actdev);
81741480Smckusick 		printhilpollbuf(hilp);
81841480Smckusick 		printf("\n");
81941480Smckusick 	}
82041480Smckusick #endif
82141480Smckusick 
82241480Smckusick 	/*
82341480Smckusick 	 * Note that HIL_READIN effectively "shuts off" any queues
82441480Smckusick 	 * that may have been in use at the time of an HILIOCHPUX call.
82541480Smckusick 	 */
82641480Smckusick 	if (dptr->hd_flags & HIL_READIN) {
82741480Smckusick 		hpuxhilevent(hilp, dptr);
82841480Smckusick 		return;
82941480Smckusick 	}
83041480Smckusick 
83141480Smckusick 	/*
83241480Smckusick 	 * If this device isn't on any queue or there are no data
83341480Smckusick 	 * in the packet (can this happen?) do nothing.
83441480Smckusick 	 */
83541480Smckusick 	if (dptr->hd_qmask == 0 ||
83641480Smckusick 	    (len0 = hilp->hl_pollbp - hilp->hl_pollbuf) <= 0)
83741480Smckusick 		return;
83841480Smckusick 
83941480Smckusick 	/*
84041480Smckusick 	 * Everybody gets the same time stamp
84141480Smckusick 	 */
84241480Smckusick 	s = splclock();
84341480Smckusick 	ourtime = time;
84441480Smckusick 	splx(s);
84541480Smckusick 	tenths = (ourtime.tv_sec * 100) + (ourtime.tv_usec / 10000);
84641480Smckusick 
84741480Smckusick 	proto = NULL;
84841480Smckusick 	mask = dptr->hd_qmask;
84941480Smckusick 	for (qnum = 0; mask; qnum++) {
85041480Smckusick 		if ((mask & hilqmask(qnum)) == 0)
85141480Smckusick 			continue;
85241480Smckusick 		mask &= ~hilqmask(qnum);
85341480Smckusick 		hq = hilp->hl_queue[qnum].hq_eventqueue;
85441480Smckusick 
85541480Smckusick 		/*
85641480Smckusick 		 * Ensure that queue fields that we rely on are valid
85741480Smckusick 		 * and that there is space in the queue.  If either
85841480Smckusick 		 * test fails, we just skip this queue.
85941480Smckusick 		 */
86041480Smckusick 		if (!HQVALID(&hq->hil_evqueue) || HQFULL(&hq->hil_evqueue))
86141480Smckusick 			continue;
86241480Smckusick 
86341480Smckusick 		/*
86441480Smckusick 		 * Copy data to queue.
86541480Smckusick 		 * If this is the first queue we construct the packet
86641480Smckusick 		 * with length, timestamp and poll buffer data.
86741480Smckusick 		 * For second and sucessive packets we just duplicate
86841480Smckusick 		 * the first packet.
86941480Smckusick 		 */
87041480Smckusick 		pp = (u_char *) &hq->hil_event[hq->hil_evqueue.tail];
87141480Smckusick 		if (proto == NULL) {
87241480Smckusick 			proto = (hil_packet *)pp;
87341480Smckusick 			cp = hilp->hl_pollbuf;
87441480Smckusick 			len = len0;
87541480Smckusick 			*pp++ = len + 6;
87641480Smckusick 			*pp++ = hilp->hl_actdev;
87741480Smckusick 			*(long *)pp = tenths;
87841480Smckusick 			pp += sizeof(long);
87941480Smckusick 			do *pp++ = *cp++; while (--len);
88041480Smckusick 		} else
88141480Smckusick 			*(hil_packet *)pp = *proto;
88241480Smckusick 
88341480Smckusick 		if (++hq->hil_evqueue.tail == hq->hil_evqueue.size)
88441480Smckusick 			hq->hil_evqueue.tail = 0;
88541480Smckusick 	}
88641480Smckusick 
88741480Smckusick 	/*
88841480Smckusick 	 * Wake up anyone selecting on this device or the loop itself
88941480Smckusick 	 */
89041480Smckusick 	if (dptr->hd_selr) {
89141480Smckusick 		selwakeup(dptr->hd_selr, dptr->hd_flags & HIL_SELCOLL);
89241480Smckusick 		dptr->hd_selr = NULL;
89341480Smckusick 		dptr->hd_flags &= ~HIL_SELCOLL;
89441480Smckusick 	}
89541480Smckusick 	dptr = &hilp->hl_device[HILLOOPDEV];
89641480Smckusick 	if (dptr->hd_selr) {
89741480Smckusick 		selwakeup(dptr->hd_selr, dptr->hd_flags & HIL_SELCOLL);
89841480Smckusick 		dptr->hd_selr = NULL;
89941480Smckusick 		dptr->hd_flags &= ~HIL_SELCOLL;
90041480Smckusick 	}
90141480Smckusick }
90241480Smckusick 
90341480Smckusick #undef HQFULL
90441480Smckusick 
90541480Smckusick hpuxhilevent(hilp, dptr)
90641480Smckusick 	register struct hilloop *hilp;
90741480Smckusick 	register struct hilloopdev *dptr;
90841480Smckusick {
90941480Smckusick 	register int len;
91041480Smckusick 	struct timeval ourtime;
91141480Smckusick 	long tstamp;
91241480Smckusick 	int s;
91341480Smckusick 
91441480Smckusick 	/*
91541480Smckusick 	 * Everybody gets the same time stamp
91641480Smckusick 	 */
91741480Smckusick 	s = splclock();
91841480Smckusick 	ourtime = time;
91941480Smckusick 	splx(s);
92041480Smckusick 	tstamp = (ourtime.tv_sec * 100) + (ourtime.tv_usec / 10000);
92141480Smckusick 
92241480Smckusick 	/*
92341480Smckusick 	 * Each packet that goes into the buffer must be preceded by the
92441480Smckusick 	 * number of bytes in the packet, and the timestamp of the packet.
92541480Smckusick 	 * This adds 5 bytes to the packet size. Make sure there is enough
92641480Smckusick 	 * room in the buffer for it, and if not, toss the packet.
92741480Smckusick 	 */
92841480Smckusick 	len = hilp->hl_pollbp - hilp->hl_pollbuf;
92941480Smckusick 	if (dptr->hd_queue.c_cc <= (HILMAXCLIST - (len+5))) {
93041480Smckusick 		putc(len+5, &dptr->hd_queue);
93141480Smckusick 		(void) b_to_q((char *)&tstamp, sizeof tstamp, &dptr->hd_queue);
93241480Smckusick 		(void) b_to_q((char *)hilp->hl_pollbuf, len, &dptr->hd_queue);
93341480Smckusick 	}
93441480Smckusick 
93541480Smckusick 	/*
93641480Smckusick 	 * Wake up any one blocked on a read or select
93741480Smckusick 	 */
93841480Smckusick 	if (dptr->hd_flags & HIL_ASLEEP) {
93941480Smckusick 		dptr->hd_flags &= ~HIL_ASLEEP;
94041480Smckusick 		wakeup((caddr_t)dptr);
94141480Smckusick 	}
94241480Smckusick 	if (dptr->hd_selr) {
94341480Smckusick 		selwakeup(dptr->hd_selr, dptr->hd_flags & HIL_SELCOLL);
94441480Smckusick 		dptr->hd_selr = NULL;
94541480Smckusick 		dptr->hd_flags &= ~HIL_SELCOLL;
94641480Smckusick 	}
94741480Smckusick }
94841480Smckusick 
94941480Smckusick /*
95041480Smckusick  * Shared queue manipulation routines
95141480Smckusick  */
95241480Smckusick 
95341480Smckusick hilqalloc(qip)
95441480Smckusick 	struct hilqinfo *qip;
95541480Smckusick {
956*43316Smckusick 	struct proc *p = u.u_procp;		/* XXX */
95741480Smckusick #ifdef MAPMEM
95841480Smckusick 	register struct hilloop *hilp = &hil0;	/* XXX */
95941480Smckusick 	register HILQ *hq;
96041480Smckusick 	register int qnum;
96141480Smckusick 	struct mapmem *mp;
96241480Smckusick 	int hilqmapin();
96341480Smckusick 
96441480Smckusick #ifdef DEBUG
96541480Smckusick 	if (hildebug & HDB_FOLLOW)
96641480Smckusick 		printf("hilqalloc(%d): addr %x\n",
967*43316Smckusick 		       p->p_pid, qip->addr);
96841480Smckusick #endif
96941480Smckusick 	/*
97041480Smckusick 	 * Find a free queue
97141480Smckusick 	 */
97241480Smckusick 	for (qnum = 0; qnum < NHILQ; qnum++)
97341480Smckusick 		if (hilp->hl_queue[qnum].hq_procp == NULL)
97441480Smckusick 			break;
97541480Smckusick 	if (qnum == NHILQ)
97641480Smckusick 		return(EMFILE);
97741480Smckusick 
97841480Smckusick 	/*
97941480Smckusick 	 * Allocate and clear memory for the queue
98041480Smckusick 	 */
98141480Smckusick 	if (hilp->hl_queue[qnum].hq_eventqueue)
98241480Smckusick 		panic("hilqalloc");
98341480Smckusick 	hq = (HILQ *) cialloc(sizeof(HILQ));
98441480Smckusick 	if (hq == NULL)
98541480Smckusick 		return(ENOMEM);
98641480Smckusick 	bzero((caddr_t)hq, sizeof(HILQ));
98741480Smckusick 	hilp->hl_queue[qnum].hq_eventqueue = hq;
98841480Smckusick 	hq->hil_evqueue.size = HEVQSIZE;
98941480Smckusick 
99041480Smckusick 	/*
99141480Smckusick 	 * Map queue into user address space as instructed
99241480Smckusick 	 */
993*43316Smckusick 	if (u.u_error = mmalloc(p, qnum, &qip->addr, sizeof(HILQ), MM_RW|MM_CI, &hilqops, &mp)) {
99441480Smckusick 		cifree((caddr_t)hq, sizeof(HILQ));
99541480Smckusick 		hilp->hl_queue[qnum].hq_eventqueue = NULL;
99641480Smckusick 		return(u.u_error);
99741480Smckusick 	}
99841480Smckusick 	qip->qid = qnum;
999*43316Smckusick 	if (!mmmapin(p, mp, hilqmapin)) {
1000*43316Smckusick 		mmfree(p, mp);
100141480Smckusick 		cifree((caddr_t)hq, sizeof(HILQ));
100241480Smckusick 		hilp->hl_queue[qnum].hq_eventqueue = NULL;
100341480Smckusick 		return(u.u_error);
100441480Smckusick 	}
1005*43316Smckusick 	hilp->hl_queue[qnum].hq_procp = p;
100641480Smckusick 	hilp->hl_queue[qnum].hq_devmask = 0;
100741480Smckusick 	return(0);
100841480Smckusick #else
100941480Smckusick 	return(EINVAL);
101041480Smckusick #endif
101141480Smckusick }
101241480Smckusick 
101341480Smckusick hilqfree(qnum)
101441480Smckusick 	register int qnum;
101541480Smckusick {
1016*43316Smckusick 	struct proc *p = u.u_procp;		/* XXX */
101741480Smckusick #ifdef MAPMEM
101841480Smckusick 	register struct hilloop *hilp = &hil0;	/* XXX */
101941480Smckusick 	register struct mapmem *mp;
102041480Smckusick 
102141480Smckusick #ifdef DEBUG
102241480Smckusick 	if (hildebug & HDB_FOLLOW)
102341480Smckusick 		printf("hilqfree(%d): qnum %d\n",
1024*43316Smckusick 		       p->p_pid, qnum);
102541480Smckusick #endif
1026*43316Smckusick 	if (qnum >= NHILQ || hilp->hl_queue[qnum].hq_procp != p)
102741480Smckusick 		return(EINVAL);
102841480Smckusick 	for (mp = u.u_mmap; mp; mp = mp->mm_next)
102941480Smckusick 		if (qnum == mp->mm_id && mp->mm_ops == &hilqops) {
103041480Smckusick 			hilqexit(mp);
103141480Smckusick 			return(0);
103241480Smckusick 		}
103341480Smckusick 	panic("hilqfree");
103441480Smckusick 	/* NOTREACHED */
103541480Smckusick #else
103641480Smckusick 	return(EINVAL);
103741480Smckusick #endif
103841480Smckusick }
103941480Smckusick 
104041480Smckusick hilqmap(qnum, device)
104141480Smckusick 	register int qnum, device;
104241480Smckusick {
1043*43316Smckusick 	struct proc *p = u.u_procp;		/* XXX */
104441480Smckusick 	register struct hilloop *hilp = &hil0;	/* XXX */
104541480Smckusick 	register struct hilloopdev *dptr = &hilp->hl_device[device];
104641480Smckusick 	int s;
104741480Smckusick 
104841480Smckusick #ifdef DEBUG
104941480Smckusick 	if (hildebug & HDB_FOLLOW)
105041480Smckusick 		printf("hilqmap(%d): qnum %d device %x\n",
1051*43316Smckusick 		       p->p_pid, qnum, device);
105241480Smckusick #endif
1053*43316Smckusick 	if (qnum >= NHILQ || hilp->hl_queue[qnum].hq_procp != p)
105441480Smckusick 		return(EINVAL);
105541480Smckusick 	if ((dptr->hd_flags & HIL_QUEUEIN) == 0)
105641480Smckusick 		return(EINVAL);
105741480Smckusick 	if (dptr->hd_qmask && u.u_uid && u.u_uid != dptr->hd_uid)
105841480Smckusick 		return(EPERM);
105941480Smckusick 
106041480Smckusick 	hilp->hl_queue[qnum].hq_devmask |= hildevmask(device);
106141480Smckusick 	if (dptr->hd_qmask == 0)
106241480Smckusick 		dptr->hd_uid = u.u_uid;
106341480Smckusick 	s = splhil();
106441480Smckusick 	dptr->hd_qmask |= hilqmask(qnum);
106541480Smckusick 	splx(s);
106641480Smckusick #ifdef DEBUG
106741480Smckusick 	if (hildebug & HDB_MASK)
106841480Smckusick 		printf("hilqmap(%d): devmask %x qmask %x\n",
1069*43316Smckusick 		       p->p_pid, hilp->hl_queue[qnum].hq_devmask,
107041480Smckusick 		       dptr->hd_qmask);
107141480Smckusick #endif
107241480Smckusick 	return(0);
107341480Smckusick }
107441480Smckusick 
107541480Smckusick hilqunmap(qnum, device)
107641480Smckusick 	register int qnum, device;
107741480Smckusick {
1078*43316Smckusick 	struct proc *p = u.u_procp;		/* XXX */
107941480Smckusick 	register struct hilloop *hilp = &hil0;	/* XXX */
108041480Smckusick 	int s;
108141480Smckusick 
108241480Smckusick #ifdef DEBUG
108341480Smckusick 	if (hildebug & HDB_FOLLOW)
108441480Smckusick 		printf("hilqunmap(%d): qnum %d device %x\n",
1085*43316Smckusick 		       p->p_pid, qnum, device);
108641480Smckusick #endif
108741480Smckusick 
1088*43316Smckusick 	if (qnum >= NHILQ || hilp->hl_queue[qnum].hq_procp != p)
108941480Smckusick 		return(EINVAL);
109041480Smckusick 
109141480Smckusick 	hilp->hl_queue[qnum].hq_devmask &= ~hildevmask(device);
109241480Smckusick 	s = splhil();
109341480Smckusick 	hilp->hl_device[device].hd_qmask &= ~hilqmask(qnum);
109441480Smckusick 	splx(s);
109541480Smckusick #ifdef DEBUG
109641480Smckusick 	if (hildebug & HDB_MASK)
109741480Smckusick 		printf("hilqunmap(%d): devmask %x qmask %x\n",
1098*43316Smckusick 		       p->p_pid, hilp->hl_queue[qnum].hq_devmask,
109941480Smckusick 		       hilp->hl_device[device].hd_qmask);
110041480Smckusick #endif
110141480Smckusick 	return(0);
110241480Smckusick }
110341480Smckusick 
110441480Smckusick #ifdef MAPMEM
110541480Smckusick hilqmapin(mp, off)
110641480Smckusick 	struct mapmem *mp;
110741480Smckusick {
110841480Smckusick 	struct hilloop *hilp = &hil0;		/* XXX */
110941480Smckusick 	register HILQ *hq = hilp->hl_queue[mp->mm_id].hq_eventqueue;
111041480Smckusick 
111141480Smckusick 	if (hq == NULL || off >= sizeof(HILQ))
111241480Smckusick 		return(-1);
111341480Smckusick 	return(kvtop((u_int)hq + off) >> PGSHIFT);
111441480Smckusick }
111541480Smckusick 
111641480Smckusick /*
111741480Smckusick  * Fork hook.
111841480Smckusick  * Unmap queue from child's address space
111941480Smckusick  */
112041480Smckusick hilqfork(mp, ischild)
112141480Smckusick 	struct mapmem *mp;
112241480Smckusick {
1123*43316Smckusick 	struct proc *p = u.u_procp;		/* XXX */
112441480Smckusick #ifdef DEBUG
112541480Smckusick 	if (hildebug & HDB_MMAP)
1126*43316Smckusick 		printf("hilqfork(%d): %s qnum %d\n", p->p_pid,
112741480Smckusick 		       ischild ? "child" : "parent", mp->mm_id);
112841480Smckusick #endif
112941480Smckusick 	if (ischild) {
1130*43316Smckusick 		mmmapout(p, mp);
1131*43316Smckusick 		mmfree(p, mp);
113241480Smckusick 	}
113341480Smckusick }
113441480Smckusick 
113541480Smckusick /*
113641480Smckusick  * Vfork hook.
113741480Smckusick  * Associate queue with child when VM resources are passed.
113841480Smckusick  */
113941480Smckusick hilqvfork(mp, fup, tup)
114041480Smckusick 	struct mapmem *mp;
114141480Smckusick 	struct user *fup, *tup;
114241480Smckusick {
114341480Smckusick 	struct hilloop *hilp = &hil0;		/* XXX */
114441480Smckusick 	register struct hiliqueue *qp = &hilp->hl_queue[mp->mm_id];
114541480Smckusick 
114641480Smckusick #ifdef DEBUG
114741480Smckusick 	if (hildebug & HDB_MMAP)
114841480Smckusick 		printf("hilqvfork(%d): from %x to %x qnum %d, qprocp %x\n",
114941480Smckusick 		       u.u_procp->p_pid, fup->u_procp, tup->u_procp,
115041480Smckusick 		       mp->mm_id, qp->hq_procp);
115141480Smckusick #endif
115241480Smckusick 	if (qp->hq_procp == fup->u_procp)
115341480Smckusick 		qp->hq_procp = tup->u_procp;
115441480Smckusick }
115541480Smckusick 
115641480Smckusick /*
115741480Smckusick  * Exit hook.
115841480Smckusick  * Unmap all devices and free all queues.
115941480Smckusick  */
116041480Smckusick hilqexit(mp)
116141480Smckusick 	struct mapmem *mp;
116241480Smckusick {
1163*43316Smckusick 	struct proc *p = u.u_procp;		/* XXX */
116441480Smckusick 	register struct hilloop *hilp = &hil0;	/* XXX */
116541480Smckusick 	register int mask, i;
116641480Smckusick 	int s;
116741480Smckusick 
116841480Smckusick #ifdef DEBUG
116941480Smckusick 	if (hildebug & HDB_MMAP)
1170*43316Smckusick 		printf("hilqexit(%d): qnum %d\n", p->p_pid, mp->mm_id);
117141480Smckusick #endif
117241480Smckusick 	/*
117341480Smckusick 	 * Atomically take all devices off the queue
117441480Smckusick 	 */
117541480Smckusick 	mask = ~hilqmask(mp->mm_id);
117641480Smckusick 	s = splhil();
117741480Smckusick 	for (i = 0; i < NHILD; i++)
117841480Smckusick 		hilp->hl_device[i].hd_qmask &= mask;
117941480Smckusick 	splx(s);
118041480Smckusick 	/*
118141480Smckusick 	 * Now unmap from user address space and free queue
118241480Smckusick 	 */
118341480Smckusick 	i = mp->mm_id;
118441480Smckusick 	cifree((caddr_t)hilp->hl_queue[i].hq_eventqueue, sizeof(HILQ));
118541480Smckusick 	hilp->hl_queue[i].hq_eventqueue = NULL;
118641480Smckusick 	hilp->hl_queue[i].hq_procp = NULL;
1187*43316Smckusick 	mmfree(p, mp);
118841480Smckusick }
118941480Smckusick #endif
119041480Smckusick 
119141480Smckusick #include "clist.h"
119241480Smckusick 
119341480Smckusick /*
119441480Smckusick  * This is just a copy of the virgin q_to_b routine with minor
119541480Smckusick  * optimizations for HIL use.  It is used for two reasons:
119641480Smckusick  * 1. If we have PAGE mode defined, the normal q_to_b processes
119741480Smckusick  *    chars one at a time and breaks on newlines.
119841480Smckusick  * 2. We don't have to raise the priority to spltty() for most
119941480Smckusick  *    of the clist manipulations.
120041480Smckusick  */
120141480Smckusick hilq_to_b(q, cp, cc)
120241480Smckusick 	register struct clist *q;
120341480Smckusick 	register char *cp;
120441480Smckusick {
120541480Smckusick 	register struct cblock *bp;
120641480Smckusick 	register int nc;
120741480Smckusick 	char *acp;
120841480Smckusick 	int s;
120941480Smckusick 	extern char cwaiting;
121041480Smckusick 
121141480Smckusick 	if (cc <= 0)
121241480Smckusick 		return (0);
121341480Smckusick 	s = splhil();
121441480Smckusick 	if (q->c_cc <= 0) {
121541480Smckusick 		q->c_cc = 0;
121641480Smckusick 		q->c_cf = q->c_cl = NULL;
121741480Smckusick 		splx(s);
121841480Smckusick 		return (0);
121941480Smckusick 	}
122041480Smckusick 	acp = cp;
122141480Smckusick 
122241480Smckusick 	while (cc) {
122341480Smckusick 		nc = sizeof (struct cblock) - ((int)q->c_cf & CROUND);
122441480Smckusick 		nc = MIN(nc, cc);
122541480Smckusick 		nc = MIN(nc, q->c_cc);
122641480Smckusick 		(void) bcopy(q->c_cf, cp, (unsigned)nc);
122741480Smckusick 		q->c_cf += nc;
122841480Smckusick 		q->c_cc -= nc;
122941480Smckusick 		cc -= nc;
123041480Smckusick 		cp += nc;
123141480Smckusick 		if (q->c_cc <= 0) {
123241480Smckusick 			bp = (struct cblock *)(q->c_cf - 1);
123341480Smckusick 			bp = (struct cblock *)((int)bp & ~CROUND);
123441480Smckusick 			q->c_cf = q->c_cl = NULL;
123541480Smckusick 			spltty();
123641480Smckusick 			bp->c_next = cfreelist;
123741480Smckusick 			cfreelist = bp;
123841480Smckusick 			cfreecount += CBSIZE;
123941480Smckusick 			if (cwaiting) {
124041480Smckusick 				wakeup(&cwaiting);
124141480Smckusick 				cwaiting = 0;
124241480Smckusick 			}
124341480Smckusick 			break;
124441480Smckusick 		}
124541480Smckusick 		if (((int)q->c_cf & CROUND) == 0) {
124641480Smckusick 			bp = (struct cblock *)(q->c_cf);
124741480Smckusick 			bp--;
124841480Smckusick 			q->c_cf = bp->c_next->c_info;
124941480Smckusick 			spltty();
125041480Smckusick 			bp->c_next = cfreelist;
125141480Smckusick 			cfreelist = bp;
125241480Smckusick 			cfreecount += CBSIZE;
125341480Smckusick 			if (cwaiting) {
125441480Smckusick 				wakeup(&cwaiting);
125541480Smckusick 				cwaiting = 0;
125641480Smckusick 			}
125741480Smckusick 			splhil();
125841480Smckusick 		}
125941480Smckusick 	}
126041480Smckusick 	splx(s);
126141480Smckusick 	return (cp-acp);
126241480Smckusick }
126341480Smckusick 
126441480Smckusick /*
126541480Smckusick  * Cooked keyboard functions for ite driver.
126641480Smckusick  * There is only one "cooked" ITE keyboard (the first keyboard found)
126741480Smckusick  * per loop.  There may be other keyboards, but they will always be "raw".
126841480Smckusick  */
126941480Smckusick 
127041480Smckusick kbdbell()
127141480Smckusick {
127241480Smckusick 	struct hilloop *hilp = &hil0;		/* XXX */
127341480Smckusick 
127441480Smckusick 	hilbeep(hilp, &default_bell);
127541480Smckusick }
127641480Smckusick 
127741480Smckusick kbdenable()
127841480Smckusick {
127941480Smckusick 	struct hilloop *hilp = &hil0;	/* XXX */
128041480Smckusick 	register struct hil_dev *hildevice = hilp->hl_addr;
128141480Smckusick 	char db;
128241480Smckusick 
128341480Smckusick 	/* Set the autorepeat rate register */
128441480Smckusick 	db = ar_format(KBD_ARR);
128541480Smckusick 	send_hil_cmd(hildevice, HIL_SETARR, &db, 1, NULL);
128641480Smckusick 
128741480Smckusick 	/* Set the autorepeat delay register */
128841480Smckusick 	db = ar_format(KBD_ARD);
128941480Smckusick 	send_hil_cmd(hildevice, HIL_SETARD, &db, 1, NULL);
129041480Smckusick 
129141480Smckusick 	/* Enable interrupts */
129241480Smckusick 	send_hil_cmd(hildevice, HIL_INTON, NULL, 0, NULL);
129341480Smckusick }
129441480Smckusick 
129541480Smckusick kbddisable()
129641480Smckusick {
129741480Smckusick }
129841480Smckusick 
129941480Smckusick /*
130041480Smckusick  * XXX: read keyboard directly and return code.
130141480Smckusick  * Used by console getchar routine.  Could really screw up anybody
130241480Smckusick  * reading from the keyboard in the normal, interrupt driven fashion.
130341480Smckusick  */
130441480Smckusick kbdgetc(statp)
130541480Smckusick 	int *statp;
130641480Smckusick {
130741480Smckusick 	struct hilloop *hilp = &hil0;		/* XXX */
130841480Smckusick 	register struct hil_dev *hildevice = hilp->hl_addr;
130941480Smckusick 	register int c, stat;
131041480Smckusick 	int s;
131141480Smckusick 
131241480Smckusick 	s = splhil();
131341480Smckusick 	while (((stat = hildevice->hil_stat) & HIL_DATA_RDY) == 0)
131441480Smckusick 		;
131541480Smckusick 	c = hildevice->hil_data;
131641480Smckusick 	splx(s);
131741480Smckusick 	*statp = stat;
131841480Smckusick 	return(c);
131941480Smckusick }
132041480Smckusick 
132141480Smckusick /*
132241480Smckusick  * Recoginize and clear keyboard generated NMIs.
132341480Smckusick  * Returns 1 if it was ours, 0 otherwise.  Note that we cannot use
132441480Smckusick  * send_hil_cmd() to issue the clear NMI command as that would actually
132541480Smckusick  * lower the priority to splimp() and it doesn't wait for the completion
132641480Smckusick  * of the command.  Either of these conditions could result in the
132741480Smckusick  * interrupt reoccuring.  Note that we issue the CNMT command twice.
132841480Smckusick  * This seems to be needed, once is not always enough!?!
132941480Smckusick  */
133041480Smckusick kbdnmi()
133141480Smckusick {
133241480Smckusick 	register struct hilloop *hilp = &hil0;		/* XXX */
133341480Smckusick 
133441480Smckusick 	if ((*KBDNMISTAT & KBDNMI) == 0)
133541480Smckusick 		return(0);
133641480Smckusick 	HILWAIT(hilp->hl_addr);
133741480Smckusick 	hilp->hl_addr->hil_cmd = HIL_CNMT;
133841480Smckusick 	HILWAIT(hilp->hl_addr);
133941480Smckusick 	hilp->hl_addr->hil_cmd = HIL_CNMT;
134041480Smckusick 	HILWAIT(hilp->hl_addr);
134141480Smckusick 	return(1);
134241480Smckusick }
134341480Smckusick 
134441480Smckusick #define HILSECURITY	0x33
134541480Smckusick #define HILIDENTIFY	0x03
134641480Smckusick #define HILSCBIT	0x04
134741480Smckusick 
134841480Smckusick /*
134941480Smckusick  * Called at boot time to print out info about interesting devices
135041480Smckusick  */
135141480Smckusick hilinfo(hilp)
135241480Smckusick 	register struct hilloop *hilp;
135341480Smckusick {
135441480Smckusick 	register int id, len;
135541480Smckusick 	register struct kbdmap *km;
135641480Smckusick 
135741480Smckusick 	/*
135841480Smckusick 	 * Keyboard info.
135941480Smckusick 	 */
136041480Smckusick 	if (hilp->hl_kbddev) {
136141480Smckusick 		printf("hil%d: ", hilp->hl_kbddev);
136241480Smckusick 		for (km = kbd_map; km->kbd_code; km++)
136341480Smckusick 			if (km->kbd_code == hilp->hl_kbdlang) {
136441480Smckusick 				printf("%s ", km->kbd_desc);
136541480Smckusick 				break;
136641480Smckusick 			}
136741480Smckusick 		printf("keyboard\n");
136841480Smckusick 	}
136941480Smckusick 	/*
137041480Smckusick 	 * ID module.
137141480Smckusick 	 * Attempt to locate the first ID module and print out its
137241480Smckusick 	 * security code.  Is this a good idea??
137341480Smckusick 	 */
137441480Smckusick 	id = hiliddev(hilp);
137541480Smckusick 	if (id) {
137641480Smckusick 		hilp->hl_cmdbp = hilp->hl_cmdbuf;
137741480Smckusick 		hilp->hl_cmddev = id;
137841480Smckusick 		send_hildev_cmd(hilp, id, HILSECURITY);
137941480Smckusick 		len = hilp->hl_cmdbp - hilp->hl_cmdbuf;
138041480Smckusick 		hilp->hl_cmdbp = hilp->hl_cmdbuf;
138141480Smckusick 		hilp->hl_cmddev = 0;
138241480Smckusick 		printf("hil%d: security code", id);
138341480Smckusick 		for (id = 0; id < len; id++)
138441480Smckusick 			printf(" %x", hilp->hl_cmdbuf[id]);
138541480Smckusick 		while (id++ < 16)
138641480Smckusick 			printf(" 0");
138741480Smckusick 		printf("\n");
138841480Smckusick 	}
138941480Smckusick }
139041480Smckusick 
139141480Smckusick #define HILAR1	0x3E
139241480Smckusick #define HILAR2	0x3F
139341480Smckusick 
139441480Smckusick /*
139541480Smckusick  * Called after the loop has reconfigured.  Here we need to:
139641480Smckusick  *	- determine how many devices are on the loop
139741480Smckusick  *	  (some may have been added or removed)
139841480Smckusick  *	- locate the ITE keyboard (if any) and ensure
139941480Smckusick  *	  that it is in the proper state (raw or cooked)
140041480Smckusick  *	  and is set to use the proper language mapping table
140141480Smckusick  *	- ensure all other keyboards are raw
140241480Smckusick  * Note that our device state is now potentially invalid as
140341480Smckusick  * devices may no longer be where they were.  What we should
140441480Smckusick  * do here is either track where the devices went and move
140541480Smckusick  * state around accordingly or, more simply, just mark all
140641480Smckusick  * devices as HIL_DERROR and don't allow any further use until
140741480Smckusick  * they are closed.  This is a little too brutal for my tastes,
140841480Smckusick  * we prefer to just assume people won't move things around.
140941480Smckusick  */
141041480Smckusick hilconfig(hilp)
141141480Smckusick 	register struct hilloop *hilp;
141241480Smckusick {
141341480Smckusick 	u_char db;
141441480Smckusick 	int s;
141541480Smckusick 
141641480Smckusick 	s = splhil();
141741480Smckusick #ifdef DEBUG
141841480Smckusick 	if (hildebug & HDB_CONFIG) {
141941480Smckusick 		printf("hilconfig: reconfigured: ");
142041480Smckusick 		send_hil_cmd(hilp->hl_addr, HIL_READLPSTAT, NULL, 0, &db);
142141480Smckusick 		printf("LPSTAT %x, ", db);
142241480Smckusick 		send_hil_cmd(hilp->hl_addr, HIL_READLPCTRL, NULL, 0, &db);
142341480Smckusick 		printf("LPCTRL %x, ", db);
142441480Smckusick 		send_hil_cmd(hilp->hl_addr, HIL_READKBDSADR, NULL, 0, &db);
142541480Smckusick 		printf("KBDSADR %x\n", db);
142641480Smckusick 		hilreport(hilp);
142741480Smckusick 	}
142841480Smckusick #endif
142941480Smckusick 	/*
143041480Smckusick 	 * Determine how many devices are on the loop.
143141480Smckusick 	 * Mark those as alive and real, all others as dead.
143241480Smckusick 	 */
143341480Smckusick 	db = 0;
143441480Smckusick 	send_hil_cmd(hilp->hl_addr, HIL_READLPSTAT, NULL, 0, &db);
143541480Smckusick 	hilp->hl_maxdev = db & LPS_DEVMASK;
143641480Smckusick 	for (db = 1; db < NHILD; db++) {
143741480Smckusick 		if (db <= hilp->hl_maxdev)
143841480Smckusick 			hilp->hl_device[db].hd_flags |= HIL_ALIVE;
143941480Smckusick 		else
144041480Smckusick 			hilp->hl_device[db].hd_flags &= ~HIL_ALIVE;
144141480Smckusick 		hilp->hl_device[db].hd_flags &= ~HIL_PSEUDO;
144241480Smckusick 	}
144341480Smckusick #ifdef DEBUG
144441480Smckusick 	if (hildebug & (HDB_CONFIG|HDB_KEYBOARD))
144541480Smckusick 		printf("hilconfig: max device %d\n", hilp->hl_maxdev);
144641480Smckusick #endif
144741480Smckusick 	if (hilp->hl_maxdev == 0) {
144841480Smckusick 		hilp->hl_kbddev = 0;
144941480Smckusick 		splx(s);
145041480Smckusick 		return;
145141480Smckusick 	}
145241480Smckusick 	/*
145341480Smckusick 	 * Find out where the keyboards are and record the ITE keyboard
145441480Smckusick 	 * (first one found).  If no keyboards found, we are all done.
145541480Smckusick 	 */
145641480Smckusick 	db = 0;
145741480Smckusick 	send_hil_cmd(hilp->hl_addr, HIL_READKBDSADR, NULL, 0, &db);
145841480Smckusick #ifdef DEBUG
145941480Smckusick 	if (hildebug & HDB_KEYBOARD)
146041480Smckusick 		printf("hilconfig: keyboard: KBDSADR %x, old %d, new %d\n",
146141480Smckusick 		       db, hilp->hl_kbddev, ffs((int)db));
146241480Smckusick #endif
146341480Smckusick 	hilp->hl_kbddev = ffs((int)db);
146441480Smckusick 	if (hilp->hl_kbddev == 0) {
146541480Smckusick 		splx(s);
146641480Smckusick 		return;
146741480Smckusick 	}
146841480Smckusick 	/*
146941480Smckusick 	 * Determine if the keyboard should be cooked or raw and configure it.
147041480Smckusick 	 */
147141480Smckusick 	db = (hilp->hl_kbdflags & KBD_RAW) ? 0 : 1 << (hilp->hl_kbddev - 1);
147241480Smckusick 	send_hil_cmd(hilp->hl_addr, HIL_WRITEKBDSADR, &db, 1, NULL);
147341480Smckusick 	/*
147441480Smckusick 	 * Re-enable autorepeat in raw mode, cooked mode AR is not affected.
147541480Smckusick 	 */
147641480Smckusick 	if (hilp->hl_kbdflags & (KBD_AR1|KBD_AR2)) {
147741480Smckusick 		db = (hilp->hl_kbdflags & KBD_AR1) ? HILAR1 : HILAR2;
147841480Smckusick 		hilp->hl_cmddev = hilp->hl_kbddev;
147941480Smckusick 		send_hildev_cmd(hilp, hilp->hl_kbddev, db);
148041480Smckusick 		hilp->hl_cmddev = 0;
148141480Smckusick 	}
148241480Smckusick 	/*
148341480Smckusick 	 * Determine the keyboard language configuration, but don't
148441480Smckusick 	 * override a user-specified setting.
148541480Smckusick 	 */
148641480Smckusick 	db = 0;
148741480Smckusick 	send_hil_cmd(hilp->hl_addr, HIL_READKBDLANG, NULL, 0, &db);
148841480Smckusick #ifdef DEBUG
148941480Smckusick 	if (hildebug & HDB_KEYBOARD)
149041480Smckusick 		printf("hilconfig: language: old %x new %x\n",
149141480Smckusick 		       hilp->hl_kbdlang, db);
149241480Smckusick #endif
149341480Smckusick 	if (hilp->hl_kbdlang != KBD_SPECIAL) {
149441480Smckusick 		struct kbdmap *km;
149541480Smckusick 
149641480Smckusick 		for (km = kbd_map; km->kbd_code; km++)
149741480Smckusick 			if (km->kbd_code == db) {
149841480Smckusick 				hilp->hl_kbdlang = db;
149941480Smckusick 				/* XXX */
150041480Smckusick 				kbd_keymap = km->kbd_keymap;
150141480Smckusick 				kbd_shiftmap = km->kbd_shiftmap;
150241480Smckusick 				kbd_ctrlmap = km->kbd_ctrlmap;
150341480Smckusick 				kbd_ctrlshiftmap = km->kbd_ctrlshiftmap;
150441480Smckusick 				kbd_stringmap = km->kbd_stringmap;
150541480Smckusick 			}
150641480Smckusick 	}
150741480Smckusick 	splx(s);
150841480Smckusick }
150941480Smckusick 
151041480Smckusick hilreset(hilp)
151141480Smckusick 	struct hilloop *hilp;
151241480Smckusick {
151341480Smckusick 	register struct hil_dev *hildevice = hilp->hl_addr;
151441480Smckusick 	u_char db;
151541480Smckusick 
151641480Smckusick 	/*
151741480Smckusick 	 * Initialize the loop: reconfigure, don't report errors,
151841480Smckusick 	 * cook keyboards, and enable autopolling.
151941480Smckusick 	 */
152041480Smckusick 	db = LPC_RECONF | LPC_KBDCOOK | LPC_NOERROR | LPC_AUTOPOLL;
152141480Smckusick 	send_hil_cmd(hildevice, HIL_WRITELPCTRL, &db, 1, NULL);
152241480Smckusick 	/*
152341480Smckusick 	 * Delay one second for reconfiguration and then read the the
152441480Smckusick 	 * data register to clear the interrupt (if the loop reconfigured).
152541480Smckusick 	 */
152641480Smckusick 	DELAY(1000000);
152741480Smckusick 	if (hildevice->hil_stat & HIL_DATA_RDY)
152841480Smckusick 		db = hildevice->hil_data;
152941480Smckusick 	/*
153041480Smckusick 	 * The HIL loop may have reconfigured.  If so we proceed on,
153141480Smckusick 	 * if not we loop until a successful reconfiguration is reported
153241480Smckusick 	 * back to us.  The HIL loop will continue to attempt forever.
153341480Smckusick 	 * Probably not very smart.
153441480Smckusick 	 */
153541480Smckusick 	do {
153641480Smckusick 		send_hil_cmd(hildevice, HIL_READLPSTAT, NULL, 0, &db);
153741480Smckusick         } while ((db & (LPS_CONFFAIL|LPS_CONFGOOD)) == 0);
153841480Smckusick 	/*
153941480Smckusick 	 * At this point, the loop should have reconfigured.
154041480Smckusick 	 * The reconfiguration interrupt has already called hilconfig()
154141480Smckusick 	 * so the keyboard has been determined.  All that is left is
154241480Smckusick 	 *
154341480Smckusick 	 */
154441480Smckusick #if 0
154541480Smckusick 	hilconfig(hilp);
154641480Smckusick #endif
154741480Smckusick 	send_hil_cmd(hildevice, HIL_INTON, NULL, 0, NULL);
154841480Smckusick }
154941480Smckusick 
155041480Smckusick hilbeep(hilp, bp)
155141480Smckusick 	struct hilloop *hilp;
155241480Smckusick 	register struct _hilbell *bp;
155341480Smckusick {
155441480Smckusick 	u_char buf[2];
155541480Smckusick 
155641480Smckusick 	buf[0] = ~((bp->duration - 10) / 10);
155741480Smckusick 	buf[1] = bp->frequency;
155841480Smckusick 	send_hil_cmd(hilp->hl_addr, HIL_SETTONE, buf, 2, NULL);
155941480Smckusick }
156041480Smckusick 
156141480Smckusick /*
156241480Smckusick  * Locate and return the address of the first ID module, 0 if none present.
156341480Smckusick  */
156441480Smckusick hiliddev(hilp)
156541480Smckusick 	register struct hilloop *hilp;
156641480Smckusick {
156741480Smckusick 	register int i, len;
156841480Smckusick 
156941480Smckusick #ifdef DEBUG
157041480Smckusick 	if (hildebug & HDB_IDMODULE)
157141480Smckusick 		printf("hiliddev(%x): looking for idmodule...", hilp);
157241480Smckusick #endif
157341480Smckusick 	for (i = 1; i <= hilp->hl_maxdev; i++) {
157441480Smckusick 		hilp->hl_cmdbp = hilp->hl_cmdbuf;
157541480Smckusick 		hilp->hl_cmddev = i;
157641480Smckusick 		send_hildev_cmd(hilp, i, HILIDENTIFY);
157741480Smckusick 		/*
157841480Smckusick 		 * XXX: the final condition checks to ensure that the
157941480Smckusick 		 * device ID byte is in the range of the ID module (0x30-0x3F)
158041480Smckusick 		 */
158141480Smckusick 		len = hilp->hl_cmdbp - hilp->hl_cmdbuf;
158241480Smckusick 		if (len > 1 && (hilp->hl_cmdbuf[1] & HILSCBIT) &&
158341480Smckusick 		    (hilp->hl_cmdbuf[0] & 0xF0) == 0x30) {
158441480Smckusick 			hilp->hl_cmdbp = hilp->hl_cmdbuf;
158541480Smckusick 			hilp->hl_cmddev = i;
158641480Smckusick 			send_hildev_cmd(hilp, i, HILSECURITY);
158741480Smckusick 			break;
158841480Smckusick 		}
158941480Smckusick 	}
159041480Smckusick 	hilp->hl_cmdbp = hilp->hl_cmdbuf;
159141480Smckusick 	hilp->hl_cmddev = 0;
159241480Smckusick #ifdef DEBUG
159341480Smckusick 	if (hildebug & HDB_IDMODULE)
159441480Smckusick 		if (i <= hilp->hl_maxdev)
159541480Smckusick 			printf("found at %d\n", i);
159641480Smckusick 		else
159741480Smckusick 			printf("not found\n");
159841480Smckusick #endif
159941480Smckusick 	return(i <= hilp->hl_maxdev ? i : 0);
160041480Smckusick }
160141480Smckusick 
160241480Smckusick /*
160341480Smckusick  * Low level routines which actually talk to the 8042 chip.
160441480Smckusick  */
160541480Smckusick 
160641480Smckusick /*
160741480Smckusick  * Send a command to the 8042 with zero or more bytes of data.
160841480Smckusick  * If rdata is non-null, wait for and return a byte of data.
160941480Smckusick  * We run at splimp() to make the transaction as atomic as
161041480Smckusick  * possible without blocking the clock (is this necessary?)
161141480Smckusick  */
161241480Smckusick send_hil_cmd(hildevice, cmd, data, dlen, rdata)
161341480Smckusick 	register struct hil_dev *hildevice;
161441480Smckusick 	u_char cmd, *data, dlen;
161541480Smckusick 	u_char *rdata;
161641480Smckusick {
161741480Smckusick 	u_char status;
161841480Smckusick 	int s = splimp();
161941480Smckusick 
162041480Smckusick 	HILWAIT(hildevice);
162141480Smckusick 	hildevice->hil_cmd = cmd;
162241480Smckusick 	while (dlen--) {
162341480Smckusick 	  	HILWAIT(hildevice);
162441480Smckusick 		hildevice->hil_data = *data++;
162541480Smckusick 	}
162641480Smckusick 	if (rdata) {
162741480Smckusick 		do {
162841480Smckusick 			HILDATAWAIT(hildevice);
162941480Smckusick 			status = hildevice->hil_stat;
163041480Smckusick 			*rdata = hildevice->hil_data;
163141480Smckusick 		} while (((status >> HIL_SSHIFT) & HIL_SMASK) != HIL_68K);
163241480Smckusick 	}
163341480Smckusick 	splx(s);
163441480Smckusick }
163541480Smckusick 
163641480Smckusick /*
163741480Smckusick  * Send a command to a device on the loop.
163841480Smckusick  * Since only one command can be active on the loop at any time,
163941480Smckusick  * we must ensure that we are not interrupted during this process.
164041480Smckusick  * Hence we mask interrupts to prevent potential access from most
164141480Smckusick  * interrupt routines and turn off auto-polling to disable the
164241480Smckusick  * internally generated poll commands.
164341480Smckusick  *
164441480Smckusick  * splhigh is extremely conservative but insures atomic operation,
164541480Smckusick  * splimp (clock only interrupts) seems to be good enough in practice.
164641480Smckusick  */
164741480Smckusick send_hildev_cmd(hilp, device, cmd)
164841480Smckusick 	register struct hilloop *hilp;
164941480Smckusick 	char device, cmd;
165041480Smckusick {
165141480Smckusick 	register struct hil_dev *hildevice = hilp->hl_addr;
165241480Smckusick 	u_char status, c;
165341480Smckusick 	int s = splimp();
165441480Smckusick 
165541480Smckusick 	polloff(hildevice);
165641480Smckusick 
165741480Smckusick 	/*
165841480Smckusick 	 * Transfer the command and device info to the chip
165941480Smckusick 	 */
166041480Smckusick 	HILWAIT(hildevice);
166141480Smckusick 	hildevice->hil_cmd = HIL_STARTCMD;
166241480Smckusick   	HILWAIT(hildevice);
166341480Smckusick 	hildevice->hil_data = 8 + device;
166441480Smckusick   	HILWAIT(hildevice);
166541480Smckusick 	hildevice->hil_data = cmd;
166641480Smckusick   	HILWAIT(hildevice);
166741480Smckusick 	hildevice->hil_data = HIL_TIMEOUT;
166841480Smckusick 	/*
166941480Smckusick 	 * Trigger the command and wait for completion
167041480Smckusick 	 */
167141480Smckusick 	HILWAIT(hildevice);
167241480Smckusick 	hildevice->hil_cmd = HIL_TRIGGER;
167341480Smckusick 	hilp->hl_cmddone = FALSE;
167441480Smckusick 	do {
167541480Smckusick 		HILDATAWAIT(hildevice);
167641480Smckusick 		status = hildevice->hil_stat;
167741480Smckusick 		c = hildevice->hil_data;
167841480Smckusick 		hil_process_int(status, c);
167941480Smckusick 	} while (!hilp->hl_cmddone);
168041480Smckusick 
168141480Smckusick 	pollon(hildevice);
168241480Smckusick 	splx(s);
168341480Smckusick }
168441480Smckusick 
168541480Smckusick /*
168641480Smckusick  * Turn auto-polling off and on.
168741480Smckusick  * Also disables and enable auto-repeat.  Why?
168841480Smckusick  */
168941480Smckusick polloff(hildevice)
169041480Smckusick 	register struct hil_dev *hildevice;
169141480Smckusick {
169241480Smckusick 	register char db;
169341480Smckusick 
169441480Smckusick 	/*
169541480Smckusick 	 * Turn off auto repeat
169641480Smckusick 	 */
169741480Smckusick 	HILWAIT(hildevice);
169841480Smckusick 	hildevice->hil_cmd = HIL_SETARR;
169941480Smckusick 	HILWAIT(hildevice);
170041480Smckusick 	hildevice->hil_data = 0;
170141480Smckusick 	/*
170241480Smckusick 	 * Turn off auto-polling
170341480Smckusick 	 */
170441480Smckusick 	HILWAIT(hildevice);
170541480Smckusick 	hildevice->hil_cmd = HIL_READLPCTRL;
170641480Smckusick 	HILDATAWAIT(hildevice);
170741480Smckusick 	db = hildevice->hil_data;
170841480Smckusick 	db &= ~LPC_AUTOPOLL;
170941480Smckusick 	HILWAIT(hildevice);
171041480Smckusick 	hildevice->hil_cmd = HIL_WRITELPCTRL;
171141480Smckusick 	HILWAIT(hildevice);
171241480Smckusick 	hildevice->hil_data = db;
171341480Smckusick 	/*
171441480Smckusick 	 * Must wait til polling is really stopped
171541480Smckusick 	 */
171641480Smckusick 	do {
171741480Smckusick 		HILWAIT(hildevice);
171841480Smckusick 		hildevice->hil_cmd = HIL_READBUSY;
171941480Smckusick 		HILDATAWAIT(hildevice);
172041480Smckusick 		db = hildevice->hil_data;
172141480Smckusick 	} while (db & BSY_LOOPBUSY);
172241480Smckusick }
172341480Smckusick 
172441480Smckusick pollon(hildevice)
172541480Smckusick 	register struct hil_dev *hildevice;
172641480Smckusick {
172741480Smckusick 	register char db;
172841480Smckusick 
172941480Smckusick 	/*
173041480Smckusick 	 * Turn on auto polling
173141480Smckusick 	 */
173241480Smckusick 	HILWAIT(hildevice);
173341480Smckusick 	hildevice->hil_cmd = HIL_READLPCTRL;
173441480Smckusick 	HILDATAWAIT(hildevice);
173541480Smckusick 	db = hildevice->hil_data;
173641480Smckusick 	db |= LPC_AUTOPOLL;
173741480Smckusick 	HILWAIT(hildevice);
173841480Smckusick 	hildevice->hil_cmd = HIL_WRITELPCTRL;
173941480Smckusick 	HILWAIT(hildevice);
174041480Smckusick 	hildevice->hil_data = db;
174141480Smckusick 	/*
174241480Smckusick 	 * Turn on auto repeat
174341480Smckusick 	 */
174441480Smckusick 	HILWAIT(hildevice);
174541480Smckusick 	hildevice->hil_cmd = HIL_SETARR;
174641480Smckusick 	HILWAIT(hildevice);
174741480Smckusick 	hildevice->hil_data = ar_format(KBD_ARR);
174841480Smckusick }
174941480Smckusick 
175041480Smckusick #ifdef DEBUG
175141480Smckusick printhilpollbuf(hilp)
175241480Smckusick 	register struct hilloop *hilp;
175341480Smckusick {
175441480Smckusick   	register u_char *cp;
175541480Smckusick 	register int i, len;
175641480Smckusick 
175741480Smckusick 	cp = hilp->hl_pollbuf;
175841480Smckusick 	len = hilp->hl_pollbp - cp;
175941480Smckusick 	for (i = 0; i < len; i++)
176041480Smckusick 		printf("%x ", hilp->hl_pollbuf[i]);
176141480Smckusick 	printf("\n");
176241480Smckusick }
176341480Smckusick 
176441480Smckusick printhilcmdbuf(hilp)
176541480Smckusick 	register struct hilloop *hilp;
176641480Smckusick {
176741480Smckusick   	register u_char *cp;
176841480Smckusick 	register int i, len;
176941480Smckusick 
177041480Smckusick 	cp = hilp->hl_cmdbuf;
177141480Smckusick 	len = hilp->hl_cmdbp - cp;
177241480Smckusick 	for (i = 0; i < len; i++)
177341480Smckusick 		printf("%x ", hilp->hl_cmdbuf[i]);
177441480Smckusick 	printf("\n");
177541480Smckusick }
177641480Smckusick 
177741480Smckusick hilreport(hilp)
177841480Smckusick 	register struct hilloop *hilp;
177941480Smckusick {
178041480Smckusick 	register int i, len;
178141480Smckusick 	int s = splhil();
178241480Smckusick 
178341480Smckusick 	for (i = 1; i <= hilp->hl_maxdev; i++) {
178441480Smckusick 		hilp->hl_cmdbp = hilp->hl_cmdbuf;
178541480Smckusick 		hilp->hl_cmddev = i;
178641480Smckusick 		send_hildev_cmd(hilp, i, HILIDENTIFY);
178741480Smckusick 		printf("hil%d: id: ", i);
178841480Smckusick 		printhilcmdbuf(hilp);
178941480Smckusick 		len = hilp->hl_cmdbp - hilp->hl_cmdbuf;
179041480Smckusick 		if (len > 1 && (hilp->hl_cmdbuf[1] & HILSCBIT)) {
179141480Smckusick 			hilp->hl_cmdbp = hilp->hl_cmdbuf;
179241480Smckusick 			hilp->hl_cmddev = i;
179341480Smckusick 			send_hildev_cmd(hilp, i, HILSECURITY);
179441480Smckusick 			printf("hil%d: sc: ", i);
179541480Smckusick 			printhilcmdbuf(hilp);
179641480Smckusick 		}
179741480Smckusick 	}
179841480Smckusick 	hilp->hl_cmdbp = hilp->hl_cmdbuf;
179941480Smckusick 	hilp->hl_cmddev = 0;
180041480Smckusick 	splx(s);
180141480Smckusick }
180241480Smckusick #endif
1803