diff options
Diffstat (limited to 'sys/i386/isa/pcvt/pcvt_kbd.c')
-rw-r--r-- | sys/i386/isa/pcvt/pcvt_kbd.c | 286 |
1 files changed, 212 insertions, 74 deletions
diff --git a/sys/i386/isa/pcvt/pcvt_kbd.c b/sys/i386/isa/pcvt/pcvt_kbd.c index 50457dc16b5d7..579c1a23abb5b 100644 --- a/sys/i386/isa/pcvt/pcvt_kbd.c +++ b/sys/i386/isa/pcvt/pcvt_kbd.c @@ -91,9 +91,11 @@ static void doreset ( void ); static void ovlinit ( int force ); static void settpmrate ( int rate ); static void setlockkeys ( int snc ); -#ifndef _DEV_KBD_KBDREG_H_ +#ifndef _I386_ISA_KBDIO_H_ static int kbc_8042cmd ( int val ); -#endif /* !_DEV_KBD_KBDREG_H_ */ +#else +static 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 ); @@ -168,7 +170,7 @@ do_vgapage(int page) #define PCVT_UPDLED_LOSES_INTR 0 /* disabled for now */ -#if PCVT_UPDLED_LOSES_INTR || defined(_DEV_KBD_KBDREG_H_) +#if PCVT_UPDLED_LOSES_INTR || defined(_I386_ISA_KBDIO_H_) /*---------------------------------------------------------------------------* * check for lost keyboard interrupts @@ -201,7 +203,7 @@ static struct callout_handle lost_intr_ch = static void check_for_lost_intr (void *arg) { -#ifndef _DEV_KBD_KBDREG_H_ +#ifndef _I386_ISA_KBDIO_H_ lost_intr_timeout_queued = 0; if (inb(CONTROLLER_CTRL) & STATUS_OUTPBF) { @@ -213,20 +215,19 @@ check_for_lost_intr (void *arg) int opri; lost_intr_timeout_queued = 0; - if ((*kbdsw[kbd->kb_index]->lock)(kbd, TRUE)) { + if (kbdc_lock(kbdc, TRUE)) { opri = spltty (); - (*kbdsw[kbd->kb_index]->lock)(kbd, FALSE); - if ((*kbdsw[kbd->kb_index]->check)(kbd)) + kbdc_lock(kbdc, FALSE); + if (kbdc_data_ready(kbdc)) pcrint (0); splx (opri); } - lost_intr_ch = timeout(check_for_lost_intr, (void *)NULL, hz); lost_intr_timeout_queued = 1; -#endif /* !_DEV_KBD_KBDREG_H_ */ +#endif /* !_I386_ISA_KBDIO_H_ */ } -#endif /* PCVT_UPDLED_LOSES_INTR || defined(_DEV_KBD_KBDREG_H_) */ +#endif /* PCVT_UPDLED_LOSES_INTR || defined(_I386_ISA_KBDIO_H_) */ /*---------------------------------------------------------------------------* * update keyboard led's @@ -238,23 +239,16 @@ update_led(void) /* Don't update LED's unless necessary. */ - int opri, new_ledstate; + int opri, new_ledstate, response1, response2; opri = spltty(); -#ifndef _DEV_KBD_KBDREG_H_ new_ledstate = (vsp->scroll_lock) | (vsp->num_lock * 2) | (vsp->caps_lock * 4); -#else - new_ledstate = ((vsp->scroll_lock) ? LED_SCR : 0) | - ((vsp->num_lock) ? LED_NUM : 0) | - ((vsp->caps_lock) ? LED_CAP : 0); -#endif /* _DEV_KBD_KBDREG_H_ */ if (new_ledstate != ledstate) { -#ifndef _DEV_KBD_KBDREG_H_ - int response1, response2; +#ifndef _I386_ISA_KBDIO_H_ ledstate = LEDSTATE_UPDATE_PENDING; @@ -301,20 +295,19 @@ update_led(void) printf( "Keyboard LED command not ACKed (responses %#x %#x)\n", response1, response2); -#else /* _DEV_KBD_KBDREG_H_ */ +#else /* _I386_ISA_KBDIO_H_ */ - if (kbd == NULL) { + if (kbdc == NULL) { ledstate = new_ledstate; splx(opri); } else { ledstate = LEDSTATE_UPDATE_PENDING; splx(opri); - if ((*kbdsw[kbd->kb_index]->ioctl)(kbd, KDSETLED, - (caddr_t)&new_ledstate) == 0) + if (set_keyboard_param(KBDC_SET_LEDS, new_ledstate) == 0) ledstate = new_ledstate; } -#endif /* !_DEV_KBD_KBDREG_H_ */ +#endif /* !_I386_ISA_KBDIO_H_ */ #if PCVT_UPDLED_LOSES_INTR if (lost_intr_timeout_queued) @@ -326,7 +319,7 @@ update_led(void) } -#ifndef _DEV_KBD_KBDREG_H_ +#ifndef _I386_ISA_KBDIO_H_ splx(opri); #endif @@ -339,22 +332,20 @@ update_led(void) static void settpmrate(int rate) { -#ifndef _DEV_KBD_KBDREG_H_ +#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 - if (kbd == NULL) - return; tpmrate = rate & 0x7f; - if ((*kbdsw[kbd->kb_index]->ioctl)(kbd, KDSETRAD, (caddr_t)&tpmrate)) + if (set_keyboard_param(KBDC_SET_TYPEMATIC, tpmrate) != 0) printf("pcvt: failed to set keyboard TYPEMATIC.\n"); -#endif /* !_DEV_KBD_KBDREG_H_ */ +#endif /* !_I386_ISA_KBDIO_H_ */ } -#ifndef _DEV_KBD_KBDREG_H_ +#ifndef _I386_ISA_KBDIO_H_ /*---------------------------------------------------------------------------* * Pass command to keyboard controller (8042) *---------------------------------------------------------------------------*/ @@ -416,7 +407,62 @@ kbd_response(void) return ch; } -#endif /* _DEV_KBD_KBDREG_H_ */ +#else +static int +set_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 /*---------------------------------------------------------------------------* @@ -425,7 +471,7 @@ kbd_response(void) void kbd_emulate_pc(int do_emulation) { -#ifndef _DEV_KBD_KBDREG_H_ +#ifndef _I386_ISA_KBDIO_H_ int cmd, timeo = 10000; cmd = COMMAND_SYSFLG|COMMAND_IRQEN; /* common base cmd */ @@ -443,9 +489,9 @@ kbd_emulate_pc(int do_emulation) break; outb(CONTROLLER_DATA, cmd); #else - set_controller_command_byte(*(KBDC *)kbd->kb_data, KBD_TRANSLATION, + set_controller_command_byte(kbdc, KBD_TRANSLATION, (do_emulation) ? KBD_TRANSLATION : 0); -#endif /* !_DEV_KBD_KBDREG_H_ */ +#endif /* !_I386_ISA_KBDIO_H_ */ } #endif /* PCVT_SCANSET > 1 */ @@ -461,7 +507,7 @@ kbd_emulate_pc(int do_emulation) static void doreset(void) { -#ifndef _DEV_KBD_KBDREG_H_ +#ifndef _I386_ISA_KBDIO_H_ int again = 0; int once = 0; int response, opri; @@ -622,8 +668,10 @@ r_entry: #endif /* PCVT_KEYBDID */ -#else /* _DEV_KBD_KBDREG_H_ */ - int type; +#else /* _I386_ISA_KBDIO_H_ */ + int c; + int m; + int s; if (!reset_keyboard) /* no, we are not ready to reset */ return; @@ -633,11 +681,29 @@ r_entry: lost_intr_timeout_queued = 0; } - if (kbd == NULL) - return; /* shouldn't happen */ - (*kbdsw[kbd->kb_index]->init)(kbd); + if (kbdc == NULL) + kbdc = kbdc_open(IO_KBD); - ledstate = LEDSTATE_UPDATE_PENDING; + if (!kbdc_lock(kbdc, TRUE)) /* strange, somebody got there first */ + return; + + /* remove any noise */ + empty_both_buffers(kbdc, 10); + + s = spltty(); + + /* save the current controller command byte */ + m = kbdc_get_device_mask(kbdc) & ~KBD_KBD_CONTROL_BITS; + c = get_controller_command_byte(kbdc); + if (c == -1) { + /* CONTROLLER ERROR */ + kbdc_set_device_mask(kbdc, m); + kbdc_lock(kbdc, FALSE); + kbdc = NULL; + splx(s); + printf("pcvt: unable to get the command byte.\n"); + return; + } #if PCVT_USEKBDSEC /* security enabled */ @@ -657,33 +723,105 @@ r_entry: #endif /* PCVT_USEKBDSEC */ - set_controller_command_byte(*(KBDC *)kbd->kb_data, - KBD_OVERRIDE_KBD_LOCK | KBD_TRANSLATION, KBDINITCMD); - - keyboard_type = KB_MFII; /* force it .. */ + /* disable the keyboard interrupt and the aux port and interrupt */ + if (!set_controller_command_byte(kbdc, + KBD_KBD_CONTROL_BITS | KBD_TRANSLATION | KBD_OVERRIDE_KBD_LOCK, + KBD_ENABLE_KBD_PORT | KBD_DISABLE_KBD_INT | KBDINITCMD)) { + /* CONTROLLER ERROR: there is very little we can do... */ + kbdc_set_device_mask(kbdc, m); + kbdc_lock(kbdc, FALSE); + kbdc = NULL; + splx(s); + printf("pcvt: unable to set the command byte.\n"); + return; + } + splx(s); + + /* reset keyboard hardware */ + ledstate = LEDSTATE_UPDATE_PENDING; + if (!reset_kbd(kbdc)) { + /* KEYBOARD ERROR */ + empty_both_buffers(kbdc, 10); + test_controller(kbdc); + test_kbd_port(kbdc); + /* + * We could disable the keyboard port and interrupt now... + * but, the keyboard may still exist. + */ + printf("pcvt: failed to reset the keyboard.\n"); + /* try to restore the original command byte */ + set_controller_command_byte(kbdc, 0xff, c); + kbdc_set_device_mask(kbdc, m); + kbdc_lock(kbdc, FALSE); + kbdc = NULL; + return; + } + #if PCVT_KEYBDID - type = KB_101; - (*kbdsw[kbd->kb_index]->ioctl)(kbd, KDGKBTYPE, (caddr_t)&type); - switch (type) - { - case KB_84: - keyboard_type = KB_AT; - break; - case KB_101: - keyboard_type = KB_MFII; - break; - default: - keyboard_type = KB_UNKNOWN; - break; + + keyboard_type = KB_UNKNOWN; + if (send_kbd_command(kbdc, KBDC_SEND_DEV_ID) == KBD_ACK) { + DELAY(10000); /* 10msec delay */ + switch (read_kbd_data(kbdc)) { + case KEYB_R_MF2ID1: + switch (read_kbd_data(kbdc)) { + case KEYB_R_MF2ID2: + case KEYB_R_MF2ID2HP: + keyboard_type = KB_MFII; + break; + case -1: + default: + break; + } + break; + case -1: + keyboard_type = KB_AT; + /* fall through */ + default: + /* XXX: should we read the second byte? */ + empty_both_buffers(kbdc, 10); /* XXX */ + break; + } + } else { + /* + * The send ID command failed. This error is considered + * benign, but may need recovery. + */ + empty_both_buffers(kbdc, 10); + test_controller(kbdc); + test_kbd_port(kbdc); } + +#else /* PCVT_KEYBDID */ + + keyboard_type = KB_MFII; /* force it .. */ + #endif /* PCVT_KEYBDID */ + /* enable the keyboard port and intr. */ + if (!set_controller_command_byte(kbdc, + KBD_KBD_CONTROL_BITS, + KBD_ENABLE_KBD_PORT | KBD_ENABLE_KBD_INT)) { + /* CONTROLLER ERROR + * This is serious; we are left with the disabled + * keyboard intr. + */ + printf("pcvt: failed to enable the keyboard port and intr.\n"); + kbdc_set_device_mask(kbdc, m); + kbdc_lock(kbdc, FALSE); + kbdc = NULL; + return; + } + + kbdc_set_device_mask(kbdc, m | KBD_KBD_CONTROL_BITS); + kbdc_lock(kbdc, FALSE); + update_led(); lost_intr_ch = timeout(check_for_lost_intr, (void *)NULL, hz); lost_intr_timeout_queued = 1; -#endif /* !_DEV_KBD_KBDREG_H_ */ +#endif /* !_I386_ISA_KBDIO_H_ */ } /*---------------------------------------------------------------------------* @@ -1105,15 +1243,15 @@ sgetc(int noblock) static char keybuf[2] = {0}; /* the second 0 is a delimiter! */ #endif /* XSERVER */ -#ifdef _DEV_KBD_KBDREG_H_ +#ifdef _I386_ISA_KBDIO_H_ int c; -#endif /* _DEV_KBD_KBDREG_H_ */ +#endif /* _I386_ISA_KBDIO_H_ */ loop: #ifdef XSERVER -#ifndef _DEV_KBD_KBDREG_H_ +#ifndef _I386_ISA_KBDIO_H_ #if PCVT_KBD_FIFO @@ -1148,7 +1286,7 @@ loop: #endif /* !PCVT_KBD_FIFO */ -#else /* _DEV_KBD_KBDREG_H_ */ +#else /* _I386_ISA_KBDIO_H_ */ #if PCVT_KBD_FIFO if (pcvt_kbd_count) { @@ -1161,18 +1299,18 @@ loop: } else #endif /* PCVT_KBD_FIFO */ if (!noblock) { - while ((c = (*kbdsw[kbd->kb_index]->read)(kbd, TRUE)) == -1) + while ((c = read_kbd_data(kbdc)) == -1) ; dt = c; } else { - if ((c = (*kbdsw[kbd->kb_index]->read)(kbd, FALSE)) == -1) + if ((c = read_kbd_data_no_wait(kbdc)) == -1) return NULL; dt = c; } { -#endif /* !_DEV_KBD_KBDREG_H_ */ +#endif /* !_I386_ISA_KBDIO_H_ */ /* * If x mode is active, only care for locking keys, then @@ -1450,7 +1588,7 @@ no_mouse_event: #else /* !XSERVER */ -#ifndef _DEV_KBD_KBDREG_H_ +#ifndef _I386_ISA_KBDIO_H_ # if PCVT_KBD_FIFO @@ -1487,7 +1625,7 @@ no_mouse_event: #endif /* !PCVT_KBD_FIFO */ -#else /* _DEV_KBD_KBDREG_H_ */ +#else /* _I386_ISA_KBDIO_H_ */ #if PCVT_KBD_FIFO if (pcvt_kbd_count) { @@ -1500,20 +1638,20 @@ no_mouse_event: } else #endif /* PCVT_KBD_FIFO */ if (!noblock) { - while ((c = (*kbdsw[kbd->kb_index]->read)(kbd, TRUE)) == -1) + while ((c = read_kbd_data(kbdc)) == -1) ; dt = c; } else { - if ((c = (*kbdsw[kbd->kb_index]->read)(kbd, FALSE)) == -1) + if ((c = read_kbd_data_no_wait(kbdc)) == -1) return NULL; dt = c; } -#endif /* !_DEV_KBD_KBDREG_H_ */ +#endif /* !_I386_ISA_KBDIO_H_ */ #endif /* !XSERVER */ -#ifndef _DEV_KBD_KBDREG_H_ +#ifndef _I386_ISA_KBDIO_H_ else { if(noblock) @@ -1521,7 +1659,7 @@ no_mouse_event: else goto loop; } -#endif /* !_DEV_KBD_KBDREG_H_ */ +#endif /* !_I386_ISA_KBDIO_H_ */ #if PCVT_SHOWKEYS showkey (' ', dt); |