📄 hil.c
字号:
/* * 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 <hp/dev/hilreg.h>#include <hp/dev/hilioctl.h>#include <hp/dev/hilvar.h>#include <hp/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"#endifstruct hilloop hilloop[NHIL];struct _hilbell default_bell = { BELLDUR, BELLFREQ };#ifdef hp800int hilspl;#endif#ifdef DEBUGint 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/* 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. */ if (p->p_md.md_flags & MDP_HPUX) { if (dptr->hd_flags & (HIL_READIN|HIL_QUEUEIN)) return(EBUSY); dptr->hd_flags |= HIL_READIN; } else { 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. */ ndflush(&dptr->hd_queue, dptr->hd_queue.c_cc); 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;#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_md.md_flags & MDP_HPUX) == 0) { /* * 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(); } } /* * Always flush the read buffer */ dptr->hd_flags &= ~(HIL_QUEUEIN|HIL_READIN|HIL_NOBLOCK); ndflush(&dptr->hd_queue, dptr->hd_queue.c_cc); /* * 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); 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 = hilq_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 HPUXCOMPAT if (p->p_md.md_flags & MDP_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 HPUXCOMPAT/* 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:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -