diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 1995-10-18 08:53:40 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 1995-10-18 08:53:40 +0000 |
commit | d6583bb2a13f329cf0332ef2570eb8bb8fc0e39c (patch) | |
tree | ece253b876159b39c620e62b6c9b1174642e070e /sys/arch/hp300/dev/hil.c |
initial import of NetBSD tree
Diffstat (limited to 'sys/arch/hp300/dev/hil.c')
-rw-r--r-- | sys/arch/hp300/dev/hil.c | 1667 |
1 files changed, 1667 insertions, 0 deletions
diff --git a/sys/arch/hp300/dev/hil.c b/sys/arch/hp300/dev/hil.c new file mode 100644 index 00000000000..65d32dd9951 --- /dev/null +++ b/sys/arch/hp300/dev/hil.c @@ -0,0 +1,1667 @@ +/* $NetBSD: hil.c,v 1.19 1995/04/22 20:25:45 christos Exp $ */ + +/* + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the Systems Programming Group of the University of Utah Computer + * Science Department. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: Utah $Hdr: hil.c 1.38 92/01/21$ + * + * @(#)hil.c 8.2 (Berkeley) 1/12/94 + */ + +#include <sys/param.h> +#include <sys/conf.h> +#include <sys/proc.h> +#include <sys/user.h> +#include <sys/ioctl.h> +#include <sys/file.h> +#include <sys/tty.h> +#include <sys/systm.h> +#include <sys/uio.h> +#include <sys/kernel.h> + +#include <hp300/dev/hilreg.h> +#include <hp300/dev/hilioctl.h> +#include <hp300/dev/hilvar.h> +#include <hp300/dev/kbdmap.h> + +#include <machine/cpu.h> + +#include <vm/vm_param.h> +#include <vm/vm_map.h> +#include <vm/vm_kern.h> +#include <vm/vm_page.h> +#include <vm/vm_pager.h> + +#ifdef hp300 +#define NHIL 1 /* XXX */ +#else +#include "hil.h" +#endif + +struct hilloop hilloop[NHIL]; +struct _hilbell default_bell = { BELLDUR, BELLFREQ }; +#ifdef hp800 +int hilspl; +#endif + +#ifdef DEBUG +int hildebug = 0; +#define HDB_FOLLOW 0x01 +#define HDB_MMAP 0x02 +#define HDB_MASK 0x04 +#define HDB_CONFIG 0x08 +#define HDB_KEYBOARD 0x10 +#define HDB_IDMODULE 0x20 +#define HDB_EVENTS 0x80 +#endif + +#ifdef COMPAT_HPUX +extern struct emul emul_hpux; +#endif + +/* symbolic sleep message strings */ +char hilin[] = "hilin"; + +hilsoftinit(unit, hilbase) + int unit; + struct hil_dev *hilbase; +{ + register struct hilloop *hilp = &hilloop[unit]; + register int i; + +#ifdef DEBUG + if (hildebug & HDB_FOLLOW) + printf("hilsoftinit(%d, %x)\n", unit, hilbase); +#endif + /* + * Initialize loop information + */ + hilp->hl_addr = hilbase; + hilp->hl_cmdending = FALSE; + hilp->hl_actdev = hilp->hl_cmddev = 0; + hilp->hl_cmddone = FALSE; + hilp->hl_cmdbp = hilp->hl_cmdbuf; + hilp->hl_pollbp = hilp->hl_pollbuf; + hilp->hl_kbddev = 0; + hilp->hl_kbdlang = KBD_DEFAULT; + hilp->hl_kbdflags = 0; + /* + * Clear all queues and device associations with queues + */ + for (i = 0; i < NHILQ; i++) { + hilp->hl_queue[i].hq_eventqueue = NULL; + hilp->hl_queue[i].hq_procp = NULL; + hilp->hl_queue[i].hq_devmask = 0; + } + for (i = 0; i < NHILD; i++) + hilp->hl_device[i].hd_qmask = 0; + hilp->hl_device[HILLOOPDEV].hd_flags = (HIL_ALIVE|HIL_PSEUDO); +} + +hilinit(unit, hilbase) + int unit; + struct hil_dev *hilbase; +{ + register struct hilloop *hilp = &hilloop[unit]; +#ifdef DEBUG + if (hildebug & HDB_FOLLOW) + printf("hilinit(%d, %x)\n", unit, hilbase); +#endif + /* + * Initialize software (if not already done). + */ + if ((hilp->hl_device[HILLOOPDEV].hd_flags & HIL_ALIVE) == 0) + hilsoftinit(unit, hilbase); + /* + * Initialize hardware. + * Reset the loop hardware, and collect keyboard/id info + */ + hilreset(hilp); + hilinfo(unit); + kbdenable(unit); +} + +/* ARGSUSED */ +hilopen(dev, flags, mode, p) + dev_t dev; + int flags, mode; + struct proc *p; +{ + register struct hilloop *hilp = &hilloop[HILLOOP(dev)]; + register struct hilloopdev *dptr; + u_char device = HILUNIT(dev); + +#ifdef DEBUG + if (hildebug & HDB_FOLLOW) + printf("hilopen(%d): loop %x device %x\n", + p->p_pid, HILLOOP(dev), device); +#endif + + if ((hilp->hl_device[HILLOOPDEV].hd_flags & HIL_ALIVE) == 0) + return(ENXIO); + + dptr = &hilp->hl_device[device]; + if ((dptr->hd_flags & HIL_ALIVE) == 0) + return(ENODEV); + + /* + * Pseudo-devices cannot be read, nothing more to do. + */ + if (dptr->hd_flags & HIL_PSEUDO) + return(0); + + /* + * Open semantics: + * 1. Open devices have only one of HIL_READIN/HIL_QUEUEIN. + * 2. HPUX processes always get read syscall interface and + * must have exclusive use of the device. + * 3. BSD processes default to shared queue interface. + * Multiple processes can open the device. + */ +#ifdef COMPAT_HPUX + if (p->p_emul == &emul_hpux) { + if (dptr->hd_flags & (HIL_READIN|HIL_QUEUEIN)) + return(EBUSY); + dptr->hd_flags |= HIL_READIN; + } else +#endif + { + if (dptr->hd_flags & HIL_READIN) + return(EBUSY); + dptr->hd_flags |= HIL_QUEUEIN; + } + if (flags & FNONBLOCK) + dptr->hd_flags |= HIL_NOBLOCK; + /* + * It is safe to flush the read buffer as we are guarenteed + * that no one else is using it. + */ + if ((dptr->hd_flags & HIL_OPENED) == 0) { + dptr->hd_flags |= HIL_OPENED; + clalloc(&dptr->hd_queue, HILMAXCLIST, 0); + } + + send_hil_cmd(hilp->hl_addr, HIL_INTON, NULL, 0, NULL); + /* + * Opened the keyboard, put in raw mode. + */ + (void) splhil(); + if (device == hilp->hl_kbddev) { + u_char mask = 0; + send_hil_cmd(hilp->hl_addr, HIL_WRITEKBDSADR, &mask, 1, NULL); + hilp->hl_kbdflags |= KBD_RAW; +#ifdef DEBUG + if (hildebug & HDB_KEYBOARD) + printf("hilopen: keyboard %d raw\n", hilp->hl_kbddev); +#endif + } + (void) spl0(); + return (0); +} + +/* ARGSUSED */ +hilclose(dev, flags, mode, p) + dev_t dev; + int flags, mode; + struct proc *p; +{ + register struct hilloop *hilp = &hilloop[HILLOOP(dev)]; + register struct hilloopdev *dptr; + register int i; + u_char device = HILUNIT(dev); + char mask, lpctrl; + extern struct emul emul_netbsd; + +#ifdef DEBUG + if (hildebug & HDB_FOLLOW) + printf("hilclose(%d): device %x\n", p->p_pid, device); +#endif + + dptr = &hilp->hl_device[device]; + if (device && (dptr->hd_flags & HIL_PSEUDO)) + return (0); + + if (p && p->p_emul == &emul_netbsd) { + /* + * If this is the loop device, + * free up all queues belonging to this process. + */ + if (device == 0) { + for (i = 0; i < NHILQ; i++) + if (hilp->hl_queue[i].hq_procp == p) + (void) hilqfree(hilp, i); + } else { + mask = ~hildevmask(device); + (void) splhil(); + for (i = 0; i < NHILQ; i++) + if (hilp->hl_queue[i].hq_procp == p) { + dptr->hd_qmask &= ~hilqmask(i); + hilp->hl_queue[i].hq_devmask &= mask; + } + (void) spl0(); + } + } + /* + * The read buffer can go away. + */ + dptr->hd_flags &= ~(HIL_QUEUEIN|HIL_READIN|HIL_NOBLOCK|HIL_OPENED); + clfree(&dptr->hd_queue); + /* + * Set keyboard back to cooked mode when closed. + */ + (void) splhil(); + if (device && device == hilp->hl_kbddev) { + mask = 1 << (hilp->hl_kbddev - 1); + send_hil_cmd(hilp->hl_addr, HIL_WRITEKBDSADR, &mask, 1, NULL); + hilp->hl_kbdflags &= ~(KBD_RAW|KBD_AR1|KBD_AR2); + /* + * XXX: We have had trouble with keyboards remaining raw + * after close due to the LPC_KBDCOOK bit getting cleared + * somewhere along the line. Hence we check and reset + * LPCTRL if necessary. + */ + send_hil_cmd(hilp->hl_addr, HIL_READLPCTRL, NULL, 0, &lpctrl); + if ((lpctrl & LPC_KBDCOOK) == 0) { + printf("hilclose: bad LPCTRL %x, reset to %x\n", + lpctrl, lpctrl|LPC_KBDCOOK); + lpctrl |= LPC_KBDCOOK; + send_hil_cmd(hilp->hl_addr, HIL_WRITELPCTRL, + &lpctrl, 1, NULL); + } +#ifdef DEBUG + if (hildebug & HDB_KEYBOARD) + printf("hilclose: keyboard %d cooked\n", + hilp->hl_kbddev); +#endif + kbdenable(HILLOOP(dev)); + } + (void) spl0(); + return (0); +} + +/* + * Read interface to HIL device. + */ +hilread(dev, uio) + dev_t dev; + register struct uio *uio; +{ + struct hilloop *hilp = &hilloop[HILLOOP(dev)]; + register struct hilloopdev *dptr; + register int cc; + u_char device = HILUNIT(dev); + u_char buf[HILBUFSIZE]; + int error; + +#if 0 + /* + * XXX: Don't do this since HP-UX doesn't. + * + * Check device number. + * This check is necessary since loop can reconfigure. + */ + if (device > hilp->hl_maxdev) + return(ENODEV); +#endif + + dptr = &hilp->hl_device[device]; + if ((dptr->hd_flags & HIL_READIN) == 0) + return(ENODEV); + + (void) splhil(); + while (dptr->hd_queue.c_cc == 0) { + if (dptr->hd_flags & HIL_NOBLOCK) { + spl0(); + return(EWOULDBLOCK); + } + dptr->hd_flags |= HIL_ASLEEP; + if (error = tsleep((caddr_t)dptr, TTIPRI | PCATCH, hilin, 0)) { + (void) spl0(); + return (error); + } + } + (void) spl0(); + + error = 0; + while (uio->uio_resid > 0 && error == 0) { + cc = q_to_b(&dptr->hd_queue, buf, + min(uio->uio_resid, HILBUFSIZE)); + if (cc <= 0) + break; + error = uiomove(buf, cc, uio); + } + return(error); +} + +hilioctl(dev, cmd, data, flag, p) + dev_t dev; + int cmd, flag; + caddr_t data; + struct proc *p; +{ + register struct hilloop *hilp = &hilloop[HILLOOP(dev)]; + char device = HILUNIT(dev); + struct hilloopdev *dptr; + register int i; + u_char hold; + int error; + +#ifdef DEBUG + if (hildebug & HDB_FOLLOW) + printf("hilioctl(%d): dev %x cmd %x\n", + p->p_pid, device, cmd); +#endif + + dptr = &hilp->hl_device[device]; + if ((dptr->hd_flags & HIL_ALIVE) == 0) + return (ENODEV); + + /* + * Don't allow hardware ioctls on virtual devices. + * Note that though these are the BSD names, they have the same + * values as the HP-UX equivalents so we catch them as well. + */ + if (dptr->hd_flags & HIL_PSEUDO) { + switch (cmd) { + case HILIOCSC: + case HILIOCID: + case OHILIOCID: + case HILIOCRN: + case HILIOCRS: + case HILIOCED: + return(ENODEV); + + /* + * XXX: should also return ENODEV but HP-UX compat + * breaks if we do. They work ok right now because + * we only recognize one keyboard on the loop. This + * will have to change if we remove that restriction. + */ + case HILIOCAROFF: + case HILIOCAR1: + case HILIOCAR2: + break; + + default: + break; + } + } + +#ifdef COMPAT_HPUX + if (p->p_emul == &emul_hpux) + return(hpuxhilioctl(dev, cmd, data, flag)); +#endif + + hilp->hl_cmdbp = hilp->hl_cmdbuf; + bzero((caddr_t)hilp->hl_cmdbuf, HILBUFSIZE); + hilp->hl_cmddev = device; + error = 0; + switch (cmd) { + + case HILIOCSBP: + /* Send four data bytes to the tone gererator. */ + send_hil_cmd(hilp->hl_addr, HIL_STARTCMD, data, 4, NULL); + /* Send the trigger beeper command to the 8042. */ + send_hil_cmd(hilp->hl_addr, (cmd & 0xFF), NULL, 0, NULL); + break; + + case OHILIOCRRT: + case HILIOCRRT: + /* Transfer the real time to the 8042 data buffer */ + send_hil_cmd(hilp->hl_addr, (cmd & 0xFF), NULL, 0, NULL); + /* Read each byte of the real time */ + for (i = 0; i < 5; i++) { + send_hil_cmd(hilp->hl_addr, HIL_READTIME + i, NULL, + 0, &hold); + data[4-i] = hold; + } + break; + + case HILIOCRT: + for (i = 0; i < 4; i++) { + send_hil_cmd(hilp->hl_addr, (cmd & 0xFF) + i, + NULL, 0, &hold); + data[i] = hold; + } + break; + + case HILIOCID: + case OHILIOCID: + case HILIOCSC: + case HILIOCRN: + case HILIOCRS: + case HILIOCED: + send_hildev_cmd(hilp, device, (cmd & 0xFF)); + bcopy(hilp->hl_cmdbuf, data, hilp->hl_cmdbp-hilp->hl_cmdbuf); + break; + + case HILIOCAROFF: + case HILIOCAR1: + case HILIOCAR2: + if (hilp->hl_kbddev) { + hilp->hl_cmddev = hilp->hl_kbddev; + send_hildev_cmd(hilp, hilp->hl_kbddev, (cmd & 0xFF)); + hilp->hl_kbdflags &= ~(KBD_AR1|KBD_AR2); + if (cmd == HILIOCAR1) + hilp->hl_kbdflags |= KBD_AR1; + else if (cmd == HILIOCAR2) + hilp->hl_kbdflags |= KBD_AR2; + } + break; + + case HILIOCBEEP: + hilbeep(hilp, (struct _hilbell *)data); + break; + + case FIONBIO: + dptr = &hilp->hl_device[device]; + if (*(int *)data) + dptr->hd_flags |= HIL_NOBLOCK; + else + dptr->hd_flags &= ~HIL_NOBLOCK; + break; + + /* + * FIOASYNC must be present for FIONBIO above to work! + * (See fcntl in kern_descrip.c). + */ + case FIOASYNC: + break; + + case HILIOCALLOCQ: + error = hilqalloc(hilp, (struct hilqinfo *)data); + break; + + case HILIOCFREEQ: + error = hilqfree(hilp, ((struct hilqinfo *)data)->qid); + break; + + case HILIOCMAPQ: + error = hilqmap(hilp, *(int *)data, device); + break; + + case HILIOCUNMAPQ: + error = hilqunmap(hilp, *(int *)data, device); + break; + + case HILIOCHPUX: + dptr = &hilp->hl_device[device]; + dptr->hd_flags |= HIL_READIN; + dptr->hd_flags &= ~HIL_QUEUEIN; + break; + + case HILIOCRESET: + hilreset(hilp); + break; + +#ifdef DEBUG + case HILIOCTEST: + hildebug = *(int *) data; + break; +#endif + + default: + error = EINVAL; + break; + + } + hilp->hl_cmddev = 0; + return(error); +} + +#ifdef COMPAT_HPUX +/* ARGSUSED */ +hpuxhilioctl(dev, cmd, data, flag) + dev_t dev; + int cmd, flag; + caddr_t data; +{ + register struct hilloop *hilp = &hilloop[HILLOOP(dev)]; + char device = HILUNIT(dev); + struct hilloopdev *dptr; + register int i; + u_char hold; + + hilp->hl_cmdbp = hilp->hl_cmdbuf; + bzero((caddr_t)hilp->hl_cmdbuf, HILBUFSIZE); + hilp->hl_cmddev = device; + switch (cmd) { + + case HILSC: + case HILID: + case HILRN: + case HILRS: + case HILED: + case HILP1: + case HILP2: + case HILP3: + case HILP4: + case HILP5: + case HILP6: + case HILP7: + case HILP: + case HILA1: + case HILA2: + case HILA3: + case HILA4: + case HILA5: + case HILA6: + case HILA7: + case HILA: + send_hildev_cmd(hilp, device, (cmd & 0xFF)); + bcopy(hilp->hl_cmdbuf, data, hilp->hl_cmdbp-hilp->hl_cmdbuf); + break; + + case HILDKR: + case HILER1: + case HILER2: + if (hilp->hl_kbddev) { + hilp->hl_cmddev = hilp->hl_kbddev; + send_hildev_cmd(hilp, hilp->hl_kbddev, (cmd & 0xFF)); + hilp->hl_kbdflags &= ~(KBD_AR1|KBD_AR2); + if (cmd == HILIOCAR1) + hilp->hl_kbdflags |= KBD_AR1; + else if (cmd == HILIOCAR2) + hilp->hl_kbdflags |= KBD_AR2; + } + break; + + case EFTSBP: + /* Send four data bytes to the tone gererator. */ + send_hil_cmd(hilp->hl_addr, HIL_STARTCMD, data, 4, NULL); + /* Send the trigger beeper command to the 8042. */ + send_hil_cmd(hilp->hl_addr, (cmd & 0xFF), NULL, 0, NULL); + break; + + case EFTRRT: + /* Transfer the real time to the 8042 data buffer */ + send_hil_cmd(hilp->hl_addr, (cmd & 0xFF), NULL, 0, NULL); + /* Read each byte of the real time */ + for (i = 0; i < 5; i++) { + send_hil_cmd(hilp->hl_addr, HIL_READTIME + i, NULL, + 0, &hold); + data[4-i] = hold; + } + break; + + case EFTRT: + for (i = 0; i < 4; i++) { + send_hil_cmd(hilp->hl_addr, (cmd & 0xFF) + i, + NULL, 0, &hold); + data[i] = hold; + } + break; + + case EFTRLC: + case EFTRCC: + send_hil_cmd(hilp->hl_addr, (cmd & 0xFF), NULL, 0, &hold); + *data = hold; + break; + + case EFTSRPG: + case EFTSRD: + case EFTSRR: + send_hil_cmd(hilp->hl_addr, (cmd & 0xFF), data, 1, NULL); + break; + + case EFTSBI: +#ifdef hp800 + /* XXX big magic */ + hold = 7 - (*(u_char *)data >> 5); + *(int *)data = 0x84069008 | (hold << 8); + send_hil_cmd(hilp->hl_addr, HIL_STARTCMD, data, 4, NULL); + send_hil_cmd(hilp->hl_addr, 0xC4, NULL, 0, NULL); + break; +#else + hilbeep(hilp, (struct _hilbell *)data); +#endif + break; + + case FIONBIO: + dptr = &hilp->hl_device[device]; + if (*(int *)data) + dptr->hd_flags |= HIL_NOBLOCK; + else + dptr->hd_flags &= ~HIL_NOBLOCK; + break; + + case FIOASYNC: + break; + + default: + hilp->hl_cmddev = 0; + return(EINVAL); + } + hilp->hl_cmddev = 0; + return(0); +} +#endif + +/* ARGSUSED */ +hilmmap(dev, off, prot) + dev_t dev; + int off, prot; +{ +} + +/*ARGSUSED*/ +hilselect(dev, rw, p) + dev_t dev; + int rw; + struct proc *p; +{ + register struct hilloop *hilp = &hilloop[HILLOOP(dev)]; + register struct hilloopdev *dptr; + register struct hiliqueue *qp; + register int mask; + int s, device; + + if (rw == FWRITE) + return (1); + device = HILUNIT(dev); + + /* + * Read interface. + * Return 1 if there is something in the queue, 0 ow. + */ + dptr = &hilp->hl_device[device]; + if (dptr->hd_flags & HIL_READIN) { + s = splhil(); + if (dptr->hd_queue.c_cc) { + splx(s); + return (1); + } + selrecord(p, &dptr->hd_selr); + splx(s); + return (0); + } + + /* + * Make sure device is alive and real (or the loop device). + * Note that we do not do this for the read interface. + * This is primarily to be consistant with HP-UX. + */ + if (device && (dptr->hd_flags & (HIL_ALIVE|HIL_PSEUDO)) != HIL_ALIVE) + return (1); + + /* + * Select on loop device is special. + * Check to see if there are any data for any loop device + * provided it is associated with a queue belonging to this user. + */ + if (device == 0) + mask = -1; + else + mask = hildevmask(device); + /* + * Must check everybody with interrupts blocked to prevent races. + */ + s = splhil(); + for (qp = hilp->hl_queue; qp < &hilp->hl_queue[NHILQ]; qp++) + if (qp->hq_procp == p && (mask & qp->hq_devmask) && + qp->hq_eventqueue->hil_evqueue.head != + qp->hq_eventqueue->hil_evqueue.tail) { + splx(s); + return (1); + } + + selrecord(p, &dptr->hd_selr); + splx(s); + return (0); +} + +/*ARGSUSED*/ +hilint(unit) + int unit; +{ +#ifdef hp300 + struct hilloop *hilp = &hilloop[0]; /* XXX how do we know on 300? */ +#else + struct hilloop *hilp = &hilloop[unit]; +#endif + register struct hil_dev *hildevice = hilp->hl_addr; + u_char c, stat; + + stat = READHILSTAT(hildevice); + c = READHILDATA(hildevice); /* clears interrupt */ + hil_process_int(hilp, stat, c); +} + +#include "ite.h" + +hil_process_int(hilp, stat, c) + register struct hilloop *hilp; + register u_char stat, c; +{ +#ifdef DEBUG + if (hildebug & HDB_EVENTS) + printf("hilint: %x %x\n", stat, c); +#endif + + /* the shift enables the compiler to generate a jump table */ + switch ((stat>>HIL_SSHIFT) & HIL_SMASK) { + +#if NITE > 0 + case HIL_KEY: + case HIL_SHIFT: + case HIL_CTRL: + case HIL_CTRLSHIFT: + itefilter(stat, c); + return; +#endif + + case HIL_STATUS: /* The status info. */ + if (c & HIL_ERROR) { + hilp->hl_cmddone = TRUE; + if (c == HIL_RECONFIG) + hilconfig(hilp); + break; + } + if (c & HIL_COMMAND) { + if (c & HIL_POLLDATA) /* End of data */ + hilevent(hilp); + else /* End of command */ + hilp->hl_cmdending = TRUE; + hilp->hl_actdev = 0; + } else { + if (c & HIL_POLLDATA) { /* Start of polled data */ + if (hilp->hl_actdev != 0) + hilevent(hilp); + hilp->hl_actdev = (c & HIL_DEVMASK); + hilp->hl_pollbp = hilp->hl_pollbuf; + } else { /* Start of command */ + if (hilp->hl_cmddev == (c & HIL_DEVMASK)) { + hilp->hl_cmdbp = hilp->hl_cmdbuf; + hilp->hl_actdev = 0; + } + } + } + return; + + case HIL_DATA: + if (hilp->hl_actdev != 0) /* Collecting poll data */ + *hilp->hl_pollbp++ = c; + else if (hilp->hl_cmddev != 0) /* Collecting cmd data */ + if (hilp->hl_cmdending) { + hilp->hl_cmddone = TRUE; + hilp->hl_cmdending = FALSE; + } else + *hilp->hl_cmdbp++ = c; + return; + + case 0: /* force full jump table */ + default: + return; + } +} + +#if (defined(DDB) || defined(DEBUG)) && !defined(PANICBUTTON) +#define PANICBUTTON +#endif + +/* + * Optimized macro to compute: + * eq->head == (eq->tail + 1) % eq->size + * i.e. has tail caught up with head. We do this because 32 bit long + * remaidering is expensive (a function call with our compiler). + */ +#define HQFULL(eq) (((eq)->head?(eq)->head:(eq)->size) == (eq)->tail+1) +#define HQVALID(eq) \ + ((eq)->size == HEVQSIZE && (eq)->tail >= 0 && (eq)->tail < HEVQSIZE) + +hilevent(hilp) + struct hilloop *hilp; +{ + register struct hilloopdev *dptr = &hilp->hl_device[hilp->hl_actdev]; + register int len, mask, qnum; + register u_char *cp, *pp; + register HILQ *hq; + struct timeval ourtime; + hil_packet *proto; + int s, len0; + long tenths; + +#ifdef PANICBUTTON + static int first; + extern int panicbutton; + + cp = hilp->hl_pollbuf; + if (panicbutton && (*cp & HIL_KBDDATA)) { + if (*++cp == 0x4E) + first = 1; + else if (first && *cp == 0x46 && !panicstr) + panic("are we having fun yet?"); + else + first = 0; + } +#endif +#ifdef DEBUG + if (hildebug & HDB_EVENTS) { + printf("hilevent: dev %d pollbuf: ", hilp->hl_actdev); + printhilpollbuf(hilp); + printf("\n"); + } +#endif + + /* + * Note that HIL_READIN effectively "shuts off" any queues + * that may have been in use at the time of an HILIOCHPUX call. + */ + if (dptr->hd_flags & HIL_READIN) { + hpuxhilevent(hilp, dptr); + return; + } + + /* + * If this device isn't on any queue or there are no data + * in the packet (can this happen?) do nothing. + */ + if (dptr->hd_qmask == 0 || + (len0 = hilp->hl_pollbp - hilp->hl_pollbuf) <= 0) + return; + + /* + * Everybody gets the same time stamp + */ + s = splclock(); + ourtime = time; + splx(s); + tenths = (ourtime.tv_sec * 100) + (ourtime.tv_usec / 10000); + + proto = NULL; + mask = dptr->hd_qmask; + for (qnum = 0; mask; qnum++) { + if ((mask & hilqmask(qnum)) == 0) + continue; + mask &= ~hilqmask(qnum); + hq = hilp->hl_queue[qnum].hq_eventqueue; + + /* + * Ensure that queue fields that we rely on are valid + * and that there is space in the queue. If either + * test fails, we just skip this queue. + */ + if (!HQVALID(&hq->hil_evqueue) || HQFULL(&hq->hil_evqueue)) + continue; + + /* + * Copy data to queue. + * If this is the first queue we construct the packet + * with length, timestamp and poll buffer data. + * For second and sucessive packets we just duplicate + * the first packet. + */ + pp = (u_char *) &hq->hil_event[hq->hil_evqueue.tail]; + if (proto == NULL) { + proto = (hil_packet *)pp; + cp = hilp->hl_pollbuf; + len = len0; + *pp++ = len + 6; + *pp++ = hilp->hl_actdev; + *(long *)pp = tenths; + pp += sizeof(long); + do *pp++ = *cp++; while (--len); + } else + *(hil_packet *)pp = *proto; + + if (++hq->hil_evqueue.tail == hq->hil_evqueue.size) + hq->hil_evqueue.tail = 0; + } + + /* + * Wake up anyone selecting on this device or the loop itself + */ + selwakeup(&dptr->hd_selr); + dptr = &hilp->hl_device[HILLOOPDEV]; + selwakeup(&dptr->hd_selr); +} + +#undef HQFULL + +hpuxhilevent(hilp, dptr) + register struct hilloop *hilp; + register struct hilloopdev *dptr; +{ + register int len; + struct timeval ourtime; + long tstamp; + int s; + + /* + * Everybody gets the same time stamp + */ + s = splclock(); + ourtime = time; + splx(s); + tstamp = (ourtime.tv_sec * 100) + (ourtime.tv_usec / 10000); + + /* + * Each packet that goes into the buffer must be preceded by the + * number of bytes in the packet, and the timestamp of the packet. + * This adds 5 bytes to the packet size. Make sure there is enough + * room in the buffer for it, and if not, toss the packet. + */ + len = hilp->hl_pollbp - hilp->hl_pollbuf; + if (dptr->hd_queue.c_cc <= (HILMAXCLIST - (len+5))) { + putc(len+5, &dptr->hd_queue); + (void) b_to_q((u_char *)&tstamp, sizeof tstamp, &dptr->hd_queue); + (void) b_to_q((u_char *)hilp->hl_pollbuf, len, &dptr->hd_queue); + } + + /* + * Wake up any one blocked on a read or select + */ + if (dptr->hd_flags & HIL_ASLEEP) { + dptr->hd_flags &= ~HIL_ASLEEP; + wakeup((caddr_t)dptr); + } + selwakeup(&dptr->hd_selr); +} + +/* + * Shared queue manipulation routines + */ + +hilqalloc(hilp, qip) + register struct hilloop *hilp; + struct hilqinfo *qip; +{ + struct proc *p = curproc; /* XXX */ + +#ifdef DEBUG + if (hildebug & HDB_FOLLOW) + printf("hilqalloc(%d): addr %x\n", p->p_pid, qip->addr); +#endif + return(EINVAL); +} + +hilqfree(hilp, qnum) + register struct hilloop *hilp; + register int qnum; +{ + struct proc *p = curproc; /* XXX */ + +#ifdef DEBUG + if (hildebug & HDB_FOLLOW) + printf("hilqfree(%d): qnum %d\n", p->p_pid, qnum); +#endif + return(EINVAL); +} + +hilqmap(hilp, qnum, device) + register struct hilloop *hilp; + register int qnum, device; +{ + struct proc *p = curproc; /* XXX */ + register struct hilloopdev *dptr = &hilp->hl_device[device]; + int s; + +#ifdef DEBUG + if (hildebug & HDB_FOLLOW) + printf("hilqmap(%d): qnum %d device %x\n", + p->p_pid, qnum, device); +#endif + if (qnum >= NHILQ || hilp->hl_queue[qnum].hq_procp != p) + return(EINVAL); + if ((dptr->hd_flags & HIL_QUEUEIN) == 0) + return(EINVAL); + if (dptr->hd_qmask && p->p_ucred->cr_uid && + p->p_ucred->cr_uid != dptr->hd_uid) + return(EPERM); + + hilp->hl_queue[qnum].hq_devmask |= hildevmask(device); + if (dptr->hd_qmask == 0) + dptr->hd_uid = p->p_ucred->cr_uid; + s = splhil(); + dptr->hd_qmask |= hilqmask(qnum); + splx(s); +#ifdef DEBUG + if (hildebug & HDB_MASK) + printf("hilqmap(%d): devmask %x qmask %x\n", + p->p_pid, hilp->hl_queue[qnum].hq_devmask, + dptr->hd_qmask); +#endif + return(0); +} + +hilqunmap(hilp, qnum, device) + register struct hilloop *hilp; + register int qnum, device; +{ + struct proc *p = curproc; /* XXX */ + int s; + +#ifdef DEBUG + if (hildebug & HDB_FOLLOW) + printf("hilqunmap(%d): qnum %d device %x\n", + p->p_pid, qnum, device); +#endif + + if (qnum >= NHILQ || hilp->hl_queue[qnum].hq_procp != p) + return(EINVAL); + + hilp->hl_queue[qnum].hq_devmask &= ~hildevmask(device); + s = splhil(); + hilp->hl_device[device].hd_qmask &= ~hilqmask(qnum); + splx(s); +#ifdef DEBUG + if (hildebug & HDB_MASK) + printf("hilqunmap(%d): devmask %x qmask %x\n", + p->p_pid, hilp->hl_queue[qnum].hq_devmask, + hilp->hl_device[device].hd_qmask); +#endif + return(0); +} + +/* + * Cooked keyboard functions for ite driver. + * There is only one "cooked" ITE keyboard (the first keyboard found) + * per loop. There may be other keyboards, but they will always be "raw". + */ + +kbdbell(unit) + int unit; +{ + struct hilloop *hilp = &hilloop[unit]; + + hilbeep(hilp, &default_bell); +} + +kbdenable(unit) + int unit; +{ + struct hilloop *hilp = &hilloop[unit]; + register struct hil_dev *hildevice = hilp->hl_addr; + char db; + + /* Set the autorepeat rate register */ + db = ar_format(KBD_ARR); + send_hil_cmd(hildevice, HIL_SETARR, &db, 1, NULL); + + /* Set the autorepeat delay register */ + db = ar_format(KBD_ARD); + send_hil_cmd(hildevice, HIL_SETARD, &db, 1, NULL); + + /* Enable interrupts */ + send_hil_cmd(hildevice, HIL_INTON, NULL, 0, NULL); +} + +kbddisable(unit) + int unit; +{ +} + +/* + * XXX: read keyboard directly and return code. + * Used by console getchar routine. Could really screw up anybody + * reading from the keyboard in the normal, interrupt driven fashion. + */ +kbdgetc(unit, statp) + int unit, *statp; +{ + struct hilloop *hilp = &hilloop[unit]; + register struct hil_dev *hildevice = hilp->hl_addr; + register int c, stat; + int s; + + s = splhil(); + while (((stat = READHILSTAT(hildevice)) & HIL_DATA_RDY) == 0) + ; + c = READHILDATA(hildevice); + splx(s); + *statp = stat; + return(c); +} + +/* + * Recoginize and clear keyboard generated NMIs. + * Returns 1 if it was ours, 0 otherwise. Note that we cannot use + * send_hil_cmd() to issue the clear NMI command as that would actually + * lower the priority to splimp() and it doesn't wait for the completion + * of the command. Either of these conditions could result in the + * interrupt reoccuring. Note that we issue the CNMT command twice. + * This seems to be needed, once is not always enough!?! + */ +kbdnmi(unit) + int unit; +{ +#ifdef hp300 + struct hilloop *hilp = &hilloop[0]; /* XXX how do we know on 300? */ +#else + struct hilloop *hilp = &hilloop[unit]; +#endif +#ifdef hp300 + if ((*KBDNMISTAT & KBDNMI) == 0) + return(0); +#endif + HILWAIT(hilp->hl_addr); + WRITEHILCMD(hilp->hl_addr, HIL_CNMT); + HILWAIT(hilp->hl_addr); + WRITEHILCMD(hilp->hl_addr, HIL_CNMT); + HILWAIT(hilp->hl_addr); + return(1); +} + +#define HILSECURITY 0x33 +#define HILIDENTIFY 0x03 +#define HILSCBIT 0x04 + +/* + * Called at boot time to print out info about interesting devices + */ +hilinfo(unit) + int unit; +{ + register struct hilloop *hilp = &hilloop[unit]; + register int id, len; + register struct kbdmap *km; + + /* + * Keyboard info. + */ + if (hilp->hl_kbddev) { + printf("hil%d: ", hilp->hl_kbddev); + for (km = kbd_map; km->kbd_code; km++) + if (km->kbd_code == hilp->hl_kbdlang) { + printf("%s ", km->kbd_desc); + break; + } + printf("keyboard\n"); + } + /* + * ID module. + * Attempt to locate the first ID module and print out its + * security code. Is this a good idea?? + */ + id = hiliddev(hilp); + if (id) { + hilp->hl_cmdbp = hilp->hl_cmdbuf; + hilp->hl_cmddev = id; + send_hildev_cmd(hilp, id, HILSECURITY); + len = hilp->hl_cmdbp - hilp->hl_cmdbuf; + hilp->hl_cmdbp = hilp->hl_cmdbuf; + hilp->hl_cmddev = 0; + printf("hil%d: security code", id); + for (id = 0; id < len; id++) + printf(" %x", hilp->hl_cmdbuf[id]); + while (id++ < 16) + printf(" 0"); + printf("\n"); + } +} + +#define HILAR1 0x3E +#define HILAR2 0x3F + +/* + * Called after the loop has reconfigured. Here we need to: + * - determine how many devices are on the loop + * (some may have been added or removed) + * - locate the ITE keyboard (if any) and ensure + * that it is in the proper state (raw or cooked) + * and is set to use the proper language mapping table + * - ensure all other keyboards are raw + * Note that our device state is now potentially invalid as + * devices may no longer be where they were. What we should + * do here is either track where the devices went and move + * state around accordingly or, more simply, just mark all + * devices as HIL_DERROR and don't allow any further use until + * they are closed. This is a little too brutal for my tastes, + * we prefer to just assume people won't move things around. + */ +hilconfig(hilp) + register struct hilloop *hilp; +{ + u_char db; + int s; + + s = splhil(); +#ifdef DEBUG + if (hildebug & HDB_CONFIG) { + printf("hilconfig: reconfigured: "); + send_hil_cmd(hilp->hl_addr, HIL_READLPSTAT, NULL, 0, &db); + printf("LPSTAT %x, ", db); + send_hil_cmd(hilp->hl_addr, HIL_READLPCTRL, NULL, 0, &db); + printf("LPCTRL %x, ", db); + send_hil_cmd(hilp->hl_addr, HIL_READKBDSADR, NULL, 0, &db); + printf("KBDSADR %x\n", db); + hilreport(hilp); + } +#endif + /* + * Determine how many devices are on the loop. + * Mark those as alive and real, all others as dead. + */ + db = 0; + send_hil_cmd(hilp->hl_addr, HIL_READLPSTAT, NULL, 0, &db); + hilp->hl_maxdev = db & LPS_DEVMASK; +#ifdef DEBUG + if (hildebug & HDB_CONFIG) + printf("hilconfig: %d devices found\n", hilp->hl_maxdev); +#endif + for (db = 1; db < NHILD; db++) { + if (db <= hilp->hl_maxdev) + hilp->hl_device[db].hd_flags |= HIL_ALIVE; + else + hilp->hl_device[db].hd_flags &= ~HIL_ALIVE; + hilp->hl_device[db].hd_flags &= ~HIL_PSEUDO; + } +#ifdef DEBUG + if (hildebug & (HDB_CONFIG|HDB_KEYBOARD)) + printf("hilconfig: max device %d\n", hilp->hl_maxdev); +#endif + if (hilp->hl_maxdev == 0) { + hilp->hl_kbddev = 0; + splx(s); + return; + } + /* + * Find out where the keyboards are and record the ITE keyboard + * (first one found). If no keyboards found, we are all done. + */ + db = 0; + send_hil_cmd(hilp->hl_addr, HIL_READKBDSADR, NULL, 0, &db); +#ifdef DEBUG + if (hildebug & HDB_KEYBOARD) + printf("hilconfig: keyboard: KBDSADR %x, old %d, new %d\n", + db, hilp->hl_kbddev, ffs((int)db)); +#endif + hilp->hl_kbddev = ffs((int)db); + if (hilp->hl_kbddev == 0) { + splx(s); + return; + } + /* + * Determine if the keyboard should be cooked or raw and configure it. + */ + db = (hilp->hl_kbdflags & KBD_RAW) ? 0 : 1 << (hilp->hl_kbddev - 1); + send_hil_cmd(hilp->hl_addr, HIL_WRITEKBDSADR, &db, 1, NULL); + /* + * Re-enable autorepeat in raw mode, cooked mode AR is not affected. + */ + if (hilp->hl_kbdflags & (KBD_AR1|KBD_AR2)) { + db = (hilp->hl_kbdflags & KBD_AR1) ? HILAR1 : HILAR2; + hilp->hl_cmddev = hilp->hl_kbddev; + send_hildev_cmd(hilp, hilp->hl_kbddev, db); + hilp->hl_cmddev = 0; + } + /* + * Determine the keyboard language configuration, but don't + * override a user-specified setting. + */ + db = 0; + send_hil_cmd(hilp->hl_addr, HIL_READKBDLANG, NULL, 0, &db); +#ifdef DEBUG + if (hildebug & HDB_KEYBOARD) + printf("hilconfig: language: old %x new %x\n", + hilp->hl_kbdlang, db); +#endif + if (hilp->hl_kbdlang != KBD_SPECIAL) { + struct kbdmap *km; + + for (km = kbd_map; km->kbd_code; km++) + if (km->kbd_code == db) { + hilp->hl_kbdlang = db; + /* XXX */ + kbd_keymap = km->kbd_keymap; + kbd_shiftmap = km->kbd_shiftmap; + kbd_ctrlmap = km->kbd_ctrlmap; + kbd_ctrlshiftmap = km->kbd_ctrlshiftmap; + kbd_stringmap = km->kbd_stringmap; + } + } + splx(s); +} + +hilreset(hilp) + struct hilloop *hilp; +{ + register struct hil_dev *hildevice = hilp->hl_addr; + u_char db; + +#ifdef DEBUG + if (hildebug & HDB_FOLLOW) + printf("hilreset(%x)\n", hilp); +#endif + /* + * Initialize the loop: reconfigure, don't report errors, + * cook keyboards, and enable autopolling. + */ + db = LPC_RECONF | LPC_KBDCOOK | LPC_NOERROR | LPC_AUTOPOLL; + send_hil_cmd(hildevice, HIL_WRITELPCTRL, &db, 1, NULL); + /* + * Delay one second for reconfiguration and then read the the + * data register to clear the interrupt (if the loop reconfigured). + */ + DELAY(1000000); + if (READHILSTAT(hildevice) & HIL_DATA_RDY) + db = READHILDATA(hildevice); + /* + * The HIL loop may have reconfigured. If so we proceed on, + * if not we loop until a successful reconfiguration is reported + * back to us. The HIL loop will continue to attempt forever. + * Probably not very smart. + */ + do { + send_hil_cmd(hildevice, HIL_READLPSTAT, NULL, 0, &db); + } while ((db & (LPS_CONFFAIL|LPS_CONFGOOD)) == 0); + /* + * At this point, the loop should have reconfigured. + * The reconfiguration interrupt has already called hilconfig() + * so the keyboard has been determined. + */ + send_hil_cmd(hildevice, HIL_INTON, NULL, 0, NULL); +} + +hilbeep(hilp, bp) + struct hilloop *hilp; + register struct _hilbell *bp; +{ + u_char buf[2]; + + buf[0] = ~((bp->duration - 10) / 10); + buf[1] = bp->frequency; + send_hil_cmd(hilp->hl_addr, HIL_SETTONE, buf, 2, NULL); +} + +/* + * Locate and return the address of the first ID module, 0 if none present. + */ +hiliddev(hilp) + register struct hilloop *hilp; +{ + register int i, len; + +#ifdef DEBUG + if (hildebug & HDB_IDMODULE) + printf("hiliddev(%x): max %d, looking for idmodule...", + hilp, hilp->hl_maxdev); +#endif + for (i = 1; i <= hilp->hl_maxdev; i++) { + hilp->hl_cmdbp = hilp->hl_cmdbuf; + hilp->hl_cmddev = i; + send_hildev_cmd(hilp, i, HILIDENTIFY); + /* + * XXX: the final condition checks to ensure that the + * device ID byte is in the range of the ID module (0x30-0x3F) + */ + len = hilp->hl_cmdbp - hilp->hl_cmdbuf; + if (len > 1 && (hilp->hl_cmdbuf[1] & HILSCBIT) && + (hilp->hl_cmdbuf[0] & 0xF0) == 0x30) { + hilp->hl_cmdbp = hilp->hl_cmdbuf; + hilp->hl_cmddev = i; + send_hildev_cmd(hilp, i, HILSECURITY); + break; + } + } + hilp->hl_cmdbp = hilp->hl_cmdbuf; + hilp->hl_cmddev = 0; +#ifdef DEBUG + if (hildebug & HDB_IDMODULE) + if (i <= hilp->hl_maxdev) + printf("found at %d\n", i); + else + printf("not found\n"); +#endif + return(i <= hilp->hl_maxdev ? i : 0); +} + +#ifdef COMPAT_HPUX +/* + * XXX map devno as expected by HP-UX + */ +hildevno(dev) + dev_t dev; +{ + int newdev; + + newdev = 24 << 24; +#ifdef HILCOMPAT + /* + * XXX compat check + * Don't convert old style specfiles already in correct format + */ + if (minor(dev) && (dev & 0xF) == 0) + newdev |= minor(dev); + else +#endif + newdev |= (HILLOOP(dev) << 8) | (HILUNIT(dev) << 4); + return(newdev); +} +#endif + +/* + * Low level routines which actually talk to the 8042 chip. + */ + +/* + * Send a command to the 8042 with zero or more bytes of data. + * If rdata is non-null, wait for and return a byte of data. + * We run at splimp() to make the transaction as atomic as + * possible without blocking the clock (is this necessary?) + */ +send_hil_cmd(hildevice, cmd, data, dlen, rdata) + register struct hil_dev *hildevice; + u_char cmd, *data, dlen; + u_char *rdata; +{ + u_char status; + int s = splimp(); + + HILWAIT(hildevice); + WRITEHILCMD(hildevice, cmd); + while (dlen--) { + HILWAIT(hildevice); + WRITEHILDATA(hildevice, *data++); + } + if (rdata) { + do { + HILDATAWAIT(hildevice); + status = READHILSTAT(hildevice); + *rdata = READHILDATA(hildevice); + } while (((status >> HIL_SSHIFT) & HIL_SMASK) != HIL_68K); + } + splx(s); +} + +/* + * Send a command to a device on the loop. + * Since only one command can be active on the loop at any time, + * we must ensure that we are not interrupted during this process. + * Hence we mask interrupts to prevent potential access from most + * interrupt routines and turn off auto-polling to disable the + * internally generated poll commands. + * + * splhigh is extremely conservative but insures atomic operation, + * splimp (clock only interrupts) seems to be good enough in practice. + */ +send_hildev_cmd(hilp, device, cmd) + register struct hilloop *hilp; + char device, cmd; +{ + register struct hil_dev *hildevice = hilp->hl_addr; + u_char status, c; + int s = splimp(); + + polloff(hildevice); + + /* + * Transfer the command and device info to the chip + */ + HILWAIT(hildevice); + WRITEHILCMD(hildevice, HIL_STARTCMD); + HILWAIT(hildevice); + WRITEHILDATA(hildevice, 8 + device); + HILWAIT(hildevice); + WRITEHILDATA(hildevice, cmd); + HILWAIT(hildevice); + WRITEHILDATA(hildevice, HIL_TIMEOUT); + /* + * Trigger the command and wait for completion + */ + HILWAIT(hildevice); + WRITEHILCMD(hildevice, HIL_TRIGGER); + hilp->hl_cmddone = FALSE; + do { + HILDATAWAIT(hildevice); + status = READHILSTAT(hildevice); + c = READHILDATA(hildevice); + hil_process_int(hilp, status, c); + } while (!hilp->hl_cmddone); + + pollon(hildevice); + splx(s); +} + +/* + * Turn auto-polling off and on. + * Also disables and enable auto-repeat. Why? + */ +polloff(hildevice) + register struct hil_dev *hildevice; +{ + register char db; + + /* + * Turn off auto repeat + */ + HILWAIT(hildevice); + WRITEHILCMD(hildevice, HIL_SETARR); + HILWAIT(hildevice); + WRITEHILDATA(hildevice, 0); + /* + * Turn off auto-polling + */ + HILWAIT(hildevice); + WRITEHILCMD(hildevice, HIL_READLPCTRL); + HILDATAWAIT(hildevice); + db = READHILDATA(hildevice); + db &= ~LPC_AUTOPOLL; + HILWAIT(hildevice); + WRITEHILCMD(hildevice, HIL_WRITELPCTRL); + HILWAIT(hildevice); + WRITEHILDATA(hildevice, db); + /* + * Must wait til polling is really stopped + */ + do { + HILWAIT(hildevice); + WRITEHILCMD(hildevice, HIL_READBUSY); + HILDATAWAIT(hildevice); + db = READHILDATA(hildevice); + } while (db & BSY_LOOPBUSY); +} + +pollon(hildevice) + register struct hil_dev *hildevice; +{ + register char db; + + /* + * Turn on auto polling + */ + HILWAIT(hildevice); + WRITEHILCMD(hildevice, HIL_READLPCTRL); + HILDATAWAIT(hildevice); + db = READHILDATA(hildevice); + db |= LPC_AUTOPOLL; + HILWAIT(hildevice); + WRITEHILCMD(hildevice, HIL_WRITELPCTRL); + HILWAIT(hildevice); + WRITEHILDATA(hildevice, db); + /* + * Turn on auto repeat + */ + HILWAIT(hildevice); + WRITEHILCMD(hildevice, HIL_SETARR); + HILWAIT(hildevice); + WRITEHILDATA(hildevice, ar_format(KBD_ARR)); +} + +#ifdef DEBUG +printhilpollbuf(hilp) + register struct hilloop *hilp; +{ + register u_char *cp; + register int i, len; + + cp = hilp->hl_pollbuf; + len = hilp->hl_pollbp - cp; + for (i = 0; i < len; i++) + printf("%x ", hilp->hl_pollbuf[i]); + printf("\n"); +} + +printhilcmdbuf(hilp) + register struct hilloop *hilp; +{ + register u_char *cp; + register int i, len; + + cp = hilp->hl_cmdbuf; + len = hilp->hl_cmdbp - cp; + for (i = 0; i < len; i++) + printf("%x ", hilp->hl_cmdbuf[i]); + printf("\n"); +} + +hilreport(hilp) + register struct hilloop *hilp; +{ + register int i, len; + int s = splhil(); + + for (i = 1; i <= hilp->hl_maxdev; i++) { + hilp->hl_cmdbp = hilp->hl_cmdbuf; + hilp->hl_cmddev = i; + send_hildev_cmd(hilp, i, HILIDENTIFY); + printf("hil%d: id: ", i); + printhilcmdbuf(hilp); + len = hilp->hl_cmdbp - hilp->hl_cmdbuf; + if (len > 1 && (hilp->hl_cmdbuf[1] & HILSCBIT)) { + hilp->hl_cmdbp = hilp->hl_cmdbuf; + hilp->hl_cmddev = i; + send_hildev_cmd(hilp, i, HILSECURITY); + printf("hil%d: sc: ", i); + printhilcmdbuf(hilp); + } + } + hilp->hl_cmdbp = hilp->hl_cmdbuf; + hilp->hl_cmddev = 0; + splx(s); +} +#endif |