📄 pcvt_kbd.c
字号:
/* * Copyright (c) 1992, 1995 Hellmuth Michaelis and Joerg Wunsch. * * Copyright (c) 1992, 1993 Brian Dunford-Shore and Holger Veit. * * All rights reserved. * * This code is derived from software contributed to Berkeley by * William Jolitz and Don Ahn. * * This code is derived from software contributed to 386BSD by * Holger Veit. * * 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 Hellmuth Michaelis, * Brian Dunford-Shore and Joerg Wunsch. * 4. The name authors may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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. * * * @(#)pcvt_kbd.c, 3.20, Last Edit-Date: [Sun Apr 2 18:59:04 1995] * *//*---------------------------------------------------------------------------* * * pcvt_kbd.c VT220 Driver Keyboard Interface Code * ---------------------------------------------------- * -hm ------------ Release 3.00 -------------- * -hm integrating NetBSD-current patches * -jw introduced kbd_emulate_pc() if scanset > 1 * -hm patch from joerg for timeout in kbd_emulate_pc() * -hm starting to implement alt-shift/ctrl key mappings * -hm Gateway 2000 Keyboard fix from Brian Moore * -hm some #if adjusting for NetBSD 0.9 * -hm split off pcvt_kbd.h * -hm applying Joerg's patches for FreeBSD 2.0 * -hm patch from Martin, PCVT_NO_LED_UPDATE * -hm PCVT_VT220KEYB patches from Lon Willet * -hm PR #399, patch from Bill Sommerfeld: Return with PCVT_META_ESC * -hm allow keyboard-less kernel boot for serial consoles and such .. * -hm patch from Lon Willett for led-update and showkey() * -hm patch from Lon Willett to fix mapping of Control-R scancode * -hm delay patch from Martin Husemann after port-i386 ml-discussion * -hm added PCVT_NONRESP_KEYB_TRY definition to doreset() * *---------------------------------------------------------------------------*/#include "vt.h"#include "opt_ddb.h"#if NVT > 0#include <i386/isa/pcvt/pcvt_hdr.h> /* global include */#define LEDSTATE_UPDATE_PENDING (1 << 3)static void fkey1(void), fkey2(void), fkey3(void), fkey4(void);static void fkey5(void), fkey6(void), fkey7(void), fkey8(void);static void fkey9(void), fkey10(void), fkey11(void), fkey12(void);static void sfkey1(void), sfkey2(void), sfkey3(void), sfkey4(void);static void sfkey5(void), sfkey6(void), sfkey7(void), sfkey8(void);static void sfkey9(void), sfkey10(void), sfkey11(void), sfkey12(void);static void cfkey1(void), cfkey2(void), cfkey3(void), cfkey4(void);static void cfkey5(void), cfkey6(void), cfkey7(void), cfkey8(void);static void cfkey9(void), cfkey10(void), cfkey11(void), cfkey12(void);static void doreset ( void );static void ovlinit ( int force );static void settpmrate ( int rate );static void setlockkeys ( int snc );#ifndef _I386_ISA_KBDIO_H_static int kbc_8042cmd ( int val );#elsestatic int set_keyboard_param( int command, int data );#endif /* !_I386_ISA_KBDIO_H_ */static int getokeydef ( unsigned key, struct kbd_ovlkey *thisdef );static int getckeydef ( unsigned key, struct kbd_ovlkey *thisdef );static int rmkeydef ( int key );static int setkeydef ( struct kbd_ovlkey *data );static u_char * xlatkey2ascii( U_short key );static int ledstate = LEDSTATE_UPDATE_PENDING; /* keyboard led's */static int tpmrate = KBD_TPD500|KBD_TPM100;static u_char altkpflag = 0;static u_short altkpval = 0;#if PCVT_SHOWKEYSu_char rawkeybuf[80];#endif#include <i386/isa/pcvt/pcvt_kbd.h> /* tables etc */#if PCVT_SHOWKEYS/*---------------------------------------------------------------------------* * keyboard debugging: put kbd communication char into some buffer *---------------------------------------------------------------------------*/static void showkey (char delim, u_char val){ int rki; for(rki = 3; rki < 80; rki++) /* shift left buffer */ rawkeybuf[rki-3] = rawkeybuf[rki]; rawkeybuf[77] = delim; /* delimiter */ rki = (val & 0xf0) >> 4; /* ms nibble */ if(rki <= 9) rki = rki + '0'; else rki = rki - 10 + 'A'; rawkeybuf[78] = rki; rki = val & 0x0f; /* ls nibble */ if(rki <= 9) rki = rki + '0'; else rki = rki - 10 + 'A'; rawkeybuf[79] = rki;}#endif /* PCVT_SHOWKEYS *//*---------------------------------------------------------------------------* * function to switch to another virtual screen *---------------------------------------------------------------------------*/static voiddo_vgapage(int page){ if(critical_scroll) /* executing critical region ? */ switch_page = page; /* yes, auto switch later */ else vgapage(page); /* no, switch now */}/* * This code from Lon Willett enclosed in #if PCVT_UPDLED_LOSES_INTR is * abled because it crashes FreeBSD 1.1.5.1 at boot time. * The cause is obviously that the timeout queue is not yet initialized * timeout is called from here the first time. * Anyway it is a pointer in the right direction so it is included for * reference here. */#define PCVT_UPDLED_LOSES_INTR 0 /* disabled for now */#if PCVT_UPDLED_LOSES_INTR || defined(_I386_ISA_KBDIO_H_)/*---------------------------------------------------------------------------* * check for lost keyboard interrupts *---------------------------------------------------------------------------*//* * The two commands to change the LEDs generate two KEYB_R_ACK responses * from the keyboard, which aren't explicitly checked for (maybe they * should be?). However, when a lot of other I/O is happening, one of * the interrupts sometimes gets lost (I'm not sure of the details of * how and why and what hardware this happens with). * * This may have had something to do with spltty() previously not being * called before the kbd_cmd() calls in update_led(). * * This is a real problem, because normally the keyboard is only polled * by pcrint(), and no more interrupts will be generated until the ACK * has been read. So the keyboard is hung. This code polls a little * while after changing the LEDs to make sure that this hasn't happened. * * XXX Quite possibly we should poll the kbd on a regular basis anyway, * in the interest of robustness. It may be possible that interrupts * get lost other times as well. */static int lost_intr_timeout_queued = 0;static voidcheck_for_lost_intr (void *arg){#ifndef _I386_ISA_KBDIO_H_ lost_intr_timeout_queued = 0; if (inb(CONTROLLER_CTRL) & STATUS_OUTPBF) { int opri = spltty (); pcrint (); splx (opri); }#else int opri; lost_intr_timeout_queued = 0; if (kbdc_lock(kbdc, TRUE)) { opri = spltty (); kbdc_lock(kbdc, FALSE); if (kbdc_data_ready(kbdc)) pcrint (0); splx (opri); } timeout(check_for_lost_intr, (void *)NULL, hz); lost_intr_timeout_queued = 1;#endif /* !_I386_ISA_KBDIO_H_ */}#endif /* PCVT_UPDLED_LOSES_INTR || defined(_I386_ISA_KBDIO_H_) *//*---------------------------------------------------------------------------* * update keyboard led's *---------------------------------------------------------------------------*/voidupdate_led(void){#if !PCVT_NO_LED_UPDATE /* Don't update LED's unless necessary. */ int opri, new_ledstate, response1, response2; opri = spltty(); new_ledstate = (vsp->scroll_lock) | (vsp->num_lock * 2) | (vsp->caps_lock * 4); if (new_ledstate != ledstate) {#ifndef _I386_ISA_KBDIO_H_ ledstate = LEDSTATE_UPDATE_PENDING; if(kbd_cmd(KEYB_C_LEDS) != 0) { printf("Keyboard LED command timeout\n"); splx(opri); return; } /* * For some keyboards or keyboard controllers, it is an * error to issue a command without waiting long enough * for an ACK for the previous command. The keyboard * gets confused, and responds with KEYB_R_RESEND, but * we ignore that. Wait for the ACK here. The busy * waiting doesn't matter much, since we lose anyway by * busy waiting to send the command. * * XXX actually wait for any response, since we can't * handle normal scancodes here. * * XXX all this should be interrupt driven. Issue only * one command at a time wait for a ACK before proceeding. * Retry after a timeout or on receipt of a KEYB_R_RESEND. * KEYB_R_RESENDs seem to be guaranteed by working * keyboard controllers with broken (or disconnected) * keyboards. There is another code for keyboard * reconnects. The keyboard hardware is very simple and * well designed :-). */ response1 = kbd_response(); if(kbd_cmd(new_ledstate) != 0) { printf("Keyboard LED data timeout\n"); splx(opri); return; } response2 = kbd_response(); if (response1 == KEYB_R_ACK && response2 == KEYB_R_ACK) ledstate = new_ledstate; else printf( "Keyboard LED command not ACKed (responses %#x %#x)\n", response1, response2);#else /* _I386_ISA_KBDIO_H_ */ if (kbdc == NULL) { ledstate = new_ledstate; splx(opri); } else { ledstate = LEDSTATE_UPDATE_PENDING; splx(opri); if (set_keyboard_param(KBDC_SET_LEDS, new_ledstate) == 0) ledstate = new_ledstate; }#endif /* !_I386_ISA_KBDIO_H_ */#if PCVT_UPDLED_LOSES_INTR if (lost_intr_timeout_queued) untimeout(check_for_lost_intr, NULL); timeout(check_for_lost_intr, NULL, hz); lost_intr_timeout_queued = 1;#endif /* PCVT_UPDLED_LOSES_INTR */ }#ifndef _I386_ISA_KBDIO_H_ splx(opri);#endif #endif /* !PCVT_NO_LED_UPDATE */}/*---------------------------------------------------------------------------* * set typematic rate *---------------------------------------------------------------------------*/static voidsettpmrate(int rate){#ifndef _I386_ISA_KBDIO_H_ tpmrate = rate & 0x7f; if(kbd_cmd(KEYB_C_TYPEM) != 0) printf("Keyboard TYPEMATIC command timeout\n"); else if(kbd_cmd(tpmrate) != 0) printf("Keyboard TYPEMATIC data timeout\n");#else tpmrate = rate & 0x7f; if (set_keyboard_param(KBDC_SET_TYPEMATIC, tpmrate) != 0) printf("pcvt: failed to set keyboard TYPEMATIC.\n");#endif /* !_I386_ISA_KBDIO_H_ */}#ifndef _I386_ISA_KBDIO_H_/*---------------------------------------------------------------------------* * Pass command to keyboard controller (8042) *---------------------------------------------------------------------------*/static intkbc_8042cmd(int val){ unsigned timeo; timeo = 100000; /* > 100 msec */ while (inb(CONTROLLER_CTRL) & STATUS_INPBF) if (--timeo == 0) return (-1); outb(CONTROLLER_CTRL, val); return (0);}/*---------------------------------------------------------------------------* * Pass command to keyboard itself *---------------------------------------------------------------------------*/intkbd_cmd(int val){ unsigned timeo; timeo = 100000; /* > 100 msec */ while (inb(CONTROLLER_CTRL) & STATUS_INPBF) if (--timeo == 0) return (-1); outb(CONTROLLER_DATA, val);#if PCVT_SHOWKEYS showkey ('>', val);#endif /* PCVT_SHOWKEYS */ return (0);}/*---------------------------------------------------------------------------* * Read response from keyboard * NB: make sure to call spltty() before kbd_cmd(), kbd_response(). *---------------------------------------------------------------------------*/intkbd_response(void){ u_char ch; unsigned timeo; timeo = 500000; /* > 500 msec (KEYB_R_SELFOK requires 87) */ while (!(inb(CONTROLLER_CTRL) & STATUS_OUTPBF)) if (--timeo == 0) return (-1); PCVT_KBD_DELAY(); /* 7 us delay */ ch = inb(CONTROLLER_DATA);#if PCVT_SHOWKEYS showkey ('<', ch);#endif /* PCVT_SHOWKEYS */ return ch;}#elsestatic intset_keyboard_param(int command, int data){ int s; int c; if (kbdc == NULL) return 1; /* prevent the timeout routine from polling the keyboard */ if (!kbdc_lock(kbdc, TRUE)) return 1; /* disable the keyboard and mouse interrupt */ s = spltty();#if 0 c = get_controller_command_byte(kbdc); if ((c == -1) || !set_controller_command_byte(kbdc, kbdc_get_device_mask(kbdc), KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT | KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { /* CONTROLLER ERROR */ kbdc_lock(kbdc, FALSE); splx(s); return 1; } /* * Now that the keyboard controller is told not to generate * the keyboard and mouse interrupts, call `splx()' to allow * the other tty interrupts. The clock interrupt may also occur, * but the timeout routine (`scrn_timer()') will be blocked * by the lock flag set via `kbdc_lock()' */ splx(s);#endif if (send_kbd_command_and_data(kbdc, command, data) != KBD_ACK) send_kbd_command(kbdc, KBDC_ENABLE_KBD);#if 0 /* restore the interrupts */ if (!set_controller_command_byte(kbdc, kbdc_get_device_mask(kbdc), c & (KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS))) { /* CONTROLLER ERROR */ }#else splx(s);#endif kbdc_lock(kbdc, FALSE); return 0;}#endif /* !_I386_ISA_KBDIO_H_ */#if PCVT_SCANSET > 1/*---------------------------------------------------------------------------* * switch PC scan code emulation mode *---------------------------------------------------------------------------*/voidkbd_emulate_pc(int do_emulation){#ifndef _I386_ISA_KBDIO_H_ int cmd, timeo = 10000; cmd = COMMAND_SYSFLG|COMMAND_IRQEN; /* common base cmd */#if !PCVT_USEKBDSEC cmd |= COMMAND_INHOVR;#endif if(do_emulation) cmd |= COMMAND_PCSCAN; kbc_8042cmd(CONTR_WRITE); while (inb(CONTROLLER_CTRL) & STATUS_INPBF) if (--timeo == 0) break; outb(CONTROLLER_DATA, cmd);#else set_controller_command_byte(kbdc, KBD_TRANSLATION, (do_emulation) ? KBD_TRANSLATION : 0);#endif /* !_I386_ISA_KBDIO_H_ */}#endif /* PCVT_SCANSET > 1 */#ifndef PCVT_NONRESP_KEYB_TRY#define PCVT_NONRESP_KEYB_TRY 25 /* no of times to try to detect */#endif /* a nonresponding keyboard *//*---------------------------------------------------------------------------* * try to force keyboard into a known state .. *---------------------------------------------------------------------------*/staticvoid doreset(void){#ifndef _I386_ISA_KBDIO_H_ int again = 0; int once = 0; int response, opri; /* Enable interrupts and keyboard, etc. */ if (kbc_8042cmd(CONTR_WRITE) != 0) printf("pcvt: doreset() - timeout controller write command\n");#if PCVT_USEKBDSEC /* security enabled */# if PCVT_SCANSET == 2# define KBDINITCMD COMMAND_SYSFLG|COMMAND_IRQEN# else /* PCVT_SCANSET != 2 */# define KBDINITCMD COMMAND_PCSCAN|COMMAND_SYSFLG|COMMAND_IRQEN# endif /* PCVT_SCANSET == 2 */#else /* ! PCVT_USEKBDSEC */ /* security disabled */# if PCVT_SCANSET == 2# define KBDINITCMD COMMAND_INHOVR|COMMAND_SYSFLG|COMMAND_IRQEN# else /* PCVT_SCANSET != 2 */# define KBDINITCMD COMMAND_PCSCAN|COMMAND_INHOVR|COMMAND_SYSFLG\ |COMMAND_IRQEN# endif /* PCVT_SCANSET == 2 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -