📄 hil.c
字号:
/* 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 HPUXCOMPAT/* * 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 DEBUGprinthilpollbuf(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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -