diff --git a/lkm/syscons/fade/fade_saver.c b/lkm/syscons/fade/fade_saver.c index 524022d8d136..64291d9eee88 100644 --- a/lkm/syscons/fade/fade_saver.c +++ b/lkm/syscons/fade/fade_saver.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1995 Søren Schmidt + * Copyright (c) 1995-1997 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -68,7 +68,7 @@ fade_saver(int blank) } } else { - load_palette(); + load_palette(palette); count = scrn_blanked = 0; } } diff --git a/lkm/syscons/saver.h b/lkm/syscons/saver.h index e190d99981b5..b43c5627551d 100644 --- a/lkm/syscons/saver.h +++ b/lkm/syscons/saver.h @@ -1,4 +1,32 @@ -/* $FreeBSD$ */ +/*- + * Copyright (c) 1995-1997 Søren Schmidt + * All rights reserved. + * + * 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 + * in this position and unchanged. + * 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. The name of the author may not be used to endorse or promote products + * derived from this software withough specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * $FreeBSD$ + */ #include #include @@ -14,6 +42,10 @@ extern scr_stat *cur_console; extern u_short *Crtat; extern u_int crtc_addr; +extern char crtc_vga; extern char scr_map[]; extern int scrn_blanked; -extern char palette[]; +extern int fonts_loaded; +extern char *font_8, *font_14, *font_16; +extern char *palette; +extern char *video_mode_ptr; diff --git a/sys/conf/files.i386 b/sys/conf/files.i386 index 326f84d4a1da..5bf7985177a5 100644 --- a/sys/conf/files.i386 +++ b/sys/conf/files.i386 @@ -117,6 +117,7 @@ i386/isa/istallion.c optional stli device-driver i386/isa/joy.c optional joy device-driver i386/isa/kbdio.c optional psm device-driver i386/isa/kbdio.c optional sc device-driver +i386/isa/kbdio.c optional vt device-driver i386/isa/lpt.c optional lpt device-driver i386/isa/labpc.c optional labpc device-driver i386/isa/mcd.c optional mcd device-driver diff --git a/sys/conf/options.i386 b/sys/conf/options.i386 index 0b6aaab12a6d..6421e58a525d 100644 --- a/sys/conf/options.i386 +++ b/sys/conf/options.i386 @@ -46,6 +46,15 @@ SC_SPLASH_SCREEN opt_syscons.h MAXCONS opt_syscons.h SLOW_VGA opt_syscons.h +PSM_ACCEL opt_psm.h +PSM_EMULATION opt_psm.h +PSM_CHECKSYNC opt_psm.h +PSM_DEBUG opt_psm.h + +KBD_RESETDELAY opt_kbdio.h +KBD_MAXWAIT opt_kbdio.h +KBDIO_DEBUG opt_kbdio.h + ATAPI opt_atapi.h ATAPI_STATIC opt_atapi.h diff --git a/sys/dev/syscons/fade/fade_saver.c b/sys/dev/syscons/fade/fade_saver.c index 524022d8d136..64291d9eee88 100644 --- a/sys/dev/syscons/fade/fade_saver.c +++ b/sys/dev/syscons/fade/fade_saver.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1995 Søren Schmidt + * Copyright (c) 1995-1997 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -68,7 +68,7 @@ fade_saver(int blank) } } else { - load_palette(); + load_palette(palette); count = scrn_blanked = 0; } } diff --git a/sys/dev/syscons/syscons.c b/sys/dev/syscons/syscons.c index 853efd6f16e2..68b5f0132727 100644 --- a/sys/dev/syscons/syscons.c +++ b/sys/dev/syscons/syscons.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1992-1996 Søren Schmidt + * Copyright (c) 1992-1997 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -103,6 +103,7 @@ static term_stat kernel_console; static default_attr *current_default; static int flags = 0; static int sc_port = IO_KBD; +static KBDC sc_kbdc = NULL; static char init_done = COLD; static u_short sc_buffer[ROW*COL]; static char switch_in_progress = FALSE; @@ -113,9 +114,6 @@ static int blinkrate = 0; char crtc_vga = FALSE; static u_char shfts = 0, ctls = 0, alts = 0, agrs = 0, metas = 0; static u_char nlkcnt = 0, clkcnt = 0, slkcnt = 0, alkcnt = 0; - char *font_8 = NULL, *font_14 = NULL, *font_16 = NULL; - int fonts_loaded = 0; - char *palette; static const u_int n_fkey_tab = sizeof(fkey_tab) / sizeof(*fkey_tab); static int delayed_next_scr = FALSE; static long scrn_blank_time = 0; /* screen saver timeout value */ @@ -124,6 +122,11 @@ static long scrn_time_stamp; u_char scr_map[256]; u_char scr_rmap[256]; char *video_mode_ptr = NULL; + int fonts_loaded = 0; + char font_8[256*8]; + char font_14[256*14]; + char font_16[256*16]; + char palette[256*3]; static char *cut_buffer; static u_short mouse_and_mask[16] = { 0xc000, 0xe000, 0xf000, 0xf800, @@ -194,6 +197,7 @@ static void history_to_screen(scr_stat *scp); static int history_up_line(scr_stat *scp); static int history_down_line(scr_stat *scp); static int mask2attr(struct term_stat *term); +static void set_keyboard(int command, int data); static void update_leds(int which); static void set_vgaregs(char *modetable); static void set_font_mode(void); @@ -294,28 +298,34 @@ move_crsr(scr_stat *scp, int x, int y) static int scprobe(struct isa_device *dev) { - int c; + int codeset; + int c = -1; + int m; sc_port = dev->id_iobase; + sc_kbdc = kbdc_open(sc_port); + + if (!kbdc_lock(sc_kbdc, TRUE)) { + /* driver error? */ + printf("sc%d: unable to lock the controller.\n", dev->id_unit); + return ((dev->id_flags & DETECT_KBD) ? 0 : IO_KBDSIZE); + } /* discard anything left after UserConfig */ - empty_both_buffers(sc_port, 10); + empty_both_buffers(sc_kbdc, 10); /* save the current keyboard controller command byte */ - c = -1; - if (!write_controller_command(sc_port, KBDC_GET_COMMAND_BYTE)) { - /* CONTROLLER ERROR */ - printf("sc%d: unable to get the current command byte value.\n", - dev->id_unit); - goto fail; - } - c = read_controller_data(sc_port); + m = kbdc_get_device_mask(sc_kbdc) & ~KBD_KBD_CONTROL_BITS; + c = get_controller_command_byte(sc_kbdc); if (c == -1) { /* CONTROLLER ERROR */ printf("sc%d: unable to get the current command byte value.\n", dev->id_unit); goto fail; } + if (bootverbose) + printf("sc%d: the current keyboard controller command byte %04x\n", + dev->id_unit, c); #if 0 /* override the keyboard lock switch */ c |= KBD_OVERRIDE_KBD_LOCK; @@ -325,19 +335,40 @@ scprobe(struct isa_device *dev) * enable the keyboard port, but disable the keyboard intr. * the aux port (mouse port) is disabled too. */ - if (!set_controller_command_byte(sc_port, - c & ~(KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS), + if (!set_controller_command_byte(sc_kbdc, + KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS, KBD_ENABLE_KBD_PORT | KBD_DISABLE_KBD_INT - | KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { + | KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { /* CONTROLLER ERROR * there is very little we can do... */ printf("sc%d: unable to set the command byte.\n", dev->id_unit); goto fail; } + + /* + * Check if we have an XT keyboard before we attempt to reset it. + * The procedure assumes that the keyboard and the controller have + * been set up properly by BIOS and have not been messed up + * during the boot process. + */ + codeset = -1; + if (dev->id_flags & XT_KEYBD) + /* the user says there is a XT keyboard */ + codeset = 1; +#ifdef DETECT_XT_KEYBOARD + else if ((c & KBD_TRANSLATION) == 0) { + /* SET_SCANCODE_SET is not always supported; ignore error */ + if (send_kbd_command_and_data(sc_kbdc, KBDC_SET_SCANCODE_SET, 0) + == KBD_ACK) + codeset = read_kbd_data(sc_kbdc); + } + if (bootverbose) + printf("sc%d: keyboard scancode set %d\n", dev->id_unit, codeset); +#endif /* DETECT_XT_KEYBOARD */ /* reset keyboard hardware */ - if (!reset_kbd(sc_port)) { + if (!reset_kbd(sc_kbdc)) { /* KEYBOARD ERROR * Keyboard reset may fail either because the keyboard doen't exist, * or because the keyboard doesn't pass the self-test, or the keyboard @@ -347,14 +378,14 @@ scprobe(struct isa_device *dev) * test_controller() and test_kbd_port() appear to bring the keyboard * controller back (I don't know why and how, though.) */ - empty_both_buffers(sc_port, 10); - test_controller(sc_port); - test_kbd_port(sc_port); + empty_both_buffers(sc_kbdc, 10); + test_controller(sc_kbdc); + test_kbd_port(sc_kbdc); /* We could disable the keyboard port and interrupt... but, * the keyboard may still exist (see above). */ - if (bootverbose) - printf("sc%d: failed to reset the keyboard.\n", dev->id_unit); + if (bootverbose) + printf("sc%d: failed to reset the keyboard.\n", dev->id_unit); goto fail; } @@ -363,9 +394,9 @@ scprobe(struct isa_device *dev) * such as those on the IBM ThinkPad laptop computers can be used * with the standard console driver. */ - if (dev->id_flags & XT_KEYBD) { + if (codeset == 1) { if (send_kbd_command_and_data( - sc_port, KBDC_SET_SCAN_CODESET, 1) == KBD_ACK) { + sc_kbdc, KBDC_SET_SCANCODE_SET, codeset) == KBD_ACK) { /* XT kbd doesn't need scan code translation */ c &= ~KBD_TRANSLATION; } else { @@ -378,8 +409,10 @@ scprobe(struct isa_device *dev) } } /* enable the keyboard port and intr. */ - if (!set_controller_command_byte(sc_port, c & ~KBD_KBD_CONTROL_BITS, - KBD_ENABLE_KBD_PORT | KBD_ENABLE_KBD_INT)) { + if (!set_controller_command_byte(sc_kbdc, + KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS | KBD_OVERRIDE_KBD_LOCK, + (c & (KBD_AUX_CONTROL_BITS | KBD_OVERRIDE_KBD_LOCK)) + | KBD_ENABLE_KBD_PORT | KBD_ENABLE_KBD_INT)) { /* CONTROLLER ERROR * This is serious; we are left with the disabled keyboard intr. */ @@ -389,12 +422,17 @@ scprobe(struct isa_device *dev) } succeed: + kbdc_set_device_mask(sc_kbdc, m | KBD_KBD_CONTROL_BITS), + kbdc_lock(sc_kbdc, FALSE); return (IO_KBDSIZE); fail: if (c != -1) - /* try to restore the command byte as before, if possible */ - set_controller_command_byte(sc_port, c, 0); + /* try to restore the command byte as before, if possible */ + set_controller_command_byte(sc_kbdc, 0xff, c); + kbdc_set_device_mask(sc_kbdc, + (dev->id_flags & DETECT_KBD) ? m : m | KBD_KBD_CONTROL_BITS); + kbdc_lock(sc_kbdc, FALSE); return ((dev->id_flags & DETECT_KBD) ? 0 : IO_KBDSIZE); } @@ -423,14 +461,6 @@ scattach(struct isa_device *dev) if (crtc_vga) { cut_buffer = (char *)malloc(scp->xsize*scp->ysize, M_DEVBUF, M_NOWAIT); - font_8 = (char *)malloc(8*256, M_DEVBUF, M_NOWAIT); - font_14 = (char *)malloc(14*256, M_DEVBUF, M_NOWAIT); - font_16 = (char *)malloc(16*256, M_DEVBUF, M_NOWAIT); - copy_font(SAVE, FONT_16, font_16); - fonts_loaded = FONT_16; - scp->font_size = FONT_16; - palette = (char *)malloc(3*256, M_DEVBUF, M_NOWAIT); - save_palette(); } scp->scr_buf = (u_short *)malloc(scp->xsize*scp->ysize*sizeof(u_short), @@ -1106,7 +1136,7 @@ scioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) copy_font(LOAD, FONT_16, font_16); if (flags & CHAR_CURSOR) set_destructive_cursor(scp); - load_palette(); + load_palette(palette); } /* FALL THROUGH */ @@ -1155,9 +1185,8 @@ scioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) case KDSETRAD: /* set keyboard repeat & delay rates */ if (*data & 0x80) return EINVAL; - i = spltty(); - send_kbd_command_and_data(sc_port, KBDC_SET_TYPEMATIC, *data); - splx(i); + if (sc_kbdc != NULL) + set_keyboard(KBDC_SET_TYPEMATIC, *data); return 0; case KDSKBMODE: /* set keyboard mode */ @@ -1405,6 +1434,8 @@ sccnprobe(struct consdev *cp) /* initialize required fields */ cp->cn_dev = makedev(CDEV_MAJOR, SC_CONSOLE); cp->cn_pri = CN_INTERNAL; + + sc_kbdc = kbdc_open(sc_port); } void @@ -1499,8 +1530,21 @@ scrn_timer() * This ugly hack calls scintr if input is ready for the keyboard * and conveniently hides the problem. XXX */ - if ((inb(sc_port+KBD_STATUS_PORT)&KBDS_BUFFER_FULL) == KBDS_KBD_BUFFER_FULL) - scintr(0); + /* Try removing anything stuck in the keyboard controller; whether + * it's a keyboard scan code or mouse data. `scintr()' doesn't + * read the mouse data directly, but `kbdio' routines will, as a + * side effect. + */ + if (kbdc_lock(sc_kbdc, TRUE)) { + /* + * We have seen the lock flag is not set. Let's reset the flag early; + * otherwise `update_led()' failes which may want the lock + * during `scintr()'. + */ + kbdc_lock(sc_kbdc, FALSE); + if (kbdc_data_ready(sc_kbdc)) + scintr(0); + } /* should we just return ? */ if ((scp->status&UNKNOWN_MODE) || blink_in_progress || switch_in_progress) { @@ -1659,7 +1703,7 @@ exchange_scr(void) if ((old_scp->status & UNKNOWN_MODE) && crtc_vga) { if (flags & CHAR_CURSOR) set_destructive_cursor(new_scp); - load_palette(); + load_palette(palette); } if (old_scp->status & KBD_RAW_MODE || new_scp->status & KBD_RAW_MODE) shfts = ctls = alts = agrs = metas = 0; @@ -2354,9 +2398,8 @@ scinit(void) u_long segoff; crtc_vga = TRUE; - /* - * Get the BIOS video mode pointer. - */ + + /* Get the BIOS video mode pointer */ segoff = *(u_long *)pa_to_va(0x4a8); pa = (((segoff & 0xffff0000) >> 12) + (segoff & 0xffff)); if (ISMAPPED(pa, sizeof(u_long))) { @@ -2374,6 +2417,13 @@ scinit(void) bcopyw(Crtat, sc_buffer, console[0]->xsize * console[0]->ysize * sizeof(u_short)); + /* Save font and palette if VGA */ + if (crtc_vga) { + copy_font(SAVE, FONT_16, font_16); + fonts_loaded = FONT_16; + save_palette(); + } + console[0]->scr_buf = console[0]->mouse_pos = sc_buffer; console[0]->cursor_pos = console[0]->cursor_oldpos = sc_buffer + hw_cursor; console[0]->xpos = hw_cursor % COL; @@ -2387,6 +2437,7 @@ scinit(void) kernel_console.cur_color = kernel_console.std_color = kernel_default.std_color; kernel_console.rev_color = kernel_default.rev_color; + /* initialize mapscrn arrays to a one to one map */ for (i=0; imode = M_VGA_M80x25; else - scp->mode = M_VGA_C80x25; + scp->mode = M_VGA_C80x25; else if (crtc_addr == MONO_BASE) scp->mode = M_B80x25; @@ -2542,12 +2593,12 @@ scgetc(u_int flags) next_code: /* first see if there is something in the keyboard port */ if (flags & SCGETC_NONBLOCK) { - c = read_kbd_data_no_wait(sc_port); + c = read_kbd_data_no_wait(sc_kbdc); if (c == -1) return(NOKEY); } else { do { - c = read_kbd_data(sc_port); + c = read_kbd_data(sc_kbdc); } while(c == -1); } scancode = (u_char)c; @@ -3001,9 +3052,54 @@ mask2attr(struct term_stat *term) } static void -update_leds(int which) +set_keyboard(int command, int data) { int s; + int c; + + if (sc_kbdc == NULL) + return; + + /* prevent the timeout routine from polling the keyboard */ + if (!kbdc_lock(sc_kbdc, TRUE)) + return; + + /* disable the keyboard and mouse interrupt */ + s = spltty(); + c = get_controller_command_byte(sc_kbdc); + if ((c == -1) + || !set_controller_command_byte(sc_kbdc, + kbdc_get_device_mask(sc_kbdc), + KBD_ENABLE_KBD_PORT | KBD_DISABLE_KBD_INT + | KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { + /* CONTROLLER ERROR */ + kbdc_lock(sc_kbdc, FALSE); + splx(s); + return; + } + /* + * 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); + + send_kbd_command_and_data(sc_kbdc, command, data); + + /* restore the interrupts */ + if (!set_controller_command_byte(sc_kbdc, + kbdc_get_device_mask(sc_kbdc), + c & (KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS))) { + /* CONTROLLER ERROR */ + } + kbdc_lock(sc_kbdc, FALSE); +} + +static void +update_leds(int which) +{ static u_char xlate_leds[8] = { 0, 4, 2, 6, 1, 5, 3, 7 }; /* replace CAPS led with ALTGR led for ALTGR keyboards */ @@ -3014,10 +3110,7 @@ update_leds(int which) which &= ~CLKED; } - s = spltty(); - send_kbd_command_and_data(sc_port, KBDC_SET_LEDS, - xlate_leds[which & LED_MASK]); - splx(s); + set_keyboard(KBDC_SET_LEDS, xlate_leds[which & LED_MASK]); } void @@ -3595,7 +3688,7 @@ save_palette(void) } void -load_palette(void) +load_palette(char *palette) { int i; @@ -3658,6 +3751,7 @@ toggle_splash_screen(scr_stat *scp) scp->mode = save_mode; scp->status &= ~UNKNOWN_MODE; set_mode(scp); + load_palette(palette); toggle = 0; } else { diff --git a/sys/dev/syscons/syscons.h b/sys/dev/syscons/syscons.h index a9d5a04e6f01..9af7e26c5860 100644 --- a/sys/dev/syscons/syscons.h +++ b/sys/dev/syscons/syscons.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1995-1996 Søren Schmidt + * Copyright (c) 1995-1997 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -192,6 +192,6 @@ typedef struct default_attr { void set_border(u_char color); void set_mode(scr_stat *scp); void copy_font(int operation, int font_type, char* font_image); -void load_palette(void); +void load_palette(char *palette); #endif /* !_I386_ISA_SYSCONS_H_ */ diff --git a/sys/i386/conf/files.i386 b/sys/i386/conf/files.i386 index 326f84d4a1da..5bf7985177a5 100644 --- a/sys/i386/conf/files.i386 +++ b/sys/i386/conf/files.i386 @@ -117,6 +117,7 @@ i386/isa/istallion.c optional stli device-driver i386/isa/joy.c optional joy device-driver i386/isa/kbdio.c optional psm device-driver i386/isa/kbdio.c optional sc device-driver +i386/isa/kbdio.c optional vt device-driver i386/isa/lpt.c optional lpt device-driver i386/isa/labpc.c optional labpc device-driver i386/isa/mcd.c optional mcd device-driver diff --git a/sys/i386/conf/options.i386 b/sys/i386/conf/options.i386 index 0b6aaab12a6d..6421e58a525d 100644 --- a/sys/i386/conf/options.i386 +++ b/sys/i386/conf/options.i386 @@ -46,6 +46,15 @@ SC_SPLASH_SCREEN opt_syscons.h MAXCONS opt_syscons.h SLOW_VGA opt_syscons.h +PSM_ACCEL opt_psm.h +PSM_EMULATION opt_psm.h +PSM_CHECKSYNC opt_psm.h +PSM_DEBUG opt_psm.h + +KBD_RESETDELAY opt_kbdio.h +KBD_MAXWAIT opt_kbdio.h +KBDIO_DEBUG opt_kbdio.h + ATAPI opt_atapi.h ATAPI_STATIC opt_atapi.h diff --git a/sys/i386/isa/kbdio.c b/sys/i386/isa/kbdio.c index 47eefc45f282..7f8633e292aa 100644 --- a/sys/i386/isa/kbdio.c +++ b/sys/i386/isa/kbdio.c @@ -29,6 +29,10 @@ * $FreeBSD$ */ +#include "sc.h" +#include "psm.h" +#include "opt_kbdio.h" + #include #include #include @@ -41,31 +45,254 @@ #include #include +/* + * driver specific options: the following options may be set by + * `options' statements in the kernel configuration file. + */ + +/* retry count */ +#ifndef KBD_MAXRETRY +#define KBD_MAXRETRY 3 +#endif + +/* timing parameters */ +#ifndef KBD_RESETDELAY +#define KBD_RESETDELAY 200 /* wait 200msec after kbd/mouse reset */ +#endif +#ifndef KBD_MAXWAIT +#define KBD_MAXWAIT 5 /* wait 5 times at most after reset */ +#endif + +/* I/O recovery time */ +#ifdef PC98 +#define KBDC_DELAYTIME 37 +#define KBDD_DELAYTIME 37 +#else +#define KBDC_DELAYTIME 20 +#define KBDD_DELAYTIME 7 +#endif + +/* debug option */ #ifndef KBDIO_DEBUG #define KBDIO_DEBUG 0 #endif +/* end of driver specific options */ + +/* constants */ + +#define NKBDC max(NSC, NPSM) +#define KBDQ_BUFSIZE 32 + +/* macros */ + +#ifndef max +#define max(x,y) ((x) > (y) ? (x) : (y)) +#endif +#ifndef min +#define min(x,y) ((x) < (y) ? (x) : (y)) +#endif + +#define kbdcp(p) ((struct kbdc_softc *)(p)) +#define nextq(i) (((i) + 1) % KBDQ_BUFSIZE) +#define availq(q) ((q)->head != (q)->tail) +#if KBDIO_DEBUG >= 2 +#define emptyq(q) ((q)->tail = (q)->head = (q)->qcount = 0) +#else +#define emptyq(q) ((q)->tail = (q)->head = 0) +#endif + +/* local variables */ + +typedef struct _kqueue { + int head; + int tail; + unsigned char q[KBDQ_BUFSIZE]; +#if KBDIO_DEBUG >= 2 + int call_count; + int qcount; + int max_qcount; +#endif +} kqueue; + +struct kbdc_softc { + int port; /* base port address */ + int command_byte; /* current command byte value */ + int command_mask; /* command byte mask bits for kbd/aux devices */ + int lock; /* FIXME: XXX not quite a semaphore... */ + kqueue kbd; /* keyboard data queue */ + kqueue aux; /* auxiliary data queue */ +}; + +static struct kbdc_softc kbdc_softc[NKBDC] = { { 0 }, }; + static int verbose = KBDIO_DEBUG; +/* function prototypes */ + +static int addq(kqueue *q, int c); +static int removeq(kqueue *q); +static int wait_while_controller_busy(struct kbdc_softc *kbdc); +static int wait_for_data(struct kbdc_softc *kbdc); +static int wait_for_kbd_data(struct kbdc_softc *kbdc); +static int wait_for_kbd_ack(struct kbdc_softc *kbdc); +static int wait_for_aux_data(struct kbdc_softc *kbdc); +static int wait_for_aux_ack(struct kbdc_softc *kbdc); + +/* associate a port number with a KBDC */ + +KBDC +kbdc_open(int port) +{ + int s; + int i; + + s = spltty(); + for (i = 0; i < NKBDC; ++i) { + if (kbdc_softc[i].port == port) { + splx(s); + return (KBDC) &kbdc_softc[i]; + } + if (kbdc_softc[i].port <= 0) { + kbdc_softc[i].port = port; + kbdc_softc[i].command_byte = -1; + kbdc_softc[i].command_mask = 0; + kbdc_softc[i].lock = FALSE; + kbdc_softc[i].kbd.head = kbdc_softc[i].kbd.tail = 0; + kbdc_softc[i].aux.head = kbdc_softc[i].aux.tail = 0; +#if KBDIO_DEBUG >= 2 + kbdc_softc[i].kbd.call_count = 0; + kbdc_softc[i].kbd.qcount = kbdc_softc[i].kbd.max_qcount = 0; + kbdc_softc[i].aux.call_count = 0; + kbdc_softc[i].aux.qcount = kbdc_softc[i].aux.max_qcount = 0; +#endif + splx(s); + return (KBDC) &kbdc_softc[i]; + } + } + splx(s); + return NULL; +} + +/* + * I/O access arbitration in `kbdio' + * + * The `kbdio' module uses a simplistic convention to arbitrate + * I/O access to the controller/keyboard/mouse. The convention requires + * close cooperation of the calling device driver. + * + * The device driver which utilizes the `kbdio' module are assumed to + * have the following set of routines. + * a. An interrupt handler (the bottom half of the driver). + * b. Timeout routines which may briefly polls the keyboard controller. + * c. Routines outside interrupt context (the top half of the driver). + * They should follow the rules below: + * 1. The interrupt handler may assume that it always has full access + * to the controller/keyboard/mouse. + * 2. The other routines must issue `spltty()' if they wish to + * prevent the interrupt handler from accessing + * the controller/keyboard/mouse. + * 3. The timeout routines and the top half routines of the device driver + * arbitrate I/O access by observing the lock flag in `kbdio'. + * The flag is manipulated via `kbdc_lock()'; when one wants to + * perform I/O, call `kbdc_lock(kbdc, TRUE)' and proceed only if + * the call returns with TRUE. Otherwise the caller must back off. + * Call `kbdc_lock(kbdc, FALSE)' when necessary I/O operaion + * is finished. This mechanism does not prevent the interrupt + * handler from being invoked at any time and carrying out I/O. + * Therefore, `spltty()' must be strategically placed in the device + * driver code. Also note that the timeout routine may interrupt + * `kbdc_lock()' called by the top half of the driver, but this + * interruption is OK so long as the timeout routine observes the + * the rule 4 below. + * 4. The interrupt and timeout routines should not extend I/O operation + * across more than one interrupt or timeout; they must complete + * necessary I/O operation within one invokation of the routine. + * This measns that if the timeout routine acquires the lock flag, + * it must reset the flag to FALSE before it returns. + */ + +/* set/reset polling lock */ +int +kbdc_lock(KBDC p, int lock) +{ + int prevlock; + + prevlock = kbdcp(p)->lock; + kbdcp(p)->lock = lock; + + return (prevlock != lock); +} + +/* check if any data is waiting to be processed */ +int +kbdc_data_ready(KBDC p) +{ + return (availq(&kbdcp(p)->kbd) || availq(&kbdcp(p)->aux) + || (inb(kbdcp(p)->port + KBD_STATUS_PORT) & KBDS_ANY_BUFFER_FULL)); +} + +/* queuing functions */ + +static int +addq(kqueue *q, int c) +{ + if (nextq(q->tail) != q->head) { + q->q[q->tail] = c; + q->tail = nextq(q->tail); +#if KBDIO_DEBUG >= 2 + ++q->call_count; + ++q->qcount; + if (q->qcount > q->max_qcount) + q->max_qcount = q->qcount; +#endif + return TRUE; + } + return FALSE; +} + +static int +removeq(kqueue *q) +{ + int c; + + if (q->tail != q->head) { + c = q->q[q->head]; + q->head = nextq(q->head); +#if KBDIO_DEBUG >= 2 + --q->qcount; +#endif + return c; + } + return -1; +} + /* * device I/O routines */ - - -int -wait_while_controller_busy(int port) +static int +wait_while_controller_busy(struct kbdc_softc *kbdc) { #ifdef PC98 - DELAY(KBDC_DELAYTIME); - return TRUE; + DELAY(KBDC_DELAYTIME); + return TRUE; #else /* CPU will stay inside the loop for 100msec at most */ int retry = 5000; + int port = kbdc->port; + int f; - while (inb(port + KBD_STATUS_PORT) & KBDS_INPUT_BUFFER_FULL) { + while ((f = inb(port + KBD_STATUS_PORT)) & KBDS_INPUT_BUFFER_FULL) { + if ((f & KBDS_BUFFER_FULL) == KBDS_KBD_BUFFER_FULL) { + DELAY(KBDD_DELAYTIME); + addq(&kbdc->kbd, inb(port + KBD_DATA_PORT)); + } else if ((f & KBDS_BUFFER_FULL) == KBDS_AUX_BUFFER_FULL) { + DELAY(KBDD_DELAYTIME); + addq(&kbdc->aux, inb(port + KBD_DATA_PORT)); + } DELAY(KBDC_DELAYTIME); if (--retry < 0) - return FALSE; + return FALSE; } return TRUE; #endif @@ -75,134 +302,257 @@ wait_while_controller_busy(int port) * wait for any data; whether it's from the controller, * the keyboard, or the aux device. */ -int -wait_for_data(int port) +static int +wait_for_data(struct kbdc_softc *kbdc) { /* CPU will stay inside the loop for 200msec at most */ int retry = 10000; + int port = kbdc->port; + int f; - while ((inb(port + KBD_STATUS_PORT) & KBDS_ANY_BUFFER_FULL) == 0) { + while ((f = inb(port + KBD_STATUS_PORT) & KBDS_ANY_BUFFER_FULL) == 0) { DELAY(KBDC_DELAYTIME); if (--retry < 0) - return FALSE; + return 0; } DELAY(KBDD_DELAYTIME); - return TRUE; + return f; } /* wait for data from the keyboard */ -int -wait_for_kbd_data(int port) +static int +wait_for_kbd_data(struct kbdc_softc *kbdc) { /* CPU will stay inside the loop for 200msec at most */ int retry = 10000; + int port = kbdc->port; + int f; - while ((inb(port + KBD_STATUS_PORT) & KBDS_BUFFER_FULL) - != KBDS_KBD_BUFFER_FULL) { + while ((f = inb(port + KBD_STATUS_PORT) & KBDS_BUFFER_FULL) + != KBDS_KBD_BUFFER_FULL) { + if (f == KBDS_AUX_BUFFER_FULL) { + DELAY(KBDD_DELAYTIME); + addq(&kbdc->aux, inb(port + KBD_DATA_PORT)); + } DELAY(KBDC_DELAYTIME); if (--retry < 0) - return FALSE; + return 0; } DELAY(KBDD_DELAYTIME); - return TRUE; + return f; +} + +/* + * wait for an ACK(FAh), RESEND(FEh), or RESET_FAIL(FCh) from the keyboard. + * queue anything else. + */ +static int +wait_for_kbd_ack(struct kbdc_softc *kbdc) +{ + /* CPU will stay inside the loop for 200msec at most */ + int retry = 10000; + int port = kbdc->port; + int f; + int b; + + while (retry-- > 0) { + if ((f = inb(port + KBD_STATUS_PORT)) & KBDS_ANY_BUFFER_FULL) { + DELAY(KBDD_DELAYTIME); + b = inb(port + KBD_DATA_PORT); + if ((f & KBDS_BUFFER_FULL) == KBDS_KBD_BUFFER_FULL) { + if ((b == KBD_ACK) || (b == KBD_RESEND) + || (b == KBD_RESET_FAIL)) + return b; + addq(&kbdc->kbd, b); + } else if ((f & KBDS_BUFFER_FULL) == KBDS_AUX_BUFFER_FULL) { + addq(&kbdc->aux, b); + } + } + DELAY(KBDC_DELAYTIME); + } + return -1; } /* wait for data from the aux device */ -int -wait_for_aux_data(int port) +static int +wait_for_aux_data(struct kbdc_softc *kbdc) { /* CPU will stay inside the loop for 200msec at most */ int retry = 10000; + int port = kbdc->port; + int f; - while ((inb(port + KBD_STATUS_PORT) & KBDS_BUFFER_FULL) - != KBDS_AUX_BUFFER_FULL) { + while ((f = inb(port + KBD_STATUS_PORT) & KBDS_BUFFER_FULL) + != KBDS_AUX_BUFFER_FULL) { + if (f == KBDS_KBD_BUFFER_FULL) { + DELAY(KBDD_DELAYTIME); + addq(&kbdc->kbd, inb(port + KBD_DATA_PORT)); + } DELAY(KBDC_DELAYTIME); if (--retry < 0) - return FALSE; + return 0; } DELAY(KBDD_DELAYTIME); + return f; +} + +/* + * wait for an ACK(FAh), RESEND(FEh), or RESET_FAIL(FCh) from the aux device. + * queue anything else. + */ +static int +wait_for_aux_ack(struct kbdc_softc *kbdc) +{ + /* CPU will stay inside the loop for 200msec at most */ + int retry = 10000; + int port = kbdc->port; + int f; + int b; + + while (retry-- > 0) { + if ((f = inb(port + KBD_STATUS_PORT)) & KBDS_ANY_BUFFER_FULL) { + DELAY(KBDD_DELAYTIME); + b = inb(port + KBD_DATA_PORT); + if ((f & KBDS_BUFFER_FULL) == KBDS_AUX_BUFFER_FULL) { + if ((b == PSM_ACK) || (b == PSM_RESEND) + || (b == PSM_RESET_FAIL)) + return b; + addq(&kbdc->aux, b); + } else if ((f & KBDS_BUFFER_FULL) == KBDS_KBD_BUFFER_FULL) { + addq(&kbdc->kbd, b); + } + } + DELAY(KBDC_DELAYTIME); + } + return -1; +} + +/* write a one byte command to the controller */ +int +write_controller_command(KBDC p, int c) +{ + if (!wait_while_controller_busy(kbdcp(p))) + return FALSE; + outb(kbdcp(p)->port + KBD_COMMAND_PORT, c); return TRUE; } +/* write a one byte data to the controller */ int -write_controller_command(int port, int c) +write_controller_data(KBDC p, int c) { - if (!wait_while_controller_busy(port)) + if (!wait_while_controller_busy(kbdcp(p))) return FALSE; - outb(port + KBD_COMMAND_PORT, c); + outb(kbdcp(p)->port + KBD_DATA_PORT, c); return TRUE; } +/* write a one byte keyboard command */ int -write_controller_data(int port, int c) +write_kbd_command(KBDC p, int c) { - if (!wait_while_controller_busy(port)) + if (!wait_while_controller_busy(kbdcp(p))) return FALSE; - outb(port + KBD_DATA_PORT, c); + outb(kbdcp(p)->port + KBD_DATA_PORT, c); return TRUE; } +/* write a one byte auxiliary device command */ int -write_kbd_command(int port, int c) +write_aux_command(KBDC p, int c) { - if (!wait_while_controller_busy(port)) + if (!write_controller_command(p, KBDC_WRITE_TO_AUX)) return FALSE; - outb(port + KBD_DATA_PORT, c); - return TRUE; + return write_controller_data(p, c); } +/* send a command to the keyboard and wait for ACK */ int -write_aux_command(int port, int c) -{ - if (!write_controller_command(port,KBDC_WRITE_TO_AUX)) - return FALSE; - return write_controller_data(port, c); -} - -int -send_kbd_command(int port, int c) +send_kbd_command(KBDC p, int c) { int retry = KBD_MAXRETRY; int res = -1; while (retry-- > 0) { - if (!write_kbd_command(port, c)) + if (!write_kbd_command(p, c)) continue; - res = read_controller_data(port); + res = wait_for_kbd_ack(kbdcp(p)); if (res == KBD_ACK) - break; + break; } return res; } +/* send a command to the auxiliary device and wait for ACK */ int -send_aux_command(int port, int c) +send_aux_command(KBDC p, int c) { int retry = KBD_MAXRETRY; int res = -1; while (retry-- > 0) { - if (!write_aux_command(port, c)) + if (!write_aux_command(p, c)) continue; - res = read_aux_data(port); + /* + * FIXME: XXX + * The aux device may have already sent one or two bytes of + * status data, when a command is received. It will immediately + * stop data transmission, thus, leaving an incomplete data + * packet in our buffer. We have to discard any unprocessed + * data in order to remove such packets. Well, we may remove + * unprocessed, but necessary data byte as well... + */ + emptyq(&kbdcp(p)->aux); + res = wait_for_aux_ack(kbdcp(p)); if (res == PSM_ACK) - break; + break; } return res; } +/* send a command and a data to the keyboard, wait for ACKs */ int -send_kbd_command_and_data(int port, int c, int d) +send_kbd_command_and_data(KBDC p, int c, int d) { int retry; int res = -1; for (retry = KBD_MAXRETRY; retry > 0; --retry) { - if (!write_kbd_command(port, c)) + if (!write_kbd_command(p, c)) continue; - res = read_controller_data(port); + res = wait_for_kbd_ack(kbdcp(p)); if (res == KBD_ACK) - break; + break; + else if (res != KBD_RESEND) + return res; + } + if (retry <= 0) + return res; + + for (retry = KBD_MAXRETRY, res = -1; retry > 0; --retry) { + if (!write_kbd_command(p, d)) + continue; + res = wait_for_kbd_ack(kbdcp(p)); + if (res != KBD_RESEND) + break; + } + return res; +} + +/* send a command and a data to the auxiliary device, wait for ACKs */ +int +send_aux_command_and_data(KBDC p, int c, int d) +{ + int retry; + int res = -1; + + for (retry = KBD_MAXRETRY; retry > 0; --retry) { + if (!write_aux_command(p, c)) + continue; + emptyq(&kbdcp(p)->aux); + res = wait_for_aux_ack(kbdcp(p)); + if (res == PSM_ACK) + break; else if (res != PSM_RESEND) return res; } @@ -210,39 +560,11 @@ send_kbd_command_and_data(int port, int c, int d) return res; for (retry = KBD_MAXRETRY, res = -1; retry > 0; --retry) { - if (!write_kbd_command(port, d)) + if (!write_aux_command(p, d)) continue; - res = read_controller_data(port); - if (res != KBD_RESEND) - break; - } - return res; -} - -int -send_aux_command_and_data(int port, int c, int d) -{ - int retry; - int res = -1; - - for (retry = KBD_MAXRETRY; retry > 0; --retry) { - if (!write_aux_command(port, c)) - continue; - res = read_aux_data(port); - if (res == PSM_ACK) - break; - else if (res != PSM_RESEND) - return res; - } - if (retry <= 0) - return res; - - for (retry = KBD_MAXRETRY, res = -1; retry > 0; --retry) { - if (!write_aux_command(port, d)) - continue; - res = read_aux_data(port); + res = wait_for_aux_ack(kbdcp(p)); if (res != PSM_RESEND) - break; + break; } return res; } @@ -252,107 +574,225 @@ send_aux_command_and_data(int port, int c, int d) * the keyboard, or the aux device */ int -read_controller_data(int port) +read_controller_data(KBDC p) { - if (!wait_for_data(port)) + if (availq(&kbdcp(p)->kbd)) + return removeq(&kbdcp(p)->kbd); + if (availq(&kbdcp(p)->aux)) + return removeq(&kbdcp(p)->aux); + if (!wait_for_data(kbdcp(p))) return -1; /* timeout */ - return inb(port + KBD_DATA_PORT); + return inb(kbdcp(p)->port + KBD_DATA_PORT); } +#if KBDIO_DEBUG >= 2 +static int call = 0; +#endif + /* read one byte from the keyboard */ int -read_kbd_data(int port) +read_kbd_data(KBDC p) { - if (!wait_for_kbd_data(port)) +#if KBDIO_DEBUG >= 2 + if (++call > 2000) { + call = 0; + log(LOG_DEBUG, "KBDIO: kbd q: %d calls, max %d chars, " + "aux q: %d calls, max %d chars\n", + kbdcp(p)->kbd.call_count, kbdcp(p)->kbd.max_qcount, + kbdcp(p)->aux.call_count, kbdcp(p)->aux.max_qcount); + } +#endif + + if (availq(&kbdcp(p)->kbd)) + return removeq(&kbdcp(p)->kbd); + if (!wait_for_kbd_data(kbdcp(p))) return -1; /* timeout */ #ifdef PC98 - DELAY(KBDC_DELAYTIME); + DELAY(KBDC_DELAYTIME); #endif - return inb(port + KBD_DATA_PORT); + return inb(kbdcp(p)->port + KBD_DATA_PORT); } /* read one byte from the keyboard, but return immediately if * no data is waiting */ int -read_kbd_data_no_wait(int port) +read_kbd_data_no_wait(KBDC p) { - if ((inb(port + KBD_STATUS_PORT) & KBDS_BUFFER_FULL) - != KBDS_KBD_BUFFER_FULL) - return -1; /* no data */ - DELAY(KBDD_DELAYTIME); - return inb(port + KBD_DATA_PORT); + int f; + +#if KBDIO_DEBUG >= 2 + if (++call > 2000) { + call = 0; + log(LOG_DEBUG, "KBDIO: kbd q: %d calls, max %d chars, " + "aux q: %d calls, max %d chars\n", + kbdcp(p)->kbd.call_count, kbdcp(p)->kbd.max_qcount, + kbdcp(p)->aux.call_count, kbdcp(p)->aux.max_qcount); + } +#endif + + if (availq(&kbdcp(p)->kbd)) + return removeq(&kbdcp(p)->kbd); + f = inb(kbdcp(p)->port + KBD_STATUS_PORT) & KBDS_BUFFER_FULL; + if (f == KBDS_AUX_BUFFER_FULL) { + DELAY(KBDD_DELAYTIME); + addq(&kbdcp(p)->aux, inb(kbdcp(p)->port + KBD_DATA_PORT)); + f = inb(kbdcp(p)->port + KBD_STATUS_PORT) & KBDS_BUFFER_FULL; + } + if (f == KBDS_KBD_BUFFER_FULL) { + DELAY(KBDD_DELAYTIME); + return inb(kbdcp(p)->port + KBD_DATA_PORT); + } + return -1; /* no data */ } /* read one byte from the aux device */ int -read_aux_data(int port) +read_aux_data(KBDC p) { - if (!wait_for_aux_data(port)) + if (availq(&kbdcp(p)->aux)) + return removeq(&kbdcp(p)->aux); + if (!wait_for_aux_data(kbdcp(p))) return -1; /* timeout */ - return inb(port + KBD_DATA_PORT); + return inb(kbdcp(p)->port + KBD_DATA_PORT); +} + +/* read one byte from the aux device, but return immediately if + * no data is waiting + */ +int +read_aux_data_no_wait(KBDC p) +{ + int f; + + if (availq(&kbdcp(p)->aux)) + return removeq(&kbdcp(p)->aux); + f = inb(kbdcp(p)->port + KBD_STATUS_PORT) & KBDS_BUFFER_FULL; + if (f == KBDS_KBD_BUFFER_FULL) { + DELAY(KBDD_DELAYTIME); + addq(&kbdcp(p)->kbd, inb(kbdcp(p)->port + KBD_DATA_PORT)); + f = inb(kbdcp(p)->port + KBD_STATUS_PORT) & KBDS_BUFFER_FULL; + } + if (f == KBDS_AUX_BUFFER_FULL) { + DELAY(KBDD_DELAYTIME); + return inb(kbdcp(p)->port + KBD_DATA_PORT); + } + return -1; /* no data */ } /* discard data from the keyboard */ void -empty_kbd_buffer(int port, int t) +empty_kbd_buffer(KBDC p, int wait) { + int t; int b; - int c = 0; + int f; +#if KBDIO_DEBUG >= 2 + int c1 = 0; + int c2 = 0; +#endif int delta = 2; - for (; t > 0; t -= delta) { - if ((inb(port + KBD_STATUS_PORT) & KBDS_BUFFER_FULL) - == KBDS_KBD_BUFFER_FULL) { + for (t = wait; t > 0; ) { + if ((f = inb(kbdcp(p)->port + KBD_STATUS_PORT)) & KBDS_ANY_BUFFER_FULL) { DELAY(KBDD_DELAYTIME); - b = inb(port + KBD_DATA_PORT); - ++c; - } + b = inb(kbdcp(p)->port + KBD_DATA_PORT); + if ((f & KBDS_BUFFER_FULL) == KBDS_AUX_BUFFER_FULL) { + addq(&kbdcp(p)->aux, b); +#if KBDIO_DEBUG >= 2 + ++c2; + } else { + ++c1; +#endif + } + t = wait; + } else { + t -= delta; + } DELAY(delta*1000); } - if ((verbose >= 2) && (c > 0)) - log(LOG_DEBUG,"kbdio: %d char read (empty_kbd_buffer)\n",c); +#if KBDIO_DEBUG >= 2 + if ((c1 > 0) || (c2 > 0)) + log(LOG_DEBUG, "kbdio: %d:%d char read (empty_kbd_buffer)\n", c1, c2); +#endif + + emptyq(&kbdcp(p)->kbd); } /* discard data from the aux device */ void -empty_aux_buffer(int port, int t) +empty_aux_buffer(KBDC p, int wait) { + int t; int b; - int c = 0; + int f; +#if KBDIO_DEBUG >= 2 + int c1 = 0; + int c2 = 0; +#endif int delta = 2; - for (; t > 0; t -= delta) { - if ((inb(port + KBD_STATUS_PORT) & KBDS_BUFFER_FULL) - == KBDS_AUX_BUFFER_FULL) { + for (t = wait; t > 0; ) { + if ((f = inb(kbdcp(p)->port + KBD_STATUS_PORT)) & KBDS_ANY_BUFFER_FULL) { DELAY(KBDD_DELAYTIME); - b = inb(port + KBD_DATA_PORT); - ++c; - } + b = inb(kbdcp(p)->port + KBD_DATA_PORT); + if ((f & KBDS_BUFFER_FULL) == KBDS_KBD_BUFFER_FULL) { + addq(&kbdcp(p)->kbd, b); +#if KBDIO_DEBUG >= 2 + ++c1; + } else { + ++c2; +#endif + } + t = wait; + } else { + t -= delta; + } DELAY(delta*1000); } - if ((verbose >= 2) && (c > 0)) - log(LOG_DEBUG,"kbdio: %d char read (empty_aux_buffer)\n",c); +#if KBDIO_DEBUG >= 2 + if ((c1 > 0) || (c2 > 0)) + log(LOG_DEBUG, "kbdio: %d:%d char read (empty_aux_buffer)\n", c1, c2); +#endif + + emptyq(&kbdcp(p)->aux); } /* discard any data from the keyboard or the aux device */ void -empty_both_buffers(int port, int t) +empty_both_buffers(KBDC p, int wait) { - int b; - int c = 0; + int t; + int f; +#if KBDIO_DEBUG >= 2 + int c1 = 0; + int c2 = 0; +#endif int delta = 2; - for (; t > 0; t -= delta) { - if (inb(port + KBD_STATUS_PORT) & KBDS_ANY_BUFFER_FULL) { + for (t = wait; t > 0; ) { + if ((f = inb(kbdcp(p)->port + KBD_STATUS_PORT)) & KBDS_ANY_BUFFER_FULL) { DELAY(KBDD_DELAYTIME); - b = inb(port + KBD_DATA_PORT); - ++c; - } + (void)inb(kbdcp(p)->port + KBD_DATA_PORT); +#if KBDIO_DEBUG >= 2 + if ((f & KBDS_BUFFER_FULL) == KBDS_KBD_BUFFER_FULL) + ++c1; + else + ++c2; +#endif + t = wait; + } else { + t -= delta; + } DELAY(delta*1000); } - if ((verbose >= 2) && (c > 0)) - log(LOG_DEBUG,"kbdio: %d char read (empty_both_buffers)\n",c); +#if KBDIO_DEBUG >= 2 + if ((c1 > 0) || (c2 > 0)) + log(LOG_DEBUG, "kbdio: %d:%d char read (empty_both_buffers)\n", c1, c2); +#endif + + emptyq(&kbdcp(p)->kbd); + emptyq(&kbdcp(p)->aux); } /* keyboard and mouse device control */ @@ -361,21 +801,22 @@ empty_both_buffers(int port, int t) * interrupt before calling "reset_kbd()". */ int -reset_kbd(int port) +reset_kbd(KBDC p) { int retry = KBD_MAXRETRY; int again = KBD_MAXWAIT; int c = KBD_RESEND; /* keep the compiler happy */ while (retry-- > 0) { - empty_both_buffers(port, 10); - if (!write_kbd_command(port, KBDC_RESET_KBD)) + empty_both_buffers(p, 10); + if (!write_kbd_command(p, KBDC_RESET_KBD)) continue; - c = read_controller_data(port); - if (verbose) - log(LOG_DEBUG,"kbdio: RESET_KBD return code:%04x\n",c); + emptyq(&kbdcp(p)->kbd); + c = read_controller_data(p); + if (verbose || bootverbose) + log(LOG_DEBUG, "kbdio: RESET_KBD return code:%04x\n", c); if (c == KBD_ACK) /* keyboard has agreed to reset itself... */ - break; + break; } if (retry < 0) return FALSE; @@ -383,12 +824,12 @@ reset_kbd(int port) while (again-- > 0) { /* wait awhile, well, in fact we must wait quite loooooooooooong */ DELAY(KBD_RESETDELAY*1000); - c = read_controller_data(port); /* RESET_DONE/RESET_FAIL */ + c = read_controller_data(p); /* RESET_DONE/RESET_FAIL */ if (c != -1) /* wait again if the controller is not ready */ - break; + break; } - if (verbose) - log(LOG_DEBUG,"kbdio: RESET_KBD status:%04x\n",c); + if (verbose || bootverbose) + log(LOG_DEBUG, "kbdio: RESET_KBD status:%04x\n", c); if (c != KBD_RESET_DONE) return FALSE; return TRUE; @@ -398,21 +839,22 @@ reset_kbd(int port) * before calling `reset_aux_dev()'. */ int -reset_aux_dev(int port) +reset_aux_dev(KBDC p) { int retry = KBD_MAXRETRY; int again = KBD_MAXWAIT; int c = PSM_RESEND; /* keep the compiler happy */ while (retry-- > 0) { - empty_both_buffers(port, 10); - if (!write_aux_command(port, PSMC_RESET_DEV)) + empty_both_buffers(p, 10); + if (!write_aux_command(p, PSMC_RESET_DEV)) continue; - c = read_controller_data(port); - if (verbose) - log(LOG_DEBUG,"kbdio: RESET_AUX return code:%04x\n",c); + emptyq(&kbdcp(p)->aux); + c = read_aux_data(p); + if (verbose || bootverbose) + log(LOG_DEBUG, "kbdio: RESET_AUX return code:%04x\n", c); if (c == PSM_ACK) /* aux dev is about to reset... */ - break; + break; } if (retry < 0) return FALSE; @@ -420,112 +862,153 @@ reset_aux_dev(int port) while (again-- > 0) { /* wait awhile, well, quite looooooooooooong */ DELAY(KBD_RESETDELAY*1000); - c = read_aux_data(port); /* RESET_DONE/RESET_FAIL */ + c = read_aux_data(p); /* RESET_DONE/RESET_FAIL */ if (c != -1) /* wait again if the controller is not ready */ - break; + break; } - if (verbose) - log(LOG_DEBUG,"kbdio: RESET_AUX status:%04x\n",c); + if (verbose || bootverbose) + log(LOG_DEBUG, "kbdio: RESET_AUX status:%04x\n", c); if (c != PSM_RESET_DONE) /* reset status */ return FALSE; - c = read_aux_data(port); /* device ID */ - if (verbose) - log(LOG_DEBUG,"kbdio: RESET_AUX ID:%04x\n",c); - /* NOTE: we could check the device ID now, but leave it later... */ + c = read_aux_data(p); /* device ID */ + if (verbose || bootverbose) + log(LOG_DEBUG, "kbdio: RESET_AUX ID:%04x\n", c); + /* NOTE: we could check the device ID now, but leave it later... */ return TRUE; } /* controller diagnostics and setup */ int -test_controller(int port) +test_controller(KBDC p) { int retry = KBD_MAXRETRY; int again = KBD_MAXWAIT; int c = KBD_DIAG_FAIL; while (retry-- > 0) { - empty_both_buffers(port, 10); - if (write_controller_command(port, KBDC_DIAGNOSE)) + empty_both_buffers(p, 10); + if (write_controller_command(p, KBDC_DIAGNOSE)) break; } if (retry < 0) return FALSE; + emptyq(&kbdcp(p)->kbd); while (again-- > 0) { /* wait awhile */ DELAY(KBD_RESETDELAY*1000); - c = read_controller_data(port); /* DIAG_DONE/DIAG_FAIL */ + c = read_controller_data(p); /* DIAG_DONE/DIAG_FAIL */ if (c != -1) /* wait again if the controller is not ready */ break; } - if (verbose) - log(LOG_DEBUG,"kbdio: DIAGNOSE status:%04x\n",c); + if (verbose || bootverbose) + log(LOG_DEBUG, "kbdio: DIAGNOSE status:%04x\n", c); return (c == KBD_DIAG_DONE); } int -test_kbd_port(int port) +test_kbd_port(KBDC p) { int retry = KBD_MAXRETRY; int again = KBD_MAXWAIT; int c = -1; while (retry-- > 0) { - empty_both_buffers(port, 10); - if (write_controller_command(port, KBDC_TEST_KBD_PORT)) + empty_both_buffers(p, 10); + if (write_controller_command(p, KBDC_TEST_KBD_PORT)) break; } if (retry < 0) return FALSE; + emptyq(&kbdcp(p)->kbd); while (again-- > 0) { - c = read_controller_data(port); + c = read_controller_data(p); if (c != -1) /* try again if the controller is not ready */ break; } - if (verbose) - log(LOG_DEBUG,"kbdio: TEST_KBD_PORT status:%04x\n",c); + if (verbose || bootverbose) + log(LOG_DEBUG, "kbdio: TEST_KBD_PORT status:%04x\n", c); return c; } int -test_aux_port(int port) +test_aux_port(KBDC p) { int retry = KBD_MAXRETRY; int again = KBD_MAXWAIT; int c = -1; while (retry-- > 0) { - empty_both_buffers(port, 10); - if (write_controller_command(port, KBDC_TEST_AUX_PORT)) + empty_both_buffers(p, 10); + if (write_controller_command(p, KBDC_TEST_AUX_PORT)) break; } if (retry < 0) return FALSE; + emptyq(&kbdcp(p)->kbd); while (again-- > 0) { - c = read_controller_data(port); + c = read_controller_data(p); if (c != -1) /* try again if the controller is not ready */ break; } - if (verbose) - log(LOG_DEBUG,"kbdio: TEST_AUX_PORT status:%04x\n",c); + if (verbose || bootverbose) + log(LOG_DEBUG, "kbdio: TEST_AUX_PORT status:%04x\n", c); return c; } int -set_controller_command_byte(int port, int command, int flag) +kbdc_get_device_mask(KBDC p) { - if ((command | flag) & KBD_DISABLE_KBD_PORT) { - if (!write_controller_command(port, KBDC_DISABLE_KBD_PORT)) + return kbdcp(p)->command_mask; +} + +void +kbdc_set_device_mask(KBDC p, int mask) +{ + kbdcp(p)->command_mask = + mask & (KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS); +} + +int +get_controller_command_byte(KBDC p) +{ + if (kbdcp(p)->command_byte != -1) + return kbdcp(p)->command_byte; + if (!write_controller_command(p, KBDC_GET_COMMAND_BYTE)) + return -1; + emptyq(&kbdcp(p)->kbd); + kbdcp(p)->command_byte = read_controller_data(p); + return kbdcp(p)->command_byte; +} + +int +set_controller_command_byte(KBDC p, int mask, int command) +{ + if (get_controller_command_byte(p) == -1) + return FALSE; + + command = (kbdcp(p)->command_byte & ~mask) | (command & mask); +#if 0 + if (command == kbdcp(p)->command_byte) + return TRUE; +#endif + if (command & KBD_DISABLE_KBD_PORT) { + if (!write_controller_command(p, KBDC_DISABLE_KBD_PORT)) return FALSE; } - if (!write_controller_command(port, KBDC_SET_COMMAND_BYTE)) + if (!write_controller_command(p, KBDC_SET_COMMAND_BYTE)) return FALSE; - if (!write_controller_data(port, command | flag)) + if (!write_controller_data(p, command)) return FALSE; - wait_while_controller_busy(port); + kbdcp(p)->command_byte = command; + + if (verbose || bootverbose) + log(LOG_DEBUG, "kbdio: new command byte:%04x (set_controller...)\n", + command); + return TRUE; } diff --git a/sys/i386/isa/kbdio.h b/sys/i386/isa/kbdio.h index 546e21b13494..37034439573a 100644 --- a/sys/i386/isa/kbdio.h +++ b/sys/i386/isa/kbdio.h @@ -39,15 +39,18 @@ #define KBD_STATUS_PORT 2 /* status port, read */ #define KBD_COMMAND_PORT 2 /* controller command port, write */ #define KBD_DATA_PORT 0 /* data port, read/write - also used as keyboard command - and mouse command port */ + * also used as keyboard command + * and mouse command port + */ #else #define KBD_STATUS_PORT 4 /* status port, read */ #define KBD_COMMAND_PORT 4 /* controller command port, write */ #define KBD_DATA_PORT 0 /* data port, read/write - also used as keyboard command - and mouse command port */ + * also used as keyboard command + * and mouse command port + */ #endif /* PC98 */ + /* FIXME: `IO_PSMSIZE' should really be in `isa.h'. */ #define IO_PSMSIZE (KBD_COMMAND_PORT - KBD_DATA_PORT + 1) /* 5 */ @@ -86,13 +89,14 @@ #define KBDC_SEND_DEV_ID 0x00f2 #define KBDC_SET_LEDS 0x00ed #define KBDC_ECHO 0x00ee -#define KBDC_SET_SCAN_CODESET 0x00f0 +#define KBDC_SET_SCANCODE_SET 0x00f0 #define KBDC_SET_TYPEMATIC 0x00f3 /* aux device commands (sent to KBD_DATA_PORT) */ #define PSMC_RESET_DEV 0x00ff #define PSMC_ENABLE_DEV 0x00f4 #define PSMC_DISABLE_DEV 0x00f5 +#define PSMC_SET_DEFAULTS 0x00f6 #define PSMC_SEND_DEV_ID 0x00f2 #define PSMC_SEND_DEV_STATUS 0x00e9 #define PSMC_SEND_DEV_DATA 0x00eb @@ -104,15 +108,11 @@ #define PSMC_SET_SAMPLING_RATE 0x00f3 /* PSMC_SET_RESOLUTION argument */ -#define PSMD_RESOLUTION_25 0 /* 25ppi */ -#define PSMD_RESOLUTION_50 1 /* 50ppi */ -#define PSMD_RESOLUTION_100 2 /* 100ppi (default after reset) */ -#define PSMD_RESOLUTION_200 3 /* 200ppi */ -/* FIXME: I don't know if it's possible to go beyond 200ppi. - The values below are of my wild guess. */ -#define PSMD_RESOLUTION_400 4 /* 400ppi */ -#define PSMD_RESOLUTION_800 5 /* 800ppi */ -#define PSMD_MAX_RESOLUTION PSMD_RESOLUTION_800 +#define PSMD_RES_LOW 0 /* typically 25ppi */ +#define PSMD_RES_MEDIUM_LOW 1 /* typically 50ppi */ +#define PSMD_RES_MEDIUM_HIGH 2 /* typically 100ppi (default) */ +#define PSMD_RES_HIGH 3 /* typically 200ppi */ +#define PSMD_MAX_RESOLUTION PSMD_RES_HIGH /* PSMC_SET_SAMPLING_RATE */ #define PSMD_MAX_RATE 255 /* FIXME: not sure if it's possible */ @@ -151,79 +151,57 @@ #ifdef KERNEL -/* driver specific options: the following options may be set by - `options' statements in the kernel configuration file. */ - -/* retry count */ -#ifndef KBD_MAXRETRY -#define KBD_MAXRETRY 3 -#endif - -/* timing parameters */ -#ifndef KBD_RESETDELAY -#define KBD_RESETDELAY 200 /* wait 200msec after kbd/mouse reset */ -#endif -#ifndef KBD_MAXWAIT -#define KBD_MAXWAIT 5 /* wait 5 times at most after reset */ -#endif - -/* I/O recovery time */ -#ifdef PC98 -#define KBDC_DELAYTIME 37 -#define KBDD_DELAYTIME 37 -#else -#define KBDC_DELAYTIME 20 -#define KBDD_DELAYTIME 7 -#endif - -/* debugging */ -/* #define KBDIO_DEBUG produces debugging output */ - -/* end of driver specific options */ - -/* misc */ #ifndef TRUE -#define TRUE (-1) +#define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif +/* types/structures */ + +typedef caddr_t KBDC; + /* function prototypes */ -int wait_while_controller_busy __P((int port)); +KBDC kbdc_open __P((int port)); -int wait_for_data __P((int port)); -int wait_for_kbd_data __P((int port)); -int wait_for_aux_data __P((int port)); +int kbdc_lock __P((KBDC kbdc, int lock)); -int write_controller_command __P((int port,int c)); -int write_controller_data __P((int port,int c)); +int kbdc_data_ready __P((KBDC kbdc)); -int write_kbd_command __P((int port,int c)); -int write_aux_command __P((int port,int c)); -int send_kbd_command __P((int port,int c)); -int send_aux_command __P((int port,int c)); -int send_kbd_command_and_data __P((int port,int c,int d)); -int send_aux_command_and_data __P((int port,int c,int d)); +int write_controller_command __P((KBDC kbdc,int c)); +int write_controller_data __P((KBDC kbdc,int c)); -int read_controller_data __P((int port)); -int read_kbd_data __P((int port)); -int read_kbd_data_no_wait __P((int port)); -int read_aux_data __P((int port)); +int write_kbd_command __P((KBDC kbdc,int c)); +int write_aux_command __P((KBDC kbdc,int c)); +int send_kbd_command __P((KBDC kbdc,int c)); +int send_aux_command __P((KBDC kbdc,int c)); +int send_kbd_command_and_data __P((KBDC kbdc,int c,int d)); +int send_aux_command_and_data __P((KBDC kbdc,int c,int d)); -void empty_kbd_buffer __P((int port, int t)); -void empty_aux_buffer __P((int port, int t)); -void empty_both_buffers __P((int port, int t)); +int read_controller_data __P((KBDC kbdc)); +int read_kbd_data __P((KBDC kbdc)); +int read_kbd_data_no_wait __P((KBDC kbdc)); +int read_aux_data __P((KBDC kbdc)); +int read_aux_data_no_wait __P((KBDC kbdc)); -int reset_kbd __P((int port)); -int reset_aux_dev __P((int port)); +void empty_kbd_buffer __P((KBDC kbdc, int t)); +void empty_aux_buffer __P((KBDC kbdc, int t)); +void empty_both_buffers __P((KBDC kbdc, int t)); -int test_controller __P((int port)); -int test_kbd_port __P((int port)); -int test_aux_port __P((int port)); +int reset_kbd __P((KBDC kbdc)); +int reset_aux_dev __P((KBDC kbdc)); -int set_controller_command_byte __P((int port,int command,int flag)); +int test_controller __P((KBDC kbdc)); +int test_kbd_port __P((KBDC kbdc)); +int test_aux_port __P((KBDC kbdc)); + +int kbdc_get_device_mask __P((KBDC kbdc)); +void kbdc_set_device_mask __P((KBDC kbdc, int mask)); + +int get_controller_command_byte __P((KBDC kbdc)); +int set_controller_command_byte __P((KBDC kbdc, int command, int flag)); #endif /* KERNEL */ diff --git a/sys/i386/isa/psm.c b/sys/i386/isa/psm.c index 24eb2757aaf6..f4da6f648d84 100644 --- a/sys/i386/isa/psm.c +++ b/sys/i386/isa/psm.c @@ -54,9 +54,11 @@ * - 12 November 1996. IOCTLs and rearranging `psmread', `psmioctl'... * - 14 November 1996. Uses `kbdio.c'. * - 30 November 1996. More fixes. + * - 13 December 1996. Uses queuing version of `kbdio.c'. */ #include "psm.h" +#include "opt_psm.h" #if NPSM > 0 @@ -102,10 +104,6 @@ /* end of driver specific options */ -/* default values */ -#define PSMD_DEFAULT_RESOLUTION 200 /* resolution: 200 ppi */ -#define PSMD_DEFAULT_RATE 100 /* report rate: 100 Hz */ - /* some macros */ #define PSM_UNIT(dev) (minor(dev) >> 1) #define PSM_NBLOCKIO(dev) (minor(dev) & 1) @@ -134,13 +132,14 @@ typedef int (*packetfunc_t) __P((unsigned char *, int *, int, mousestatus_t *)); static struct psm_softc { /* Driver status information */ struct selinfo rsel; /* Process selecting for Input */ unsigned char state; /* Mouse driver state */ + KBDC kbdc; int addr; /* I/O port address */ - int command_byte; /* controller command byte */ mousehw_t hw; /* hardware information */ mousemode_t mode; /* operation mode */ + mousemode_t dflt_mode; /* default operation mode */ ringbuf_t queue; /* mouse status queue */ packetfunc_t mkpacket; /* func. to turn queued data into output format */ - char ipacket[MOUSE_PS2_PACKETSIZE]; /* interim input buffer */ + unsigned char ipacket[MOUSE_PS2_PACKETSIZE];/* interim input buffer */ unsigned char opacket[PSM_BUFSIZE]; /* output buffer */ int inputbytes; /* # of bytes in the input buffer */ int outputbytes; /* # of bytes in the output buffer */ @@ -187,11 +186,11 @@ static int verbose = PSM_DEBUG; /* device I/O routines */ static int -enable_aux_dev(int port) +enable_aux_dev(KBDC kbdc) { int res; - res = send_aux_command(port, PSMC_ENABLE_DEV); + res = send_aux_command(kbdc, PSMC_ENABLE_DEV); if (verbose >= 2) log(LOG_DEBUG, "psm: ENABLE_DEV return code:%04x\n", res); @@ -199,11 +198,11 @@ enable_aux_dev(int port) } static int -disable_aux_dev(int port) +disable_aux_dev(KBDC kbdc) { int res; - res = send_aux_command(port, PSMC_DISABLE_DEV); + res = send_aux_command(kbdc, PSMC_DISABLE_DEV); if (verbose >= 2) log(LOG_DEBUG, "psm: DISABLE_DEV return code:%04x\n", res); @@ -211,41 +210,41 @@ disable_aux_dev(int port) } static int -get_mouse_status(int port, int *status) +get_mouse_status(KBDC kbdc, int *status) { int res; - empty_both_buffers(port, 2); - res = send_aux_command(port, PSMC_SEND_DEV_STATUS); + empty_aux_buffer(kbdc, 5); + res = send_aux_command(kbdc, PSMC_SEND_DEV_STATUS); if (verbose >= 2) log(LOG_DEBUG, "psm: SEND_AUX_STATUS return code:%04x\n", res); if (res != PSM_ACK) return FALSE; - status[0] = read_aux_data(port); - status[1] = read_aux_data(port); - status[2] = read_aux_data(port); + status[0] = read_aux_data(kbdc); + status[1] = read_aux_data(kbdc); + status[2] = read_aux_data(kbdc); return TRUE; } static int -get_aux_id(int port) +get_aux_id(KBDC kbdc) { int res; int id; - empty_both_buffers(port, 2); - res = send_aux_command(port, PSMC_SEND_DEV_ID); + empty_aux_buffer(kbdc, 5); + res = send_aux_command(kbdc, PSMC_SEND_DEV_ID); if (verbose >= 2) log(LOG_DEBUG, "psm: SEND_DEV_ID return code:%04x\n", res); if (res != PSM_ACK) return (-1); - /* 10ms delay */ - DELAY(10000); + /* 10ms delay */ + DELAY(10000); - id = read_aux_data(port); + id = read_aux_data(kbdc); if (verbose >= 2) log(LOG_DEBUG, "psm: device ID: %04x\n", id); @@ -253,11 +252,11 @@ get_aux_id(int port) } static int -set_mouse_sampling_rate(int port, int rate) +set_mouse_sampling_rate(KBDC kbdc, int rate) { int res; - res = send_aux_command_and_data(port, PSMC_SET_SAMPLING_RATE, rate); + res = send_aux_command_and_data(kbdc, PSMC_SET_SAMPLING_RATE, rate); if (verbose >= 2) log(LOG_DEBUG, "psm: SET_SAMPLING_RATE (%d) %04x\n", rate, res); @@ -265,54 +264,28 @@ set_mouse_sampling_rate(int port, int rate) } static int -set_mouse_scaling(int port) +set_mouse_scaling(KBDC kbdc) { int res; - res = send_aux_command(port, PSMC_SET_SCALING11); + res = send_aux_command(kbdc, PSMC_SET_SCALING11); if (verbose >= 2) log(LOG_DEBUG, "psm: SET_SCALING11 return code:%04x\n", res); return (res == PSM_ACK); } -static struct { - int resolution; - int code; -} rescode[] = { - { 25, PSMD_RESOLUTION_25 }, - { 50, PSMD_RESOLUTION_50 }, - { 100, PSMD_RESOLUTION_100 }, - { 200, PSMD_RESOLUTION_200 }, - { 400, PSMD_RESOLUTION_400 }, /* ?? */ - { 800, PSMD_RESOLUTION_800 }, /* ?? */ - { INT_MAX, PSMD_MAX_RESOLUTION }, - { -1 }, -}; - +/* `val' must be 0 through PSMD_MAX_RESOLUTION */ static int -set_mouse_resolution(int port, int res) +set_mouse_resolution(KBDC kbdc, int val) { - int ret; - int i; + int res; - if (res <= 0) - return (-1); - for (i = 0; rescode[i].resolution > 0; ++i) - if (rescode[i].resolution >= res) - break; + res = send_aux_command_and_data(kbdc, PSMC_SET_RESOLUTION, val); + if (verbose >= 2) + log(LOG_DEBUG, "psm: SET_RESOLUTION (%d) %04x\n", val, res); - for (; i >= 0; --i) { - ret = send_aux_command_and_data(port, - PSMC_SET_RESOLUTION, rescode[i].code); - if (verbose >= 2) - log(LOG_DEBUG, "psm: SET_RESOLUTION (%d) %04x\n", - rescode[i].code, ret); - if (ret == PSM_ACK) - return rescode[i].resolution; - } - - return (-1); + return ((res == PSM_ACK) ? val : -1); } /* @@ -320,11 +293,11 @@ set_mouse_resolution(int port, int res) * re-enabled by calling `enable_aux_dev()' */ static int -set_mouse_mode(int port) +set_mouse_mode(KBDC kbdc) { int res; - res = send_aux_command(port, PSMC_SET_STREAM_MODE); + res = send_aux_command(kbdc, PSMC_SET_STREAM_MODE); if (verbose >= 2) log(LOG_DEBUG, "psm: SET_STREAM_MODE return code:%04x\n", res); @@ -332,7 +305,7 @@ set_mouse_mode(int port) } static int -get_mouse_buttons(int port) +get_mouse_buttons(KBDC kbdc) { int c = 2; /* assume two buttons by default */ int res; @@ -344,16 +317,16 @@ get_mouse_buttons(int port) * scaling to 1:1, set scaling to 1:1. Then the second byte of the * mouse status bytes is the number of available buttons. */ - if (set_mouse_resolution(port, 25) != 25) + if (set_mouse_resolution(kbdc, PSMD_RES_LOW) != PSMD_RES_LOW) return c; - if (set_mouse_scaling(port) && set_mouse_scaling(port) - && set_mouse_scaling(port) && get_mouse_status(port, status)) { + if (set_mouse_scaling(kbdc) && set_mouse_scaling(kbdc) + && set_mouse_scaling(kbdc) && get_mouse_status(kbdc, status)) { if (verbose) { log(LOG_DEBUG, "psm: status %02x %02x %02x (get_mouse_buttons)\n", status[0], status[1], status[2]); } - if (status[1] == 3) - return 3; + if (status[1] != 0) + return status[1]; } return c; } @@ -372,38 +345,38 @@ is_a_mouse(int id) -1 /* end of table */ }; #if 0 - int i; + int i; - for(i = 0; valid_ids[i] >= 0; ++i) - if (valid_ids[i] == id) - return TRUE; - return FALSE; + for (i = 0; valid_ids[i] >= 0; ++i) + if (valid_ids[i] == id) + return TRUE; + return FALSE; #else return TRUE; #endif } static void -recover_from_error(int port) +recover_from_error(KBDC kbdc) { /* discard anything left in the output buffer */ - empty_both_buffers(port, 10); + empty_both_buffers(kbdc, 10); #if 0 /* * NOTE: KBDC_RESET_KBD may not restore the communication between the * keyboard and the controller. */ - reset_kbd(port); + reset_kbd(kbdc); #else /* * NOTE: somehow diagnostic and keyboard port test commands bring the * keyboard back. */ - if (!test_controller(port)) + if (!test_controller(kbdc)) log(LOG_ERR, "psm: keyboard controller failed.\n"); /* if there isn't a keyboard in the system, the following error is OK */ - if (test_kbd_port(port) != 0) { + if (test_kbd_port(kbdc) != 0) { if (verbose) log(LOG_ERR, "psm: keyboard port failed.\n"); } @@ -411,9 +384,9 @@ recover_from_error(int port) } static int -restore_controller(int port, int command_byte) +restore_controller(KBDC kbdc, int command_byte) { - if (!set_controller_command_byte(port, command_byte, 0)) { + if (!set_controller_command_byte(kbdc, 0xff, command_byte)) { log(LOG_ERR, "psm: failed to restore the keyboard controller " "command byte.\n"); return FALSE; @@ -426,20 +399,27 @@ restore_controller(int port, int command_byte) * Re-initialize the aux port and device. The aux port must be enabled * and its interrupt must be disabled before calling this routine. * The aux device will be disabled before returning. + * The keyboard controller must be locked via `kbdc_lock()' before + * calling this routine. */ static int reinitialize(dev_t dev, mousemode_t *mode) { - int port = psm_softc[PSM_UNIT(dev)]->addr; + KBDC kbdc = psm_softc[PSM_UNIT(dev)]->kbdc; int stat[3]; int i; - switch((i = test_aux_port(port))) { + switch((i = test_aux_port(kbdc))) { + case 1: /* ignore this error */ + if (verbose) + log(LOG_DEBUG, "psm%d: strange result for test aux port (%d).\n", + PSM_UNIT(dev), i); + /* fall though */ case 0: /* no error */ break; case -1: /* time out */ default: /* error */ - recover_from_error(port); + recover_from_error(kbdc); log(LOG_ERR, "psm%d: the aux port is not functioning (%d).\n", PSM_UNIT(dev),i); return FALSE; @@ -449,8 +429,8 @@ reinitialize(dev_t dev, mousemode_t *mode) * NOTE: some controllers appears to hang the `keyboard' when * the aux port doesn't exist and `PSMC_RESET_DEV' is issued. */ - if (!reset_aux_dev(port)) { - recover_from_error(port); + if (!reset_aux_dev(kbdc)) { + recover_from_error(kbdc); log(LOG_ERR, "psm%d: failed to reset the aux device.\n", PSM_UNIT(dev)); return FALSE; @@ -460,27 +440,29 @@ reinitialize(dev_t dev, mousemode_t *mode) * both the aux port and the aux device is functioning, see * if the device can be enabled. */ - if (!enable_aux_dev(port) || !disable_aux_dev(port)) { + if (!enable_aux_dev(kbdc) || !disable_aux_dev(kbdc)) { log(LOG_ERR, "psm%d: failed to enable the aux device.\n", PSM_UNIT(dev)); return FALSE; } - empty_both_buffers(port, 10); + empty_both_buffers(kbdc, 10); /* remove stray data if any */ /* set mouse parameters */ if (mode != (mousemode_t *)NULL) { if (mode->rate > 0) - mode->rate = set_mouse_sampling_rate(port, mode->rate); - if (mode->resolution > 0) - mode->resolution = set_mouse_resolution(port, mode->resolution); - set_mouse_scaling(port); - set_mouse_mode(port); + mode->rate = set_mouse_sampling_rate(kbdc, mode->rate); + if (mode->resolution >= 0) + mode->resolution = set_mouse_resolution(kbdc, mode->resolution); + set_mouse_scaling(kbdc); + set_mouse_mode(kbdc); } /* just check the status of the mouse */ - if (verbose) { - get_mouse_status(port, stat); - log(LOG_DEBUG, "psm%d: status %02x %02x %02x (reinitialized)\n", + i = get_mouse_status(kbdc, stat); + if (!i) { + log(LOG_DEBUG, "psm%d: failed to get status.\n", PSM_UNIT(dev)); + } else if (verbose) { + log(LOG_DEBUG, "psm%d: status %02x %02x %02x\n", PSM_UNIT(dev), stat[0], stat[1], stat[2]); } @@ -489,40 +471,41 @@ reinitialize(dev_t dev, mousemode_t *mode) /* psm driver entry points */ -#define endprobe(v) { if (bootverbose) \ - --verbose; \ - return (v); \ +#define endprobe(v) { if (bootverbose) \ + --verbose; \ + kbdc_set_device_mask(sc->kbdc, mask); \ + kbdc_lock(sc->kbdc, FALSE); \ + return (v); \ } static int psmprobe(struct isa_device *dvp) { int unit = dvp->id_unit; - int ioport = dvp->id_iobase; struct psm_softc *sc; int stat[3]; - int setparams; + int command_byte; + int mask; int i; /* validate unit number */ if (unit >= NPSM) return (0); - psm_softc[unit] = NULL; - sc = malloc(sizeof *sc, M_DEVBUF, M_NOWAIT); - bzero(sc, sizeof *sc); - sc->addr = ioport; + sc->addr = dvp->id_iobase; + sc->kbdc = kbdc_open(sc->addr); if (bootverbose) ++verbose; - /* - * FIXME:XXX - * the keyboard interrupt should be disabled while probing a - * mouse? - */ + if (!kbdc_lock(sc->kbdc, TRUE)) { + printf("psm%d: unable to lock the controller.\n", unit); + if (bootverbose) + --verbose; + return (0); + } /* * NOTE: two bits in the command byte controls the operation of the @@ -542,8 +525,7 @@ psmprobe(struct isa_device *dvp) * disabled. Case 2b: The aux port exists. A device and a driver may * exist, using the device in the polling(remote) mode. Case 2c: The * aux port exists. A device may exist, but someone who knows nothing - * about the aux port has set the command byte this way (this is the - * case with `syscons'). + * about the aux port has set the command byte this way. * * Case 3: aux port disabled (bit 5:1), aux int. enabled (bit 2:1) The * aux port exists, but someone is controlloing the device and @@ -557,24 +539,19 @@ psmprobe(struct isa_device *dvp) * of the port and the mouse device. */ + /* discard anything left after the keyboard initialization */ + empty_both_buffers(sc->kbdc, 10); + /* save the current command byte; it will be used later */ - if (!write_controller_command(ioport,KBDC_GET_COMMAND_BYTE)) { - /* CONTROLLER ERROR */ - printf("psm%d: failed to get the current command byte value.\n", - unit); - free(sc, M_DEVBUF); - endprobe(0); - } - sc->command_byte = read_controller_data(ioport); - if (verbose) { - printf("psm%d: current command byte:%04x\n", - unit, sc->command_byte); - } - if (sc->command_byte == -1) { + mask = kbdc_get_device_mask(sc->kbdc) & ~KBD_AUX_CONTROL_BITS; + command_byte = get_controller_command_byte(sc->kbdc); + if (verbose) + printf("psm%d: current command byte:%04x\n", unit, command_byte); + if (command_byte == -1) { /* CONTROLLER ERROR */ printf("psm%d: unable to get the current command byte value.\n", unit); - free(sc, M_DEVBUF); + free(sc, M_DEVBUF); endprobe(0); } @@ -582,15 +559,15 @@ psmprobe(struct isa_device *dvp) * disable the keyboard port while probing the aux port, which must be * enabled during this routine */ - if (!set_controller_command_byte(ioport, - sc->command_byte & ~(KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS), - KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT - | KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { + if (!set_controller_command_byte(sc->kbdc, + KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS, + KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT + | KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { /* * this is CONTROLLER ERROR; I don't know how to recover * from this error... */ - restore_controller(ioport, sc->command_byte); + restore_controller(sc->kbdc, command_byte); printf("psm%d: unable to set the command byte.\n", unit); free(sc, M_DEVBUF); endprobe(0); @@ -606,18 +583,28 @@ psmprobe(struct isa_device *dvp) * supporsed to return with an error code or simply time out. In any * case, we have to continue probing the port even when the controller * passes this test. + * + * XXX: some controllers erroneously return the error code 1 when + * it has the perfectly functional aux port. We have to ignore this + * error code. Even if the controller HAS error with the aux port, + * it will be detected later... */ - switch ((i = test_aux_port(ioport))) { + switch ((i = test_aux_port(sc->kbdc))) { + case 1: /* ignore this error */ + if (verbose) + printf("psm%d: strange result for test aux port (%d).\n", + unit, i); + /* fall though */ case 0: /* no error */ break; case -1: /* time out */ default: /* error */ - recover_from_error(ioport); - restore_controller(ioport, sc->command_byte); + recover_from_error(sc->kbdc); + restore_controller(sc->kbdc, command_byte); if (verbose) printf("psm%d: the aux port is not functioning (%d).\n", unit, i); - free(sc, M_DEVBUF); + free(sc, M_DEVBUF); endprobe(0); } @@ -625,12 +612,12 @@ psmprobe(struct isa_device *dvp) * NOTE: some controllers appears to hang the `keyboard' when the aux * port doesn't exist and `PSMC_RESET_DEV' is issued. */ - if (!reset_aux_dev(ioport)) { - recover_from_error(ioport); - restore_controller(ioport, sc->command_byte); + if (!reset_aux_dev(sc->kbdc)) { + recover_from_error(sc->kbdc); + restore_controller(sc->kbdc, command_byte); if (verbose) printf("psm%d: failed to reset the aux device.\n", unit); - free(sc, M_DEVBUF); + free(sc, M_DEVBUF); endprobe(0); } /* @@ -639,43 +626,37 @@ psmprobe(struct isa_device *dvp) * sending data; we shall immediately disable the device once we know * the device can be enabled. */ - if (!enable_aux_dev(ioport) || !disable_aux_dev(ioport)) { + if (!enable_aux_dev(sc->kbdc) || !disable_aux_dev(sc->kbdc)) { /* MOUSE ERROR */ - restore_controller(ioport, sc->command_byte); + restore_controller(sc->kbdc, command_byte); if (verbose) printf("psm%d: failed to enable the aux device.\n", unit); - free(sc, M_DEVBUF); + free(sc, M_DEVBUF); endprobe(0); } - empty_both_buffers(ioport, 10); /* remove stray data if any */ /* save the default values after reset */ - if (get_mouse_status(ioport, stat)) { + if (get_mouse_status(sc->kbdc, stat)) { if (verbose) printf("psm%d: status after reset %02x %02x %02x\n", unit, stat[0], stat[1], stat[2]); - sc->mode.rate = stat[2]; - sc->mode.resolution = PSMD_DEFAULT_RESOLUTION; - for (i = 0; rescode[i].resolution > 0; ++i) - if (rescode[i].code == stat[1]) - sc->mode.resolution = rescode[i].resolution; - setparams = TRUE; + sc->dflt_mode.rate = sc->mode.rate = stat[2]; + sc->dflt_mode.resolution = sc->mode.resolution = stat[1]; } else { - sc->mode.rate = -1; - sc->mode.resolution = -1; - setparams = FALSE; + sc->dflt_mode.rate = sc->mode.rate = -1; + sc->dflt_mode.resolution = sc->mode.resolution = -1; } /* hardware information */ sc->hw.iftype = MOUSE_IF_PS2; /* verify the device is a mouse */ - sc->hw.hwid = get_aux_id(ioport); + sc->hw.hwid = get_aux_id(sc->kbdc); if (!is_a_mouse(sc->hw.hwid)) { - restore_controller(ioport, sc->command_byte); + restore_controller(sc->kbdc, command_byte); if (verbose) printf("psm%d: unknown device type (%d).\n", unit, sc->hw.hwid); - free(sc, M_DEVBUF); + free(sc, M_DEVBUF); endprobe(0); } switch (sc->hw.hwid) { @@ -691,53 +672,53 @@ psmprobe(struct isa_device *dvp) } /* # of buttons */ - sc->hw.buttons = (setparams) ? get_mouse_buttons(ioport) : 2; + sc->hw.buttons = get_mouse_buttons(sc->kbdc); /* set mouse parameters */ /* FIXME:XXX should we set them in `psmattach()' rather than here? */ - if (setparams) { - if (sc->mode.rate > 0) - sc->mode.rate = set_mouse_sampling_rate(ioport, sc->mode.rate); - if (sc->mode.resolution > 0) - sc->mode.resolution = - set_mouse_resolution(ioport, sc->mode.resolution); - } /* FIXME:XXX I don't know if these parameters are reasonable */ - set_mouse_scaling(ioport); /* 1:1 scaling */ - set_mouse_mode(ioport); /* stream mode */ + i = send_aux_command(sc->kbdc, PSMC_SET_DEFAULTS); + if (verbose >= 2) + log(LOG_DEBUG, "psm%d: SET_DEFAULTS return code:%04x\n", + unit, i); +#if 0 + set_mouse_scaling(sc->kbdc); /* 1:1 scaling */ + set_mouse_mode(sc->kbdc); /* stream mode */ +#endif /* just check the status of the mouse */ - if (verbose) { - get_mouse_status(ioport, stat); + /* + * NOTE: XXX there are some arcane controller/mouse combinations out + * there, which hung the controller unless there is data transmission + * after ACK from the mouse. + */ + i = get_mouse_status(sc->kbdc, stat); + if (!i) { + log(LOG_DEBUG, "psm%d: failed to get status.\n", unit); + } else if (verbose) { log(LOG_DEBUG, "psm%d: status %02x %02x %02x\n", unit, stat[0], stat[1], stat[2]); } /* disable the aux port for now... */ - - /* - * WARNING: we save the controller command byte and use it later - * during `psmopen()' and `psmclose()'. This will be OK, so long as - * the keyboard/console device driver won't change the command byte in - * the course of its operation (this is the case with `syscons'). If - * not,... - */ - if (!set_controller_command_byte(ioport, - sc->command_byte & ~KBD_AUX_CONTROL_BITS, - KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { + if (!set_controller_command_byte(sc->kbdc, + KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS, + (command_byte & KBD_KBD_CONTROL_BITS) + | KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { /* * this is CONTROLLER ERROR; I don't know the proper way to * recover from this error... */ - restore_controller(ioport, sc->command_byte); + restore_controller(sc->kbdc, command_byte); printf("psm%d: unable to set the command byte.\n", unit); free(sc, M_DEVBUF); endprobe(0); } - sc->command_byte &= ~KBD_AUX_CONTROL_BITS; /* done */ psm_softc[unit] = sc; + kbdc_set_device_mask(sc->kbdc, mask | KBD_AUX_CONTROL_BITS); + kbdc_lock(sc->kbdc, FALSE); return (IO_PSMSIZE); } @@ -747,12 +728,9 @@ psmattach(struct isa_device *dvp) int unit = dvp->id_unit; struct psm_softc *sc = psm_softc[unit]; - if (sc == NULL) /* shouldn't happen */ - return (0); - /* initial operation mode */ - sc->mode.accelfactor = PSM_ACCEL; - sc->mode.protocol = MOUSE_PROTO_PS2; + sc->dflt_mode.accelfactor = sc->mode.accelfactor = PSM_ACCEL; + sc->dflt_mode.protocol = sc->mode.protocol = MOUSE_PROTO_PS2; sc->mkpacket = mkps2; /* Setup initial state */ @@ -768,8 +746,8 @@ psmattach(struct isa_device *dvp) DV_CHR, 0, 0, 0666, "npsm%d", unit); #endif - printf("psm%d: device ID %d, %d buttons?\n", - unit, sc->hw.hwid, sc->hw.buttons); + printf("psm%d: device ID %d, %d buttons\n", + unit, sc->hw.hwid, sc->hw.buttons); if (bootverbose) --verbose; @@ -781,9 +759,11 @@ static int psmopen(dev_t dev, int flag, int fmt, struct proc *p) { int unit = PSM_UNIT(dev); - int ioport; struct psm_softc *sc; int stat[3]; + int command_byte; + int ret; + int s; /* Validate unit number */ if (unit >= NPSM) @@ -791,10 +771,9 @@ psmopen(dev_t dev, int flag, int fmt, struct proc *p) /* Get device data */ sc = psm_softc[unit]; - if ((sc == NULL) || (sc->state & PSM_VALID) == 0) + if ((sc->state & PSM_VALID) == 0) /* the device is no longer valid/functioning */ return (ENXIO); - ioport = sc->addr; /* Disallow multiple opens */ if (sc->state & PSM_OPEN) @@ -815,58 +794,79 @@ psmopen(dev_t dev, int flag, int fmt, struct proc *p) sc->outputbytes = 0; sc->outputhead = 0; + /* don't let timeout routines in the keyboard driver to poll the kbdc */ + if (!kbdc_lock(sc->kbdc, TRUE)) + return (EIO); + + /* save the current controller command byte */ + s = spltty(); + command_byte = get_controller_command_byte(sc->kbdc); + /* enable the aux port and temporalily disable the keyboard */ - if (!set_controller_command_byte(ioport, - sc->command_byte & ~KBD_KBD_CONTROL_BITS, - KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT - | KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { + if ((command_byte == -1) + || !set_controller_command_byte(sc->kbdc, + kbdc_get_device_mask(sc->kbdc), + KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT + | KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { /* CONTROLLER ERROR; do you know how to get out of this? */ - set_controller_command_byte(ioport, - sc->command_byte, KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT); + kbdc_lock(sc->kbdc, FALSE); + splx(s); log(LOG_ERR, "psm%d: unable to set the command byte (psmopen).\n", unit); return (EIO); } - + /* + * 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 timeout routines will be blocked by the poll flag set + * via `kbdc_lock()' + */ + splx(s); + /* enable the mouse device */ - if (!enable_aux_dev(ioport)) { + if (!enable_aux_dev(sc->kbdc)) { /* MOUSE ERROR: failed to enable the mouse because: * 1) the mouse is faulty, * 2) the mouse has been removed(!?) * In the latter case, the keyboard may have hung, and need * recovery procedure... */ - recover_from_error(ioport); + recover_from_error(sc->kbdc); #if 0 /* FIXME: we could reset the mouse here and try to enable * it again. But it will take long time and it's not a good * idea to disable the keyboard that long... */ - if (!reinitialize(dev, &sc->mode) || !enable_aux_dev(ioport)) - recover_from_error(ioport); + if (!reinitialize(dev, &sc->mode) || !enable_aux_dev(sc->kbdc)) + recover_from_error(sc->kbdc); #endif - set_controller_command_byte(ioport, - sc->command_byte, KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT); + restore_controller(sc->kbdc, command_byte); /* mark this device is no longer available */ sc->state &= ~PSM_VALID; + kbdc_lock(sc->kbdc, FALSE); log(LOG_ERR, "psm%d: failed to enable the device (psmopen).\n", unit); - return (EIO); + return (EIO); } - if (verbose >= 2) { - get_mouse_status(ioport, stat); - log(LOG_DEBUG, "psm%d: status %02x %02x %02x\n", + ret = get_mouse_status(sc->kbdc, stat); + if (!ret) { + log(LOG_DEBUG, "psm%d: failed to get status (psmopen).\n", unit); + } else if (verbose >= 2) { + log(LOG_DEBUG, "psm%d: status %02x %02x %02x (psmopen)\n", unit, stat[0], stat[1], stat[2]); } /* enable the aux port and interrupt */ - if (!set_controller_command_byte(ioport, sc->command_byte, - KBD_ENABLE_AUX_PORT | KBD_ENABLE_AUX_INT)) { + if (!set_controller_command_byte(sc->kbdc, + kbdc_get_device_mask(sc->kbdc), + (command_byte & KBD_KBD_CONTROL_BITS) + | KBD_ENABLE_AUX_PORT | KBD_ENABLE_AUX_INT)) { /* CONTROLLER ERROR */ - disable_aux_dev(ioport); - set_controller_command_byte(ioport, sc->command_byte, - KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT); + disable_aux_dev(sc->kbdc); + restore_controller(sc->kbdc, command_byte); + kbdc_lock(sc->kbdc, FALSE); log(LOG_ERR, "psm%d: failed to enable the aux interrupt (psmopen).\n", unit); return (EIO); @@ -874,6 +874,7 @@ psmopen(dev_t dev, int flag, int fmt, struct proc *p) /* done */ sc->state |= PSM_OPEN; + kbdc_lock(sc->kbdc, FALSE); return (0); } @@ -881,11 +882,29 @@ static int psmclose(dev_t dev, int flag, int fmt, struct proc *p) { struct psm_softc *sc = psm_softc[PSM_UNIT(dev)]; - int ioport = sc->addr; + int stat[3]; + int command_byte; + int ret; + int s; - /* disable the aux interrupt */ - if (!set_controller_command_byte(ioport, sc->command_byte, - KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { + /* don't let timeout routines in the keyboard driver to poll the kbdc */ + if (!kbdc_lock(sc->kbdc, TRUE)) + return (EIO); + + /* save the current controller command byte */ + s = spltty(); + command_byte = get_controller_command_byte(sc->kbdc); + if (command_byte == -1) { + kbdc_lock(sc->kbdc, FALSE); + splx(s); + return (EIO); + } + + /* disable the aux interrupt and temporalily disable the keyboard */ + if (!set_controller_command_byte(sc->kbdc, + kbdc_get_device_mask(sc->kbdc), + KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT + | KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { log(LOG_ERR, "psm%d: failed to disable the aux int (psmclose).\n", PSM_UNIT(dev)); /* CONTROLLER ERROR; @@ -895,12 +914,13 @@ psmclose(dev_t dev, int flag, int fmt, struct proc *p) * so long as the mouse will accept the DISABLE command. */ } + splx(s); /* remove anything left in the output buffer */ - empty_aux_buffer(ioport, 20); + empty_aux_buffer(sc->kbdc, 10); /* disable the aux device, port and interrupt */ - if (!disable_aux_dev(ioport)) { + if (!disable_aux_dev(sc->kbdc)) { /* MOUSE ERROR; * NOTE: we don't return error and continue, pretending * we have successfully disabled the device. It's OK because @@ -910,8 +930,20 @@ psmclose(dev_t dev, int flag, int fmt, struct proc *p) log(LOG_ERR, "psm%d: failed to disable the device (psmclose).\n", PSM_UNIT(dev)); } - if (!set_controller_command_byte(ioport, sc->command_byte, - KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { + + ret = get_mouse_status(sc->kbdc, stat); + if (!ret) { + log(LOG_DEBUG, "psm%d: failed to get status (psmclose).\n", + PSM_UNIT(dev)); + } else if (verbose >= 2) { + log(LOG_DEBUG, "psm%d: status %02x %02x %02x (psmclose)\n", + PSM_UNIT(dev), stat[0], stat[1], stat[2]); + } + + if (!set_controller_command_byte(sc->kbdc, + kbdc_get_device_mask(sc->kbdc), + (command_byte & KBD_KBD_CONTROL_BITS) + | KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { /* CONTROLLER ERROR; * we shall ignore this error; see the above comment. */ @@ -920,10 +952,11 @@ psmclose(dev_t dev, int flag, int fmt, struct proc *p) } /* remove anything left in the output buffer */ - empty_aux_buffer(ioport, 10); + empty_aux_buffer(sc->kbdc, 10); /* close is almost always successful */ sc->state &= ~PSM_OPEN; + kbdc_lock(sc->kbdc, FALSE); return (0); } @@ -1120,22 +1153,22 @@ mkps2(unsigned char *buf, int *len, int maxlen, register mousestatus_t *status) if ((verbose >= 2) && ((buf[0] & MOUSE_PS2_BUTTON4UP) == 0)) log(LOG_DEBUG, "psm: button 4 down (%04x) (mkps2)\n", buf[0]); - if (status->dx < -128) - delta = -128; + if (status->dx < -256) + delta = -256; else - if (status->dx > 127) - delta = 127; + if (status->dx > 255) + delta = 255; else delta = status->dx; if (delta < 0) buf[0] |= MOUSE_PS2_XNEG; buf[1] = delta; - if (status->dy < -128) - delta = -128; + if (status->dy < -256) + delta = -256; else - if (status->dy > 127) - delta = 127; + if (status->dy > 255) + delta = 255; else delta = status->dy; if (delta < 0) @@ -1166,6 +1199,7 @@ psmread(dev_t dev, struct uio *uio, int flag) } sc->state |= PSM_ASLP; error = tsleep((caddr_t) sc, PZERO | PCATCH, "psmread", 0); + sc->state &= ~PSM_ASLP; if (error) { splx(s); return (error); @@ -1211,6 +1245,7 @@ psmioctl(dev_t dev, int cmd, caddr_t addr, int flag, struct proc *p) mousemode_t mode; mousestatus_t status; packetfunc_t func; + int command_byte; int error = 0; int s; @@ -1223,24 +1258,26 @@ psmioctl(dev_t dev, int cmd, caddr_t addr, int flag, struct proc *p) case MOUSE_GETMODE: *(mousemode_t *) addr = sc->mode; + if (sc->mode.resolution >= 0) + ((mousemode_t *) addr)->resolution = sc->mode.resolution + 1; break; case MOUSE_SETMODE: mode = *(mousemode_t *) addr; if (mode.rate == 0) { - mode.rate = PSMD_DEFAULT_RATE; + mode.rate = sc->dflt_mode.rate; } else if (mode.rate > 0) { mode.rate = min(mode.rate, PSMD_MAX_RATE); } else { /* mode.rate < 0 */ mode.rate = sc->mode.rate; } if (mode.resolution == 0) { - mode.resolution = PSMD_DEFAULT_RESOLUTION; + mode.resolution = sc->dflt_mode.resolution; } else if (mode.resolution > 0) { - mode.resolution = mode.resolution; + mode.resolution = min(mode.resolution - 1, PSMD_MAX_RESOLUTION); } else { /* mode.resolution < 0 */ mode.resolution = sc->mode.resolution; - } + } #ifdef PSM_EMULATION switch (mode.protocol) { case MOUSE_PROTO_MS: @@ -1273,41 +1310,69 @@ psmioctl(dev_t dev, int cmd, caddr_t addr, int flag, struct proc *p) break; } - s = spltty(); /* disable interrupt while updating */ + /* don't allow anybody to poll the keyboard controller */ + if (!kbdc_lock(sc->kbdc, TRUE)) { + error = EIO; + break; + } /* temporalily disable the keyboard */ - if (!set_controller_command_byte(sc->addr, - sc->command_byte & ~KBD_KBD_CONTROL_BITS, - KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT - | KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { + s = spltty(); + command_byte = get_controller_command_byte(sc->kbdc); + if ((command_byte == -1) + || !set_controller_command_byte(sc->kbdc, + kbdc_get_device_mask(sc->kbdc), + KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT + | KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { /* this is CONTROLLER ERROR; I don't know how to recover - * from this error. The least we can do is to send - * ENABLE_KBD_PORT... + * from this error. */ - write_controller_command(sc->addr, KBDC_ENABLE_KBD_PORT); + kbdc_lock(sc->kbdc, FALSE); splx(s); log(LOG_ERR, "psm%d: failed to set the command byte (psmioctl).\n", PSM_UNIT(dev)); error = EIO; break; } + /* + * The device may be in the middle of status data transmission. + * The transmission will be interrupted, thus, incomplete status + * data must be discarded. Although the aux interrupt is disabled + * at the keyboard controller level, at most one aux interrupt + * may have already been pending and a data byte is in the + * output buffer; throw it away. Note that the second argument + * to `empty_aux_buffer()' is zero, so that the call will just + * flush the internal queue. + * `psmintr()' will be invoked after `splx()' if an interrupt is + * pending; it will see no data and returns immediately. + */ + empty_aux_buffer(sc->kbdc, 0); /* flush the queue */ + read_aux_data_no_wait(sc->kbdc); /* throw away data if any */ + sc->inputbytes = 0; + splx(s); - /* program the mouse */ if (mode.rate > 0) - mode.rate = set_mouse_sampling_rate(sc->addr, mode.rate); - if (mode.resolution > 0) - mode.resolution = set_mouse_resolution(sc->addr, mode.resolution); + mode.rate = set_mouse_sampling_rate(sc->kbdc, mode.rate); + if (mode.resolution >= 0) + mode.resolution = set_mouse_resolution(sc->kbdc, mode.resolution); + + /* + * We may have seen a part of status data, which is queued, + * during `set_mouse_XXX()'; flush it. + */ + empty_aux_buffer(sc->kbdc, 0); - /* enable the aux port and interrupt */ - if (!set_controller_command_byte(sc->addr, sc->command_byte, - KBD_ENABLE_AUX_PORT | KBD_ENABLE_AUX_INT)) { + /* restore ports and interrupt */ + if (!set_controller_command_byte(sc->kbdc, + kbdc_get_device_mask(sc->kbdc), + command_byte & (KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS))) { /* CONTROLLER ERROR; this is serious, we may have * been left with the unaccessible keyboard and * the disabled mouse interrupt. */ - splx(s); - log(LOG_ERR, "psm%d: failed to re-enable the aux port and int (psmioctl).\n", - PSM_UNIT(dev)); + kbdc_lock(sc->kbdc, FALSE); + log(LOG_ERR, "psm%d: failed to re-enable " + "the aux port and int (psmioctl).\n", PSM_UNIT(dev)); error = EIO; break; } @@ -1318,8 +1383,8 @@ psmioctl(dev_t dev, int cmd, caddr_t addr, int flag, struct proc *p) sc->outputbytes = 0; sc->outputhead = 0; #endif /* PSM_EMULATION */ + kbdc_lock(sc->kbdc, FALSE); - splx(s); break; case MOUSEIOCREAD: /* FIXME:XXX this should go... */ @@ -1335,7 +1400,7 @@ psmioctl(dev_t dev, int cmd, caddr_t addr, int flag, struct proc *p) } else { status.button = status.obutton = sc->button; status.dx = status.dy = 0; - } + } splx(s); *(mousestatus_t *) addr = status; @@ -1355,9 +1420,9 @@ psmintr(int unit) { /* * the table to turn PS/2 mouse button bits (MOUSE_PS2_BUTTON?DOWN) - * into `mousestatus' button bits (BUTTON?DOWN). + * into `mousestatus' button bits (MOUSE_BUTTON?DOWN). */ - static butmap[8] = { + static int butmap[8] = { 0, MOUSE_BUTTON1DOWN, MOUSE_BUTTON3DOWN, MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN, @@ -1367,117 +1432,115 @@ psmintr(int unit) MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN }; register struct psm_softc *sc = psm_softc[unit]; - int ioport = sc->addr; mousestatus_t *ms; - unsigned char c; - int x, y; + int c; + int x, y; - /* is this really for us? */ - if ((inb(ioport + KBD_STATUS_PORT) & KBDS_BUFFER_FULL) - != KBDS_AUX_BUFFER_FULL) - return; - DELAY(7); - - /* read a byte */ - c = inb(ioport + KBD_DATA_PORT); - - /* discard the byte if the device is not open */ - if ((sc->state & PSM_OPEN) == 0) - return; - - /* interpret data bytes */ - /* - * FIXME: there seems no way to reliably - * re-synchronize with the PS/2 mouse once we are out of sync. Sure, - * there is sync bits in the first data byte, but the second and the - * third bytes may have these bits on (they are not functioning as - * sync bits then!). There need to be two consequtive bytes with these - * bits off to re-sync. (This can be done if the user clicks buttons - * without moving the mouse?) - */ - if (sc->inputbytes == 0) { + /* read until there is nothing to read */ + while((c = read_aux_data_no_wait(sc->kbdc)) != -1) { + + /* discard the byte if the device is not open */ + if ((sc->state & PSM_OPEN) == 0) + continue; + + /* + * FIXME: there seems no way to reliably + * re-synchronize with the PS/2 mouse once we are out of sync. Sure, + * there is a sync bit in the first data byte, but the second and the + * third bytes may have these bits on (oh, it's not functioning as + * sync bit then!). There need to be two consequtive bytes with this + * bit off to re-sync. (This can be done if the user clicks buttons + * without moving the mouse?) + */ + if (sc->inputbytes == 0) { #ifdef PSM_CHECKSYNC - if ((c & MOUSE_PS2_SYNCMASK) == MOUSE_PS2_SYNC) - sc->ipacket[sc->inputbytes++] = c; - else - log(LOG_DEBUG, "psmintr: sync. bit is off.\n"); + if ((c & MOUSE_PS2_SYNCMASK) == MOUSE_PS2_SYNC) + sc->ipacket[sc->inputbytes++] = c; + else + log(LOG_DEBUG, "psmintr: sync. bit is off (%04x).\n", c); #else - sc->ipacket[sc->inputbytes++] = c; -#endif /* PSM_CHECKSYNC */ - } else { - sc->ipacket[sc->inputbytes++] = c; - if (sc->inputbytes >= MOUSE_PS2_PACKETSIZE) { - if (sc->queue.count >= PSM_BUFSIZE) { - /* no room in the queue */ - sc->inputbytes = 0; - return; - } - if (sc->mode.accelfactor >= 1) { - x = (sc->ipacket[0] & MOUSE_PS2_XOVERFLOW) ? - 128 : sc->ipacket[1]; - if (x != 0) { - x = x * x / sc->mode.accelfactor; - if (x == 0) - x = 1; - if (sc->ipacket[0] & MOUSE_PS2_XNEG) - x = -x; + sc->ipacket[sc->inputbytes++] = c; +#endif /* PSM_CHECKSYNC */ + } else { + sc->ipacket[sc->inputbytes++] = c; + if (sc->inputbytes >= MOUSE_PS2_PACKETSIZE) { + if (sc->queue.count >= PSM_BUFSIZE) { + /* no room in the queue */ + sc->inputbytes = 0; + return; } - y = (sc->ipacket[0] & MOUSE_PS2_YOVERFLOW) ? - 128 : sc->ipacket[2]; - if (y != 0) { - y = y * y / sc->mode.accelfactor; - if (y == 0) - y = 1; - if (sc->ipacket[0] & MOUSE_PS2_YNEG) - y = -y; - } - } else {/* sc->mode.accelfactor <= 0 */ - x = (sc->ipacket[0] & MOUSE_PS2_XOVERFLOW) ? - ((sc->ipacket[0] & MOUSE_PS2_XNEG) ? - -128 : 127) : sc->ipacket[1]; - y = (sc->ipacket[0] & MOUSE_PS2_YOVERFLOW) ? - ((sc->ipacket[0] & MOUSE_PS2_YNEG) ? - -128 : 127) : sc->ipacket[2]; - } - - /* - * FIXME:XXX - * we shouldn't store data if no movement and - * no button status change is detected? - */ - ms = &sc->queue.buf[sc->queue.tail]; - ms->dx = x; - ms->dy = y; - ms->obutton = sc->button; /* previous button state */ - sc->button = ms->button = /* latest button state */ - butmap[sc->ipacket[0] & MOUSE_PS2_BUTTONS] - | ((sc->ipacket[0] & MOUSE_PS2_BUTTON4UP) - ? 0 : MOUSE_BUTTON4DOWN); #if 0 - if ((verbose >= 2) - && ((sc->ipacket[0] & MOUSE_PS2_BUTTON4UP) == 0)) - log(LOG_DEBUG, "psm%d: button 4 down (%04x) (psmintr)\n", - unit, sc->ipacket[0]); + x = (sc->ipacket[0] & MOUSE_PS2_XOVERFLOW) ? + ((sc->ipacket[0] & MOUSE_PS2_XNEG) ? -256 : 255) : + ((sc->ipacket[0] & MOUSE_PS2_XNEG) ? + sc->ipacket[1] - 256 : sc->ipacket[1]); + y = (sc->ipacket[0] & MOUSE_PS2_YOVERFLOW) ? + ((sc->ipacket[0] & MOUSE_PS2_YNEG) ? -256 : 255) : + ((sc->ipacket[0] & MOUSE_PS2_YNEG) ? + sc->ipacket[2] - 256 : sc->ipacket[2]); +#else + /* it seems OK to ignore the OVERFLOW bits... */ + x = (sc->ipacket[0] & MOUSE_PS2_XNEG) ? + sc->ipacket[1] - 256 : sc->ipacket[1]; + y = (sc->ipacket[0] & MOUSE_PS2_YNEG) ? + sc->ipacket[2] - 256 : sc->ipacket[2]; #endif - sc->queue.tail = - (sc->queue.tail + 1) % PSM_BUFSIZE; - ++sc->queue.count; - sc->inputbytes = 0; + if (sc->mode.accelfactor >= 1) { + if (x != 0) { + x = x * x / sc->mode.accelfactor; + if (x == 0) + x = 1; + if (sc->ipacket[0] & MOUSE_PS2_XNEG) + x = -x; + } + if (y != 0) { + y = y * y / sc->mode.accelfactor; + if (y == 0) + y = 1; + if (sc->ipacket[0] & MOUSE_PS2_YNEG) + y = -y; + } + } + + /* + * FIXME:XXX + * we shouldn't store data if no movement and + * no button status change is detected? + */ + ms = &sc->queue.buf[sc->queue.tail]; + ms->dx = x; + ms->dy = y; + ms->obutton = sc->button; /* previous button state */ + sc->button = ms->button = /* latest button state */ + butmap[sc->ipacket[0] & MOUSE_PS2_BUTTONS] + | ((sc->ipacket[0] & MOUSE_PS2_BUTTON4UP) + ? 0 : MOUSE_BUTTON4DOWN); +#if 0 + if ((verbose >= 2) + && ((sc->ipacket[0] & MOUSE_PS2_BUTTON4UP) == 0)) + log(LOG_DEBUG, "psm%d: button 4 down (%04x) (psmintr)\n", + unit, sc->ipacket[0]); +#endif + sc->queue.tail = (sc->queue.tail + 1) % PSM_BUFSIZE; + ++sc->queue.count; + sc->inputbytes = 0; + + if (sc->state & PSM_ASLP) { + sc->state &= ~PSM_ASLP; + wakeup((caddr_t) sc); + } + selwakeup(&sc->rsel); + } } } - - if (sc->state & PSM_ASLP) { - sc->state &= ~PSM_ASLP; - wakeup((caddr_t) sc); - } - selwakeup(&sc->rsel); } static int psmselect(dev_t dev, int rw, struct proc *p) { struct psm_softc *sc = psm_softc[PSM_UNIT(dev)]; - int s, ret; + int ret; + int s; /* Silly to select for output */ if (rw == FWRITE) diff --git a/sys/i386/isa/syscons.c b/sys/i386/isa/syscons.c index 853efd6f16e2..68b5f0132727 100644 --- a/sys/i386/isa/syscons.c +++ b/sys/i386/isa/syscons.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1992-1996 Søren Schmidt + * Copyright (c) 1992-1997 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -103,6 +103,7 @@ static term_stat kernel_console; static default_attr *current_default; static int flags = 0; static int sc_port = IO_KBD; +static KBDC sc_kbdc = NULL; static char init_done = COLD; static u_short sc_buffer[ROW*COL]; static char switch_in_progress = FALSE; @@ -113,9 +114,6 @@ static int blinkrate = 0; char crtc_vga = FALSE; static u_char shfts = 0, ctls = 0, alts = 0, agrs = 0, metas = 0; static u_char nlkcnt = 0, clkcnt = 0, slkcnt = 0, alkcnt = 0; - char *font_8 = NULL, *font_14 = NULL, *font_16 = NULL; - int fonts_loaded = 0; - char *palette; static const u_int n_fkey_tab = sizeof(fkey_tab) / sizeof(*fkey_tab); static int delayed_next_scr = FALSE; static long scrn_blank_time = 0; /* screen saver timeout value */ @@ -124,6 +122,11 @@ static long scrn_time_stamp; u_char scr_map[256]; u_char scr_rmap[256]; char *video_mode_ptr = NULL; + int fonts_loaded = 0; + char font_8[256*8]; + char font_14[256*14]; + char font_16[256*16]; + char palette[256*3]; static char *cut_buffer; static u_short mouse_and_mask[16] = { 0xc000, 0xe000, 0xf000, 0xf800, @@ -194,6 +197,7 @@ static void history_to_screen(scr_stat *scp); static int history_up_line(scr_stat *scp); static int history_down_line(scr_stat *scp); static int mask2attr(struct term_stat *term); +static void set_keyboard(int command, int data); static void update_leds(int which); static void set_vgaregs(char *modetable); static void set_font_mode(void); @@ -294,28 +298,34 @@ move_crsr(scr_stat *scp, int x, int y) static int scprobe(struct isa_device *dev) { - int c; + int codeset; + int c = -1; + int m; sc_port = dev->id_iobase; + sc_kbdc = kbdc_open(sc_port); + + if (!kbdc_lock(sc_kbdc, TRUE)) { + /* driver error? */ + printf("sc%d: unable to lock the controller.\n", dev->id_unit); + return ((dev->id_flags & DETECT_KBD) ? 0 : IO_KBDSIZE); + } /* discard anything left after UserConfig */ - empty_both_buffers(sc_port, 10); + empty_both_buffers(sc_kbdc, 10); /* save the current keyboard controller command byte */ - c = -1; - if (!write_controller_command(sc_port, KBDC_GET_COMMAND_BYTE)) { - /* CONTROLLER ERROR */ - printf("sc%d: unable to get the current command byte value.\n", - dev->id_unit); - goto fail; - } - c = read_controller_data(sc_port); + m = kbdc_get_device_mask(sc_kbdc) & ~KBD_KBD_CONTROL_BITS; + c = get_controller_command_byte(sc_kbdc); if (c == -1) { /* CONTROLLER ERROR */ printf("sc%d: unable to get the current command byte value.\n", dev->id_unit); goto fail; } + if (bootverbose) + printf("sc%d: the current keyboard controller command byte %04x\n", + dev->id_unit, c); #if 0 /* override the keyboard lock switch */ c |= KBD_OVERRIDE_KBD_LOCK; @@ -325,19 +335,40 @@ scprobe(struct isa_device *dev) * enable the keyboard port, but disable the keyboard intr. * the aux port (mouse port) is disabled too. */ - if (!set_controller_command_byte(sc_port, - c & ~(KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS), + if (!set_controller_command_byte(sc_kbdc, + KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS, KBD_ENABLE_KBD_PORT | KBD_DISABLE_KBD_INT - | KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { + | KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { /* CONTROLLER ERROR * there is very little we can do... */ printf("sc%d: unable to set the command byte.\n", dev->id_unit); goto fail; } + + /* + * Check if we have an XT keyboard before we attempt to reset it. + * The procedure assumes that the keyboard and the controller have + * been set up properly by BIOS and have not been messed up + * during the boot process. + */ + codeset = -1; + if (dev->id_flags & XT_KEYBD) + /* the user says there is a XT keyboard */ + codeset = 1; +#ifdef DETECT_XT_KEYBOARD + else if ((c & KBD_TRANSLATION) == 0) { + /* SET_SCANCODE_SET is not always supported; ignore error */ + if (send_kbd_command_and_data(sc_kbdc, KBDC_SET_SCANCODE_SET, 0) + == KBD_ACK) + codeset = read_kbd_data(sc_kbdc); + } + if (bootverbose) + printf("sc%d: keyboard scancode set %d\n", dev->id_unit, codeset); +#endif /* DETECT_XT_KEYBOARD */ /* reset keyboard hardware */ - if (!reset_kbd(sc_port)) { + if (!reset_kbd(sc_kbdc)) { /* KEYBOARD ERROR * Keyboard reset may fail either because the keyboard doen't exist, * or because the keyboard doesn't pass the self-test, or the keyboard @@ -347,14 +378,14 @@ scprobe(struct isa_device *dev) * test_controller() and test_kbd_port() appear to bring the keyboard * controller back (I don't know why and how, though.) */ - empty_both_buffers(sc_port, 10); - test_controller(sc_port); - test_kbd_port(sc_port); + empty_both_buffers(sc_kbdc, 10); + test_controller(sc_kbdc); + test_kbd_port(sc_kbdc); /* We could disable the keyboard port and interrupt... but, * the keyboard may still exist (see above). */ - if (bootverbose) - printf("sc%d: failed to reset the keyboard.\n", dev->id_unit); + if (bootverbose) + printf("sc%d: failed to reset the keyboard.\n", dev->id_unit); goto fail; } @@ -363,9 +394,9 @@ scprobe(struct isa_device *dev) * such as those on the IBM ThinkPad laptop computers can be used * with the standard console driver. */ - if (dev->id_flags & XT_KEYBD) { + if (codeset == 1) { if (send_kbd_command_and_data( - sc_port, KBDC_SET_SCAN_CODESET, 1) == KBD_ACK) { + sc_kbdc, KBDC_SET_SCANCODE_SET, codeset) == KBD_ACK) { /* XT kbd doesn't need scan code translation */ c &= ~KBD_TRANSLATION; } else { @@ -378,8 +409,10 @@ scprobe(struct isa_device *dev) } } /* enable the keyboard port and intr. */ - if (!set_controller_command_byte(sc_port, c & ~KBD_KBD_CONTROL_BITS, - KBD_ENABLE_KBD_PORT | KBD_ENABLE_KBD_INT)) { + if (!set_controller_command_byte(sc_kbdc, + KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS | KBD_OVERRIDE_KBD_LOCK, + (c & (KBD_AUX_CONTROL_BITS | KBD_OVERRIDE_KBD_LOCK)) + | KBD_ENABLE_KBD_PORT | KBD_ENABLE_KBD_INT)) { /* CONTROLLER ERROR * This is serious; we are left with the disabled keyboard intr. */ @@ -389,12 +422,17 @@ scprobe(struct isa_device *dev) } succeed: + kbdc_set_device_mask(sc_kbdc, m | KBD_KBD_CONTROL_BITS), + kbdc_lock(sc_kbdc, FALSE); return (IO_KBDSIZE); fail: if (c != -1) - /* try to restore the command byte as before, if possible */ - set_controller_command_byte(sc_port, c, 0); + /* try to restore the command byte as before, if possible */ + set_controller_command_byte(sc_kbdc, 0xff, c); + kbdc_set_device_mask(sc_kbdc, + (dev->id_flags & DETECT_KBD) ? m : m | KBD_KBD_CONTROL_BITS); + kbdc_lock(sc_kbdc, FALSE); return ((dev->id_flags & DETECT_KBD) ? 0 : IO_KBDSIZE); } @@ -423,14 +461,6 @@ scattach(struct isa_device *dev) if (crtc_vga) { cut_buffer = (char *)malloc(scp->xsize*scp->ysize, M_DEVBUF, M_NOWAIT); - font_8 = (char *)malloc(8*256, M_DEVBUF, M_NOWAIT); - font_14 = (char *)malloc(14*256, M_DEVBUF, M_NOWAIT); - font_16 = (char *)malloc(16*256, M_DEVBUF, M_NOWAIT); - copy_font(SAVE, FONT_16, font_16); - fonts_loaded = FONT_16; - scp->font_size = FONT_16; - palette = (char *)malloc(3*256, M_DEVBUF, M_NOWAIT); - save_palette(); } scp->scr_buf = (u_short *)malloc(scp->xsize*scp->ysize*sizeof(u_short), @@ -1106,7 +1136,7 @@ scioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) copy_font(LOAD, FONT_16, font_16); if (flags & CHAR_CURSOR) set_destructive_cursor(scp); - load_palette(); + load_palette(palette); } /* FALL THROUGH */ @@ -1155,9 +1185,8 @@ scioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) case KDSETRAD: /* set keyboard repeat & delay rates */ if (*data & 0x80) return EINVAL; - i = spltty(); - send_kbd_command_and_data(sc_port, KBDC_SET_TYPEMATIC, *data); - splx(i); + if (sc_kbdc != NULL) + set_keyboard(KBDC_SET_TYPEMATIC, *data); return 0; case KDSKBMODE: /* set keyboard mode */ @@ -1405,6 +1434,8 @@ sccnprobe(struct consdev *cp) /* initialize required fields */ cp->cn_dev = makedev(CDEV_MAJOR, SC_CONSOLE); cp->cn_pri = CN_INTERNAL; + + sc_kbdc = kbdc_open(sc_port); } void @@ -1499,8 +1530,21 @@ scrn_timer() * This ugly hack calls scintr if input is ready for the keyboard * and conveniently hides the problem. XXX */ - if ((inb(sc_port+KBD_STATUS_PORT)&KBDS_BUFFER_FULL) == KBDS_KBD_BUFFER_FULL) - scintr(0); + /* Try removing anything stuck in the keyboard controller; whether + * it's a keyboard scan code or mouse data. `scintr()' doesn't + * read the mouse data directly, but `kbdio' routines will, as a + * side effect. + */ + if (kbdc_lock(sc_kbdc, TRUE)) { + /* + * We have seen the lock flag is not set. Let's reset the flag early; + * otherwise `update_led()' failes which may want the lock + * during `scintr()'. + */ + kbdc_lock(sc_kbdc, FALSE); + if (kbdc_data_ready(sc_kbdc)) + scintr(0); + } /* should we just return ? */ if ((scp->status&UNKNOWN_MODE) || blink_in_progress || switch_in_progress) { @@ -1659,7 +1703,7 @@ exchange_scr(void) if ((old_scp->status & UNKNOWN_MODE) && crtc_vga) { if (flags & CHAR_CURSOR) set_destructive_cursor(new_scp); - load_palette(); + load_palette(palette); } if (old_scp->status & KBD_RAW_MODE || new_scp->status & KBD_RAW_MODE) shfts = ctls = alts = agrs = metas = 0; @@ -2354,9 +2398,8 @@ scinit(void) u_long segoff; crtc_vga = TRUE; - /* - * Get the BIOS video mode pointer. - */ + + /* Get the BIOS video mode pointer */ segoff = *(u_long *)pa_to_va(0x4a8); pa = (((segoff & 0xffff0000) >> 12) + (segoff & 0xffff)); if (ISMAPPED(pa, sizeof(u_long))) { @@ -2374,6 +2417,13 @@ scinit(void) bcopyw(Crtat, sc_buffer, console[0]->xsize * console[0]->ysize * sizeof(u_short)); + /* Save font and palette if VGA */ + if (crtc_vga) { + copy_font(SAVE, FONT_16, font_16); + fonts_loaded = FONT_16; + save_palette(); + } + console[0]->scr_buf = console[0]->mouse_pos = sc_buffer; console[0]->cursor_pos = console[0]->cursor_oldpos = sc_buffer + hw_cursor; console[0]->xpos = hw_cursor % COL; @@ -2387,6 +2437,7 @@ scinit(void) kernel_console.cur_color = kernel_console.std_color = kernel_default.std_color; kernel_console.rev_color = kernel_default.rev_color; + /* initialize mapscrn arrays to a one to one map */ for (i=0; imode = M_VGA_M80x25; else - scp->mode = M_VGA_C80x25; + scp->mode = M_VGA_C80x25; else if (crtc_addr == MONO_BASE) scp->mode = M_B80x25; @@ -2542,12 +2593,12 @@ scgetc(u_int flags) next_code: /* first see if there is something in the keyboard port */ if (flags & SCGETC_NONBLOCK) { - c = read_kbd_data_no_wait(sc_port); + c = read_kbd_data_no_wait(sc_kbdc); if (c == -1) return(NOKEY); } else { do { - c = read_kbd_data(sc_port); + c = read_kbd_data(sc_kbdc); } while(c == -1); } scancode = (u_char)c; @@ -3001,9 +3052,54 @@ mask2attr(struct term_stat *term) } static void -update_leds(int which) +set_keyboard(int command, int data) { int s; + int c; + + if (sc_kbdc == NULL) + return; + + /* prevent the timeout routine from polling the keyboard */ + if (!kbdc_lock(sc_kbdc, TRUE)) + return; + + /* disable the keyboard and mouse interrupt */ + s = spltty(); + c = get_controller_command_byte(sc_kbdc); + if ((c == -1) + || !set_controller_command_byte(sc_kbdc, + kbdc_get_device_mask(sc_kbdc), + KBD_ENABLE_KBD_PORT | KBD_DISABLE_KBD_INT + | KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { + /* CONTROLLER ERROR */ + kbdc_lock(sc_kbdc, FALSE); + splx(s); + return; + } + /* + * 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); + + send_kbd_command_and_data(sc_kbdc, command, data); + + /* restore the interrupts */ + if (!set_controller_command_byte(sc_kbdc, + kbdc_get_device_mask(sc_kbdc), + c & (KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS))) { + /* CONTROLLER ERROR */ + } + kbdc_lock(sc_kbdc, FALSE); +} + +static void +update_leds(int which) +{ static u_char xlate_leds[8] = { 0, 4, 2, 6, 1, 5, 3, 7 }; /* replace CAPS led with ALTGR led for ALTGR keyboards */ @@ -3014,10 +3110,7 @@ update_leds(int which) which &= ~CLKED; } - s = spltty(); - send_kbd_command_and_data(sc_port, KBDC_SET_LEDS, - xlate_leds[which & LED_MASK]); - splx(s); + set_keyboard(KBDC_SET_LEDS, xlate_leds[which & LED_MASK]); } void @@ -3595,7 +3688,7 @@ save_palette(void) } void -load_palette(void) +load_palette(char *palette) { int i; @@ -3658,6 +3751,7 @@ toggle_splash_screen(scr_stat *scp) scp->mode = save_mode; scp->status &= ~UNKNOWN_MODE; set_mode(scp); + load_palette(palette); toggle = 0; } else { diff --git a/sys/i386/isa/syscons.h b/sys/i386/isa/syscons.h index a9d5a04e6f01..9af7e26c5860 100644 --- a/sys/i386/isa/syscons.h +++ b/sys/i386/isa/syscons.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1995-1996 Søren Schmidt + * Copyright (c) 1995-1997 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -192,6 +192,6 @@ typedef struct default_attr { void set_border(u_char color); void set_mode(scr_stat *scp); void copy_font(int operation, int font_type, char* font_image); -void load_palette(void); +void load_palette(char *palette); #endif /* !_I386_ISA_SYSCONS_H_ */ diff --git a/sys/isa/kbdio.c b/sys/isa/kbdio.c index 47eefc45f282..7f8633e292aa 100644 --- a/sys/isa/kbdio.c +++ b/sys/isa/kbdio.c @@ -29,6 +29,10 @@ * $FreeBSD$ */ +#include "sc.h" +#include "psm.h" +#include "opt_kbdio.h" + #include #include #include @@ -41,31 +45,254 @@ #include #include +/* + * driver specific options: the following options may be set by + * `options' statements in the kernel configuration file. + */ + +/* retry count */ +#ifndef KBD_MAXRETRY +#define KBD_MAXRETRY 3 +#endif + +/* timing parameters */ +#ifndef KBD_RESETDELAY +#define KBD_RESETDELAY 200 /* wait 200msec after kbd/mouse reset */ +#endif +#ifndef KBD_MAXWAIT +#define KBD_MAXWAIT 5 /* wait 5 times at most after reset */ +#endif + +/* I/O recovery time */ +#ifdef PC98 +#define KBDC_DELAYTIME 37 +#define KBDD_DELAYTIME 37 +#else +#define KBDC_DELAYTIME 20 +#define KBDD_DELAYTIME 7 +#endif + +/* debug option */ #ifndef KBDIO_DEBUG #define KBDIO_DEBUG 0 #endif +/* end of driver specific options */ + +/* constants */ + +#define NKBDC max(NSC, NPSM) +#define KBDQ_BUFSIZE 32 + +/* macros */ + +#ifndef max +#define max(x,y) ((x) > (y) ? (x) : (y)) +#endif +#ifndef min +#define min(x,y) ((x) < (y) ? (x) : (y)) +#endif + +#define kbdcp(p) ((struct kbdc_softc *)(p)) +#define nextq(i) (((i) + 1) % KBDQ_BUFSIZE) +#define availq(q) ((q)->head != (q)->tail) +#if KBDIO_DEBUG >= 2 +#define emptyq(q) ((q)->tail = (q)->head = (q)->qcount = 0) +#else +#define emptyq(q) ((q)->tail = (q)->head = 0) +#endif + +/* local variables */ + +typedef struct _kqueue { + int head; + int tail; + unsigned char q[KBDQ_BUFSIZE]; +#if KBDIO_DEBUG >= 2 + int call_count; + int qcount; + int max_qcount; +#endif +} kqueue; + +struct kbdc_softc { + int port; /* base port address */ + int command_byte; /* current command byte value */ + int command_mask; /* command byte mask bits for kbd/aux devices */ + int lock; /* FIXME: XXX not quite a semaphore... */ + kqueue kbd; /* keyboard data queue */ + kqueue aux; /* auxiliary data queue */ +}; + +static struct kbdc_softc kbdc_softc[NKBDC] = { { 0 }, }; + static int verbose = KBDIO_DEBUG; +/* function prototypes */ + +static int addq(kqueue *q, int c); +static int removeq(kqueue *q); +static int wait_while_controller_busy(struct kbdc_softc *kbdc); +static int wait_for_data(struct kbdc_softc *kbdc); +static int wait_for_kbd_data(struct kbdc_softc *kbdc); +static int wait_for_kbd_ack(struct kbdc_softc *kbdc); +static int wait_for_aux_data(struct kbdc_softc *kbdc); +static int wait_for_aux_ack(struct kbdc_softc *kbdc); + +/* associate a port number with a KBDC */ + +KBDC +kbdc_open(int port) +{ + int s; + int i; + + s = spltty(); + for (i = 0; i < NKBDC; ++i) { + if (kbdc_softc[i].port == port) { + splx(s); + return (KBDC) &kbdc_softc[i]; + } + if (kbdc_softc[i].port <= 0) { + kbdc_softc[i].port = port; + kbdc_softc[i].command_byte = -1; + kbdc_softc[i].command_mask = 0; + kbdc_softc[i].lock = FALSE; + kbdc_softc[i].kbd.head = kbdc_softc[i].kbd.tail = 0; + kbdc_softc[i].aux.head = kbdc_softc[i].aux.tail = 0; +#if KBDIO_DEBUG >= 2 + kbdc_softc[i].kbd.call_count = 0; + kbdc_softc[i].kbd.qcount = kbdc_softc[i].kbd.max_qcount = 0; + kbdc_softc[i].aux.call_count = 0; + kbdc_softc[i].aux.qcount = kbdc_softc[i].aux.max_qcount = 0; +#endif + splx(s); + return (KBDC) &kbdc_softc[i]; + } + } + splx(s); + return NULL; +} + +/* + * I/O access arbitration in `kbdio' + * + * The `kbdio' module uses a simplistic convention to arbitrate + * I/O access to the controller/keyboard/mouse. The convention requires + * close cooperation of the calling device driver. + * + * The device driver which utilizes the `kbdio' module are assumed to + * have the following set of routines. + * a. An interrupt handler (the bottom half of the driver). + * b. Timeout routines which may briefly polls the keyboard controller. + * c. Routines outside interrupt context (the top half of the driver). + * They should follow the rules below: + * 1. The interrupt handler may assume that it always has full access + * to the controller/keyboard/mouse. + * 2. The other routines must issue `spltty()' if they wish to + * prevent the interrupt handler from accessing + * the controller/keyboard/mouse. + * 3. The timeout routines and the top half routines of the device driver + * arbitrate I/O access by observing the lock flag in `kbdio'. + * The flag is manipulated via `kbdc_lock()'; when one wants to + * perform I/O, call `kbdc_lock(kbdc, TRUE)' and proceed only if + * the call returns with TRUE. Otherwise the caller must back off. + * Call `kbdc_lock(kbdc, FALSE)' when necessary I/O operaion + * is finished. This mechanism does not prevent the interrupt + * handler from being invoked at any time and carrying out I/O. + * Therefore, `spltty()' must be strategically placed in the device + * driver code. Also note that the timeout routine may interrupt + * `kbdc_lock()' called by the top half of the driver, but this + * interruption is OK so long as the timeout routine observes the + * the rule 4 below. + * 4. The interrupt and timeout routines should not extend I/O operation + * across more than one interrupt or timeout; they must complete + * necessary I/O operation within one invokation of the routine. + * This measns that if the timeout routine acquires the lock flag, + * it must reset the flag to FALSE before it returns. + */ + +/* set/reset polling lock */ +int +kbdc_lock(KBDC p, int lock) +{ + int prevlock; + + prevlock = kbdcp(p)->lock; + kbdcp(p)->lock = lock; + + return (prevlock != lock); +} + +/* check if any data is waiting to be processed */ +int +kbdc_data_ready(KBDC p) +{ + return (availq(&kbdcp(p)->kbd) || availq(&kbdcp(p)->aux) + || (inb(kbdcp(p)->port + KBD_STATUS_PORT) & KBDS_ANY_BUFFER_FULL)); +} + +/* queuing functions */ + +static int +addq(kqueue *q, int c) +{ + if (nextq(q->tail) != q->head) { + q->q[q->tail] = c; + q->tail = nextq(q->tail); +#if KBDIO_DEBUG >= 2 + ++q->call_count; + ++q->qcount; + if (q->qcount > q->max_qcount) + q->max_qcount = q->qcount; +#endif + return TRUE; + } + return FALSE; +} + +static int +removeq(kqueue *q) +{ + int c; + + if (q->tail != q->head) { + c = q->q[q->head]; + q->head = nextq(q->head); +#if KBDIO_DEBUG >= 2 + --q->qcount; +#endif + return c; + } + return -1; +} + /* * device I/O routines */ - - -int -wait_while_controller_busy(int port) +static int +wait_while_controller_busy(struct kbdc_softc *kbdc) { #ifdef PC98 - DELAY(KBDC_DELAYTIME); - return TRUE; + DELAY(KBDC_DELAYTIME); + return TRUE; #else /* CPU will stay inside the loop for 100msec at most */ int retry = 5000; + int port = kbdc->port; + int f; - while (inb(port + KBD_STATUS_PORT) & KBDS_INPUT_BUFFER_FULL) { + while ((f = inb(port + KBD_STATUS_PORT)) & KBDS_INPUT_BUFFER_FULL) { + if ((f & KBDS_BUFFER_FULL) == KBDS_KBD_BUFFER_FULL) { + DELAY(KBDD_DELAYTIME); + addq(&kbdc->kbd, inb(port + KBD_DATA_PORT)); + } else if ((f & KBDS_BUFFER_FULL) == KBDS_AUX_BUFFER_FULL) { + DELAY(KBDD_DELAYTIME); + addq(&kbdc->aux, inb(port + KBD_DATA_PORT)); + } DELAY(KBDC_DELAYTIME); if (--retry < 0) - return FALSE; + return FALSE; } return TRUE; #endif @@ -75,134 +302,257 @@ wait_while_controller_busy(int port) * wait for any data; whether it's from the controller, * the keyboard, or the aux device. */ -int -wait_for_data(int port) +static int +wait_for_data(struct kbdc_softc *kbdc) { /* CPU will stay inside the loop for 200msec at most */ int retry = 10000; + int port = kbdc->port; + int f; - while ((inb(port + KBD_STATUS_PORT) & KBDS_ANY_BUFFER_FULL) == 0) { + while ((f = inb(port + KBD_STATUS_PORT) & KBDS_ANY_BUFFER_FULL) == 0) { DELAY(KBDC_DELAYTIME); if (--retry < 0) - return FALSE; + return 0; } DELAY(KBDD_DELAYTIME); - return TRUE; + return f; } /* wait for data from the keyboard */ -int -wait_for_kbd_data(int port) +static int +wait_for_kbd_data(struct kbdc_softc *kbdc) { /* CPU will stay inside the loop for 200msec at most */ int retry = 10000; + int port = kbdc->port; + int f; - while ((inb(port + KBD_STATUS_PORT) & KBDS_BUFFER_FULL) - != KBDS_KBD_BUFFER_FULL) { + while ((f = inb(port + KBD_STATUS_PORT) & KBDS_BUFFER_FULL) + != KBDS_KBD_BUFFER_FULL) { + if (f == KBDS_AUX_BUFFER_FULL) { + DELAY(KBDD_DELAYTIME); + addq(&kbdc->aux, inb(port + KBD_DATA_PORT)); + } DELAY(KBDC_DELAYTIME); if (--retry < 0) - return FALSE; + return 0; } DELAY(KBDD_DELAYTIME); - return TRUE; + return f; +} + +/* + * wait for an ACK(FAh), RESEND(FEh), or RESET_FAIL(FCh) from the keyboard. + * queue anything else. + */ +static int +wait_for_kbd_ack(struct kbdc_softc *kbdc) +{ + /* CPU will stay inside the loop for 200msec at most */ + int retry = 10000; + int port = kbdc->port; + int f; + int b; + + while (retry-- > 0) { + if ((f = inb(port + KBD_STATUS_PORT)) & KBDS_ANY_BUFFER_FULL) { + DELAY(KBDD_DELAYTIME); + b = inb(port + KBD_DATA_PORT); + if ((f & KBDS_BUFFER_FULL) == KBDS_KBD_BUFFER_FULL) { + if ((b == KBD_ACK) || (b == KBD_RESEND) + || (b == KBD_RESET_FAIL)) + return b; + addq(&kbdc->kbd, b); + } else if ((f & KBDS_BUFFER_FULL) == KBDS_AUX_BUFFER_FULL) { + addq(&kbdc->aux, b); + } + } + DELAY(KBDC_DELAYTIME); + } + return -1; } /* wait for data from the aux device */ -int -wait_for_aux_data(int port) +static int +wait_for_aux_data(struct kbdc_softc *kbdc) { /* CPU will stay inside the loop for 200msec at most */ int retry = 10000; + int port = kbdc->port; + int f; - while ((inb(port + KBD_STATUS_PORT) & KBDS_BUFFER_FULL) - != KBDS_AUX_BUFFER_FULL) { + while ((f = inb(port + KBD_STATUS_PORT) & KBDS_BUFFER_FULL) + != KBDS_AUX_BUFFER_FULL) { + if (f == KBDS_KBD_BUFFER_FULL) { + DELAY(KBDD_DELAYTIME); + addq(&kbdc->kbd, inb(port + KBD_DATA_PORT)); + } DELAY(KBDC_DELAYTIME); if (--retry < 0) - return FALSE; + return 0; } DELAY(KBDD_DELAYTIME); + return f; +} + +/* + * wait for an ACK(FAh), RESEND(FEh), or RESET_FAIL(FCh) from the aux device. + * queue anything else. + */ +static int +wait_for_aux_ack(struct kbdc_softc *kbdc) +{ + /* CPU will stay inside the loop for 200msec at most */ + int retry = 10000; + int port = kbdc->port; + int f; + int b; + + while (retry-- > 0) { + if ((f = inb(port + KBD_STATUS_PORT)) & KBDS_ANY_BUFFER_FULL) { + DELAY(KBDD_DELAYTIME); + b = inb(port + KBD_DATA_PORT); + if ((f & KBDS_BUFFER_FULL) == KBDS_AUX_BUFFER_FULL) { + if ((b == PSM_ACK) || (b == PSM_RESEND) + || (b == PSM_RESET_FAIL)) + return b; + addq(&kbdc->aux, b); + } else if ((f & KBDS_BUFFER_FULL) == KBDS_KBD_BUFFER_FULL) { + addq(&kbdc->kbd, b); + } + } + DELAY(KBDC_DELAYTIME); + } + return -1; +} + +/* write a one byte command to the controller */ +int +write_controller_command(KBDC p, int c) +{ + if (!wait_while_controller_busy(kbdcp(p))) + return FALSE; + outb(kbdcp(p)->port + KBD_COMMAND_PORT, c); return TRUE; } +/* write a one byte data to the controller */ int -write_controller_command(int port, int c) +write_controller_data(KBDC p, int c) { - if (!wait_while_controller_busy(port)) + if (!wait_while_controller_busy(kbdcp(p))) return FALSE; - outb(port + KBD_COMMAND_PORT, c); + outb(kbdcp(p)->port + KBD_DATA_PORT, c); return TRUE; } +/* write a one byte keyboard command */ int -write_controller_data(int port, int c) +write_kbd_command(KBDC p, int c) { - if (!wait_while_controller_busy(port)) + if (!wait_while_controller_busy(kbdcp(p))) return FALSE; - outb(port + KBD_DATA_PORT, c); + outb(kbdcp(p)->port + KBD_DATA_PORT, c); return TRUE; } +/* write a one byte auxiliary device command */ int -write_kbd_command(int port, int c) +write_aux_command(KBDC p, int c) { - if (!wait_while_controller_busy(port)) + if (!write_controller_command(p, KBDC_WRITE_TO_AUX)) return FALSE; - outb(port + KBD_DATA_PORT, c); - return TRUE; + return write_controller_data(p, c); } +/* send a command to the keyboard and wait for ACK */ int -write_aux_command(int port, int c) -{ - if (!write_controller_command(port,KBDC_WRITE_TO_AUX)) - return FALSE; - return write_controller_data(port, c); -} - -int -send_kbd_command(int port, int c) +send_kbd_command(KBDC p, int c) { int retry = KBD_MAXRETRY; int res = -1; while (retry-- > 0) { - if (!write_kbd_command(port, c)) + if (!write_kbd_command(p, c)) continue; - res = read_controller_data(port); + res = wait_for_kbd_ack(kbdcp(p)); if (res == KBD_ACK) - break; + break; } return res; } +/* send a command to the auxiliary device and wait for ACK */ int -send_aux_command(int port, int c) +send_aux_command(KBDC p, int c) { int retry = KBD_MAXRETRY; int res = -1; while (retry-- > 0) { - if (!write_aux_command(port, c)) + if (!write_aux_command(p, c)) continue; - res = read_aux_data(port); + /* + * FIXME: XXX + * The aux device may have already sent one or two bytes of + * status data, when a command is received. It will immediately + * stop data transmission, thus, leaving an incomplete data + * packet in our buffer. We have to discard any unprocessed + * data in order to remove such packets. Well, we may remove + * unprocessed, but necessary data byte as well... + */ + emptyq(&kbdcp(p)->aux); + res = wait_for_aux_ack(kbdcp(p)); if (res == PSM_ACK) - break; + break; } return res; } +/* send a command and a data to the keyboard, wait for ACKs */ int -send_kbd_command_and_data(int port, int c, int d) +send_kbd_command_and_data(KBDC p, int c, int d) { int retry; int res = -1; for (retry = KBD_MAXRETRY; retry > 0; --retry) { - if (!write_kbd_command(port, c)) + if (!write_kbd_command(p, c)) continue; - res = read_controller_data(port); + res = wait_for_kbd_ack(kbdcp(p)); if (res == KBD_ACK) - break; + break; + else if (res != KBD_RESEND) + return res; + } + if (retry <= 0) + return res; + + for (retry = KBD_MAXRETRY, res = -1; retry > 0; --retry) { + if (!write_kbd_command(p, d)) + continue; + res = wait_for_kbd_ack(kbdcp(p)); + if (res != KBD_RESEND) + break; + } + return res; +} + +/* send a command and a data to the auxiliary device, wait for ACKs */ +int +send_aux_command_and_data(KBDC p, int c, int d) +{ + int retry; + int res = -1; + + for (retry = KBD_MAXRETRY; retry > 0; --retry) { + if (!write_aux_command(p, c)) + continue; + emptyq(&kbdcp(p)->aux); + res = wait_for_aux_ack(kbdcp(p)); + if (res == PSM_ACK) + break; else if (res != PSM_RESEND) return res; } @@ -210,39 +560,11 @@ send_kbd_command_and_data(int port, int c, int d) return res; for (retry = KBD_MAXRETRY, res = -1; retry > 0; --retry) { - if (!write_kbd_command(port, d)) + if (!write_aux_command(p, d)) continue; - res = read_controller_data(port); - if (res != KBD_RESEND) - break; - } - return res; -} - -int -send_aux_command_and_data(int port, int c, int d) -{ - int retry; - int res = -1; - - for (retry = KBD_MAXRETRY; retry > 0; --retry) { - if (!write_aux_command(port, c)) - continue; - res = read_aux_data(port); - if (res == PSM_ACK) - break; - else if (res != PSM_RESEND) - return res; - } - if (retry <= 0) - return res; - - for (retry = KBD_MAXRETRY, res = -1; retry > 0; --retry) { - if (!write_aux_command(port, d)) - continue; - res = read_aux_data(port); + res = wait_for_aux_ack(kbdcp(p)); if (res != PSM_RESEND) - break; + break; } return res; } @@ -252,107 +574,225 @@ send_aux_command_and_data(int port, int c, int d) * the keyboard, or the aux device */ int -read_controller_data(int port) +read_controller_data(KBDC p) { - if (!wait_for_data(port)) + if (availq(&kbdcp(p)->kbd)) + return removeq(&kbdcp(p)->kbd); + if (availq(&kbdcp(p)->aux)) + return removeq(&kbdcp(p)->aux); + if (!wait_for_data(kbdcp(p))) return -1; /* timeout */ - return inb(port + KBD_DATA_PORT); + return inb(kbdcp(p)->port + KBD_DATA_PORT); } +#if KBDIO_DEBUG >= 2 +static int call = 0; +#endif + /* read one byte from the keyboard */ int -read_kbd_data(int port) +read_kbd_data(KBDC p) { - if (!wait_for_kbd_data(port)) +#if KBDIO_DEBUG >= 2 + if (++call > 2000) { + call = 0; + log(LOG_DEBUG, "KBDIO: kbd q: %d calls, max %d chars, " + "aux q: %d calls, max %d chars\n", + kbdcp(p)->kbd.call_count, kbdcp(p)->kbd.max_qcount, + kbdcp(p)->aux.call_count, kbdcp(p)->aux.max_qcount); + } +#endif + + if (availq(&kbdcp(p)->kbd)) + return removeq(&kbdcp(p)->kbd); + if (!wait_for_kbd_data(kbdcp(p))) return -1; /* timeout */ #ifdef PC98 - DELAY(KBDC_DELAYTIME); + DELAY(KBDC_DELAYTIME); #endif - return inb(port + KBD_DATA_PORT); + return inb(kbdcp(p)->port + KBD_DATA_PORT); } /* read one byte from the keyboard, but return immediately if * no data is waiting */ int -read_kbd_data_no_wait(int port) +read_kbd_data_no_wait(KBDC p) { - if ((inb(port + KBD_STATUS_PORT) & KBDS_BUFFER_FULL) - != KBDS_KBD_BUFFER_FULL) - return -1; /* no data */ - DELAY(KBDD_DELAYTIME); - return inb(port + KBD_DATA_PORT); + int f; + +#if KBDIO_DEBUG >= 2 + if (++call > 2000) { + call = 0; + log(LOG_DEBUG, "KBDIO: kbd q: %d calls, max %d chars, " + "aux q: %d calls, max %d chars\n", + kbdcp(p)->kbd.call_count, kbdcp(p)->kbd.max_qcount, + kbdcp(p)->aux.call_count, kbdcp(p)->aux.max_qcount); + } +#endif + + if (availq(&kbdcp(p)->kbd)) + return removeq(&kbdcp(p)->kbd); + f = inb(kbdcp(p)->port + KBD_STATUS_PORT) & KBDS_BUFFER_FULL; + if (f == KBDS_AUX_BUFFER_FULL) { + DELAY(KBDD_DELAYTIME); + addq(&kbdcp(p)->aux, inb(kbdcp(p)->port + KBD_DATA_PORT)); + f = inb(kbdcp(p)->port + KBD_STATUS_PORT) & KBDS_BUFFER_FULL; + } + if (f == KBDS_KBD_BUFFER_FULL) { + DELAY(KBDD_DELAYTIME); + return inb(kbdcp(p)->port + KBD_DATA_PORT); + } + return -1; /* no data */ } /* read one byte from the aux device */ int -read_aux_data(int port) +read_aux_data(KBDC p) { - if (!wait_for_aux_data(port)) + if (availq(&kbdcp(p)->aux)) + return removeq(&kbdcp(p)->aux); + if (!wait_for_aux_data(kbdcp(p))) return -1; /* timeout */ - return inb(port + KBD_DATA_PORT); + return inb(kbdcp(p)->port + KBD_DATA_PORT); +} + +/* read one byte from the aux device, but return immediately if + * no data is waiting + */ +int +read_aux_data_no_wait(KBDC p) +{ + int f; + + if (availq(&kbdcp(p)->aux)) + return removeq(&kbdcp(p)->aux); + f = inb(kbdcp(p)->port + KBD_STATUS_PORT) & KBDS_BUFFER_FULL; + if (f == KBDS_KBD_BUFFER_FULL) { + DELAY(KBDD_DELAYTIME); + addq(&kbdcp(p)->kbd, inb(kbdcp(p)->port + KBD_DATA_PORT)); + f = inb(kbdcp(p)->port + KBD_STATUS_PORT) & KBDS_BUFFER_FULL; + } + if (f == KBDS_AUX_BUFFER_FULL) { + DELAY(KBDD_DELAYTIME); + return inb(kbdcp(p)->port + KBD_DATA_PORT); + } + return -1; /* no data */ } /* discard data from the keyboard */ void -empty_kbd_buffer(int port, int t) +empty_kbd_buffer(KBDC p, int wait) { + int t; int b; - int c = 0; + int f; +#if KBDIO_DEBUG >= 2 + int c1 = 0; + int c2 = 0; +#endif int delta = 2; - for (; t > 0; t -= delta) { - if ((inb(port + KBD_STATUS_PORT) & KBDS_BUFFER_FULL) - == KBDS_KBD_BUFFER_FULL) { + for (t = wait; t > 0; ) { + if ((f = inb(kbdcp(p)->port + KBD_STATUS_PORT)) & KBDS_ANY_BUFFER_FULL) { DELAY(KBDD_DELAYTIME); - b = inb(port + KBD_DATA_PORT); - ++c; - } + b = inb(kbdcp(p)->port + KBD_DATA_PORT); + if ((f & KBDS_BUFFER_FULL) == KBDS_AUX_BUFFER_FULL) { + addq(&kbdcp(p)->aux, b); +#if KBDIO_DEBUG >= 2 + ++c2; + } else { + ++c1; +#endif + } + t = wait; + } else { + t -= delta; + } DELAY(delta*1000); } - if ((verbose >= 2) && (c > 0)) - log(LOG_DEBUG,"kbdio: %d char read (empty_kbd_buffer)\n",c); +#if KBDIO_DEBUG >= 2 + if ((c1 > 0) || (c2 > 0)) + log(LOG_DEBUG, "kbdio: %d:%d char read (empty_kbd_buffer)\n", c1, c2); +#endif + + emptyq(&kbdcp(p)->kbd); } /* discard data from the aux device */ void -empty_aux_buffer(int port, int t) +empty_aux_buffer(KBDC p, int wait) { + int t; int b; - int c = 0; + int f; +#if KBDIO_DEBUG >= 2 + int c1 = 0; + int c2 = 0; +#endif int delta = 2; - for (; t > 0; t -= delta) { - if ((inb(port + KBD_STATUS_PORT) & KBDS_BUFFER_FULL) - == KBDS_AUX_BUFFER_FULL) { + for (t = wait; t > 0; ) { + if ((f = inb(kbdcp(p)->port + KBD_STATUS_PORT)) & KBDS_ANY_BUFFER_FULL) { DELAY(KBDD_DELAYTIME); - b = inb(port + KBD_DATA_PORT); - ++c; - } + b = inb(kbdcp(p)->port + KBD_DATA_PORT); + if ((f & KBDS_BUFFER_FULL) == KBDS_KBD_BUFFER_FULL) { + addq(&kbdcp(p)->kbd, b); +#if KBDIO_DEBUG >= 2 + ++c1; + } else { + ++c2; +#endif + } + t = wait; + } else { + t -= delta; + } DELAY(delta*1000); } - if ((verbose >= 2) && (c > 0)) - log(LOG_DEBUG,"kbdio: %d char read (empty_aux_buffer)\n",c); +#if KBDIO_DEBUG >= 2 + if ((c1 > 0) || (c2 > 0)) + log(LOG_DEBUG, "kbdio: %d:%d char read (empty_aux_buffer)\n", c1, c2); +#endif + + emptyq(&kbdcp(p)->aux); } /* discard any data from the keyboard or the aux device */ void -empty_both_buffers(int port, int t) +empty_both_buffers(KBDC p, int wait) { - int b; - int c = 0; + int t; + int f; +#if KBDIO_DEBUG >= 2 + int c1 = 0; + int c2 = 0; +#endif int delta = 2; - for (; t > 0; t -= delta) { - if (inb(port + KBD_STATUS_PORT) & KBDS_ANY_BUFFER_FULL) { + for (t = wait; t > 0; ) { + if ((f = inb(kbdcp(p)->port + KBD_STATUS_PORT)) & KBDS_ANY_BUFFER_FULL) { DELAY(KBDD_DELAYTIME); - b = inb(port + KBD_DATA_PORT); - ++c; - } + (void)inb(kbdcp(p)->port + KBD_DATA_PORT); +#if KBDIO_DEBUG >= 2 + if ((f & KBDS_BUFFER_FULL) == KBDS_KBD_BUFFER_FULL) + ++c1; + else + ++c2; +#endif + t = wait; + } else { + t -= delta; + } DELAY(delta*1000); } - if ((verbose >= 2) && (c > 0)) - log(LOG_DEBUG,"kbdio: %d char read (empty_both_buffers)\n",c); +#if KBDIO_DEBUG >= 2 + if ((c1 > 0) || (c2 > 0)) + log(LOG_DEBUG, "kbdio: %d:%d char read (empty_both_buffers)\n", c1, c2); +#endif + + emptyq(&kbdcp(p)->kbd); + emptyq(&kbdcp(p)->aux); } /* keyboard and mouse device control */ @@ -361,21 +801,22 @@ empty_both_buffers(int port, int t) * interrupt before calling "reset_kbd()". */ int -reset_kbd(int port) +reset_kbd(KBDC p) { int retry = KBD_MAXRETRY; int again = KBD_MAXWAIT; int c = KBD_RESEND; /* keep the compiler happy */ while (retry-- > 0) { - empty_both_buffers(port, 10); - if (!write_kbd_command(port, KBDC_RESET_KBD)) + empty_both_buffers(p, 10); + if (!write_kbd_command(p, KBDC_RESET_KBD)) continue; - c = read_controller_data(port); - if (verbose) - log(LOG_DEBUG,"kbdio: RESET_KBD return code:%04x\n",c); + emptyq(&kbdcp(p)->kbd); + c = read_controller_data(p); + if (verbose || bootverbose) + log(LOG_DEBUG, "kbdio: RESET_KBD return code:%04x\n", c); if (c == KBD_ACK) /* keyboard has agreed to reset itself... */ - break; + break; } if (retry < 0) return FALSE; @@ -383,12 +824,12 @@ reset_kbd(int port) while (again-- > 0) { /* wait awhile, well, in fact we must wait quite loooooooooooong */ DELAY(KBD_RESETDELAY*1000); - c = read_controller_data(port); /* RESET_DONE/RESET_FAIL */ + c = read_controller_data(p); /* RESET_DONE/RESET_FAIL */ if (c != -1) /* wait again if the controller is not ready */ - break; + break; } - if (verbose) - log(LOG_DEBUG,"kbdio: RESET_KBD status:%04x\n",c); + if (verbose || bootverbose) + log(LOG_DEBUG, "kbdio: RESET_KBD status:%04x\n", c); if (c != KBD_RESET_DONE) return FALSE; return TRUE; @@ -398,21 +839,22 @@ reset_kbd(int port) * before calling `reset_aux_dev()'. */ int -reset_aux_dev(int port) +reset_aux_dev(KBDC p) { int retry = KBD_MAXRETRY; int again = KBD_MAXWAIT; int c = PSM_RESEND; /* keep the compiler happy */ while (retry-- > 0) { - empty_both_buffers(port, 10); - if (!write_aux_command(port, PSMC_RESET_DEV)) + empty_both_buffers(p, 10); + if (!write_aux_command(p, PSMC_RESET_DEV)) continue; - c = read_controller_data(port); - if (verbose) - log(LOG_DEBUG,"kbdio: RESET_AUX return code:%04x\n",c); + emptyq(&kbdcp(p)->aux); + c = read_aux_data(p); + if (verbose || bootverbose) + log(LOG_DEBUG, "kbdio: RESET_AUX return code:%04x\n", c); if (c == PSM_ACK) /* aux dev is about to reset... */ - break; + break; } if (retry < 0) return FALSE; @@ -420,112 +862,153 @@ reset_aux_dev(int port) while (again-- > 0) { /* wait awhile, well, quite looooooooooooong */ DELAY(KBD_RESETDELAY*1000); - c = read_aux_data(port); /* RESET_DONE/RESET_FAIL */ + c = read_aux_data(p); /* RESET_DONE/RESET_FAIL */ if (c != -1) /* wait again if the controller is not ready */ - break; + break; } - if (verbose) - log(LOG_DEBUG,"kbdio: RESET_AUX status:%04x\n",c); + if (verbose || bootverbose) + log(LOG_DEBUG, "kbdio: RESET_AUX status:%04x\n", c); if (c != PSM_RESET_DONE) /* reset status */ return FALSE; - c = read_aux_data(port); /* device ID */ - if (verbose) - log(LOG_DEBUG,"kbdio: RESET_AUX ID:%04x\n",c); - /* NOTE: we could check the device ID now, but leave it later... */ + c = read_aux_data(p); /* device ID */ + if (verbose || bootverbose) + log(LOG_DEBUG, "kbdio: RESET_AUX ID:%04x\n", c); + /* NOTE: we could check the device ID now, but leave it later... */ return TRUE; } /* controller diagnostics and setup */ int -test_controller(int port) +test_controller(KBDC p) { int retry = KBD_MAXRETRY; int again = KBD_MAXWAIT; int c = KBD_DIAG_FAIL; while (retry-- > 0) { - empty_both_buffers(port, 10); - if (write_controller_command(port, KBDC_DIAGNOSE)) + empty_both_buffers(p, 10); + if (write_controller_command(p, KBDC_DIAGNOSE)) break; } if (retry < 0) return FALSE; + emptyq(&kbdcp(p)->kbd); while (again-- > 0) { /* wait awhile */ DELAY(KBD_RESETDELAY*1000); - c = read_controller_data(port); /* DIAG_DONE/DIAG_FAIL */ + c = read_controller_data(p); /* DIAG_DONE/DIAG_FAIL */ if (c != -1) /* wait again if the controller is not ready */ break; } - if (verbose) - log(LOG_DEBUG,"kbdio: DIAGNOSE status:%04x\n",c); + if (verbose || bootverbose) + log(LOG_DEBUG, "kbdio: DIAGNOSE status:%04x\n", c); return (c == KBD_DIAG_DONE); } int -test_kbd_port(int port) +test_kbd_port(KBDC p) { int retry = KBD_MAXRETRY; int again = KBD_MAXWAIT; int c = -1; while (retry-- > 0) { - empty_both_buffers(port, 10); - if (write_controller_command(port, KBDC_TEST_KBD_PORT)) + empty_both_buffers(p, 10); + if (write_controller_command(p, KBDC_TEST_KBD_PORT)) break; } if (retry < 0) return FALSE; + emptyq(&kbdcp(p)->kbd); while (again-- > 0) { - c = read_controller_data(port); + c = read_controller_data(p); if (c != -1) /* try again if the controller is not ready */ break; } - if (verbose) - log(LOG_DEBUG,"kbdio: TEST_KBD_PORT status:%04x\n",c); + if (verbose || bootverbose) + log(LOG_DEBUG, "kbdio: TEST_KBD_PORT status:%04x\n", c); return c; } int -test_aux_port(int port) +test_aux_port(KBDC p) { int retry = KBD_MAXRETRY; int again = KBD_MAXWAIT; int c = -1; while (retry-- > 0) { - empty_both_buffers(port, 10); - if (write_controller_command(port, KBDC_TEST_AUX_PORT)) + empty_both_buffers(p, 10); + if (write_controller_command(p, KBDC_TEST_AUX_PORT)) break; } if (retry < 0) return FALSE; + emptyq(&kbdcp(p)->kbd); while (again-- > 0) { - c = read_controller_data(port); + c = read_controller_data(p); if (c != -1) /* try again if the controller is not ready */ break; } - if (verbose) - log(LOG_DEBUG,"kbdio: TEST_AUX_PORT status:%04x\n",c); + if (verbose || bootverbose) + log(LOG_DEBUG, "kbdio: TEST_AUX_PORT status:%04x\n", c); return c; } int -set_controller_command_byte(int port, int command, int flag) +kbdc_get_device_mask(KBDC p) { - if ((command | flag) & KBD_DISABLE_KBD_PORT) { - if (!write_controller_command(port, KBDC_DISABLE_KBD_PORT)) + return kbdcp(p)->command_mask; +} + +void +kbdc_set_device_mask(KBDC p, int mask) +{ + kbdcp(p)->command_mask = + mask & (KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS); +} + +int +get_controller_command_byte(KBDC p) +{ + if (kbdcp(p)->command_byte != -1) + return kbdcp(p)->command_byte; + if (!write_controller_command(p, KBDC_GET_COMMAND_BYTE)) + return -1; + emptyq(&kbdcp(p)->kbd); + kbdcp(p)->command_byte = read_controller_data(p); + return kbdcp(p)->command_byte; +} + +int +set_controller_command_byte(KBDC p, int mask, int command) +{ + if (get_controller_command_byte(p) == -1) + return FALSE; + + command = (kbdcp(p)->command_byte & ~mask) | (command & mask); +#if 0 + if (command == kbdcp(p)->command_byte) + return TRUE; +#endif + if (command & KBD_DISABLE_KBD_PORT) { + if (!write_controller_command(p, KBDC_DISABLE_KBD_PORT)) return FALSE; } - if (!write_controller_command(port, KBDC_SET_COMMAND_BYTE)) + if (!write_controller_command(p, KBDC_SET_COMMAND_BYTE)) return FALSE; - if (!write_controller_data(port, command | flag)) + if (!write_controller_data(p, command)) return FALSE; - wait_while_controller_busy(port); + kbdcp(p)->command_byte = command; + + if (verbose || bootverbose) + log(LOG_DEBUG, "kbdio: new command byte:%04x (set_controller...)\n", + command); + return TRUE; } diff --git a/sys/isa/kbdio.h b/sys/isa/kbdio.h index 546e21b13494..37034439573a 100644 --- a/sys/isa/kbdio.h +++ b/sys/isa/kbdio.h @@ -39,15 +39,18 @@ #define KBD_STATUS_PORT 2 /* status port, read */ #define KBD_COMMAND_PORT 2 /* controller command port, write */ #define KBD_DATA_PORT 0 /* data port, read/write - also used as keyboard command - and mouse command port */ + * also used as keyboard command + * and mouse command port + */ #else #define KBD_STATUS_PORT 4 /* status port, read */ #define KBD_COMMAND_PORT 4 /* controller command port, write */ #define KBD_DATA_PORT 0 /* data port, read/write - also used as keyboard command - and mouse command port */ + * also used as keyboard command + * and mouse command port + */ #endif /* PC98 */ + /* FIXME: `IO_PSMSIZE' should really be in `isa.h'. */ #define IO_PSMSIZE (KBD_COMMAND_PORT - KBD_DATA_PORT + 1) /* 5 */ @@ -86,13 +89,14 @@ #define KBDC_SEND_DEV_ID 0x00f2 #define KBDC_SET_LEDS 0x00ed #define KBDC_ECHO 0x00ee -#define KBDC_SET_SCAN_CODESET 0x00f0 +#define KBDC_SET_SCANCODE_SET 0x00f0 #define KBDC_SET_TYPEMATIC 0x00f3 /* aux device commands (sent to KBD_DATA_PORT) */ #define PSMC_RESET_DEV 0x00ff #define PSMC_ENABLE_DEV 0x00f4 #define PSMC_DISABLE_DEV 0x00f5 +#define PSMC_SET_DEFAULTS 0x00f6 #define PSMC_SEND_DEV_ID 0x00f2 #define PSMC_SEND_DEV_STATUS 0x00e9 #define PSMC_SEND_DEV_DATA 0x00eb @@ -104,15 +108,11 @@ #define PSMC_SET_SAMPLING_RATE 0x00f3 /* PSMC_SET_RESOLUTION argument */ -#define PSMD_RESOLUTION_25 0 /* 25ppi */ -#define PSMD_RESOLUTION_50 1 /* 50ppi */ -#define PSMD_RESOLUTION_100 2 /* 100ppi (default after reset) */ -#define PSMD_RESOLUTION_200 3 /* 200ppi */ -/* FIXME: I don't know if it's possible to go beyond 200ppi. - The values below are of my wild guess. */ -#define PSMD_RESOLUTION_400 4 /* 400ppi */ -#define PSMD_RESOLUTION_800 5 /* 800ppi */ -#define PSMD_MAX_RESOLUTION PSMD_RESOLUTION_800 +#define PSMD_RES_LOW 0 /* typically 25ppi */ +#define PSMD_RES_MEDIUM_LOW 1 /* typically 50ppi */ +#define PSMD_RES_MEDIUM_HIGH 2 /* typically 100ppi (default) */ +#define PSMD_RES_HIGH 3 /* typically 200ppi */ +#define PSMD_MAX_RESOLUTION PSMD_RES_HIGH /* PSMC_SET_SAMPLING_RATE */ #define PSMD_MAX_RATE 255 /* FIXME: not sure if it's possible */ @@ -151,79 +151,57 @@ #ifdef KERNEL -/* driver specific options: the following options may be set by - `options' statements in the kernel configuration file. */ - -/* retry count */ -#ifndef KBD_MAXRETRY -#define KBD_MAXRETRY 3 -#endif - -/* timing parameters */ -#ifndef KBD_RESETDELAY -#define KBD_RESETDELAY 200 /* wait 200msec after kbd/mouse reset */ -#endif -#ifndef KBD_MAXWAIT -#define KBD_MAXWAIT 5 /* wait 5 times at most after reset */ -#endif - -/* I/O recovery time */ -#ifdef PC98 -#define KBDC_DELAYTIME 37 -#define KBDD_DELAYTIME 37 -#else -#define KBDC_DELAYTIME 20 -#define KBDD_DELAYTIME 7 -#endif - -/* debugging */ -/* #define KBDIO_DEBUG produces debugging output */ - -/* end of driver specific options */ - -/* misc */ #ifndef TRUE -#define TRUE (-1) +#define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif +/* types/structures */ + +typedef caddr_t KBDC; + /* function prototypes */ -int wait_while_controller_busy __P((int port)); +KBDC kbdc_open __P((int port)); -int wait_for_data __P((int port)); -int wait_for_kbd_data __P((int port)); -int wait_for_aux_data __P((int port)); +int kbdc_lock __P((KBDC kbdc, int lock)); -int write_controller_command __P((int port,int c)); -int write_controller_data __P((int port,int c)); +int kbdc_data_ready __P((KBDC kbdc)); -int write_kbd_command __P((int port,int c)); -int write_aux_command __P((int port,int c)); -int send_kbd_command __P((int port,int c)); -int send_aux_command __P((int port,int c)); -int send_kbd_command_and_data __P((int port,int c,int d)); -int send_aux_command_and_data __P((int port,int c,int d)); +int write_controller_command __P((KBDC kbdc,int c)); +int write_controller_data __P((KBDC kbdc,int c)); -int read_controller_data __P((int port)); -int read_kbd_data __P((int port)); -int read_kbd_data_no_wait __P((int port)); -int read_aux_data __P((int port)); +int write_kbd_command __P((KBDC kbdc,int c)); +int write_aux_command __P((KBDC kbdc,int c)); +int send_kbd_command __P((KBDC kbdc,int c)); +int send_aux_command __P((KBDC kbdc,int c)); +int send_kbd_command_and_data __P((KBDC kbdc,int c,int d)); +int send_aux_command_and_data __P((KBDC kbdc,int c,int d)); -void empty_kbd_buffer __P((int port, int t)); -void empty_aux_buffer __P((int port, int t)); -void empty_both_buffers __P((int port, int t)); +int read_controller_data __P((KBDC kbdc)); +int read_kbd_data __P((KBDC kbdc)); +int read_kbd_data_no_wait __P((KBDC kbdc)); +int read_aux_data __P((KBDC kbdc)); +int read_aux_data_no_wait __P((KBDC kbdc)); -int reset_kbd __P((int port)); -int reset_aux_dev __P((int port)); +void empty_kbd_buffer __P((KBDC kbdc, int t)); +void empty_aux_buffer __P((KBDC kbdc, int t)); +void empty_both_buffers __P((KBDC kbdc, int t)); -int test_controller __P((int port)); -int test_kbd_port __P((int port)); -int test_aux_port __P((int port)); +int reset_kbd __P((KBDC kbdc)); +int reset_aux_dev __P((KBDC kbdc)); -int set_controller_command_byte __P((int port,int command,int flag)); +int test_controller __P((KBDC kbdc)); +int test_kbd_port __P((KBDC kbdc)); +int test_aux_port __P((KBDC kbdc)); + +int kbdc_get_device_mask __P((KBDC kbdc)); +void kbdc_set_device_mask __P((KBDC kbdc, int mask)); + +int get_controller_command_byte __P((KBDC kbdc)); +int set_controller_command_byte __P((KBDC kbdc, int command, int flag)); #endif /* KERNEL */ diff --git a/sys/isa/syscons.c b/sys/isa/syscons.c index 853efd6f16e2..68b5f0132727 100644 --- a/sys/isa/syscons.c +++ b/sys/isa/syscons.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1992-1996 Søren Schmidt + * Copyright (c) 1992-1997 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -103,6 +103,7 @@ static term_stat kernel_console; static default_attr *current_default; static int flags = 0; static int sc_port = IO_KBD; +static KBDC sc_kbdc = NULL; static char init_done = COLD; static u_short sc_buffer[ROW*COL]; static char switch_in_progress = FALSE; @@ -113,9 +114,6 @@ static int blinkrate = 0; char crtc_vga = FALSE; static u_char shfts = 0, ctls = 0, alts = 0, agrs = 0, metas = 0; static u_char nlkcnt = 0, clkcnt = 0, slkcnt = 0, alkcnt = 0; - char *font_8 = NULL, *font_14 = NULL, *font_16 = NULL; - int fonts_loaded = 0; - char *palette; static const u_int n_fkey_tab = sizeof(fkey_tab) / sizeof(*fkey_tab); static int delayed_next_scr = FALSE; static long scrn_blank_time = 0; /* screen saver timeout value */ @@ -124,6 +122,11 @@ static long scrn_time_stamp; u_char scr_map[256]; u_char scr_rmap[256]; char *video_mode_ptr = NULL; + int fonts_loaded = 0; + char font_8[256*8]; + char font_14[256*14]; + char font_16[256*16]; + char palette[256*3]; static char *cut_buffer; static u_short mouse_and_mask[16] = { 0xc000, 0xe000, 0xf000, 0xf800, @@ -194,6 +197,7 @@ static void history_to_screen(scr_stat *scp); static int history_up_line(scr_stat *scp); static int history_down_line(scr_stat *scp); static int mask2attr(struct term_stat *term); +static void set_keyboard(int command, int data); static void update_leds(int which); static void set_vgaregs(char *modetable); static void set_font_mode(void); @@ -294,28 +298,34 @@ move_crsr(scr_stat *scp, int x, int y) static int scprobe(struct isa_device *dev) { - int c; + int codeset; + int c = -1; + int m; sc_port = dev->id_iobase; + sc_kbdc = kbdc_open(sc_port); + + if (!kbdc_lock(sc_kbdc, TRUE)) { + /* driver error? */ + printf("sc%d: unable to lock the controller.\n", dev->id_unit); + return ((dev->id_flags & DETECT_KBD) ? 0 : IO_KBDSIZE); + } /* discard anything left after UserConfig */ - empty_both_buffers(sc_port, 10); + empty_both_buffers(sc_kbdc, 10); /* save the current keyboard controller command byte */ - c = -1; - if (!write_controller_command(sc_port, KBDC_GET_COMMAND_BYTE)) { - /* CONTROLLER ERROR */ - printf("sc%d: unable to get the current command byte value.\n", - dev->id_unit); - goto fail; - } - c = read_controller_data(sc_port); + m = kbdc_get_device_mask(sc_kbdc) & ~KBD_KBD_CONTROL_BITS; + c = get_controller_command_byte(sc_kbdc); if (c == -1) { /* CONTROLLER ERROR */ printf("sc%d: unable to get the current command byte value.\n", dev->id_unit); goto fail; } + if (bootverbose) + printf("sc%d: the current keyboard controller command byte %04x\n", + dev->id_unit, c); #if 0 /* override the keyboard lock switch */ c |= KBD_OVERRIDE_KBD_LOCK; @@ -325,19 +335,40 @@ scprobe(struct isa_device *dev) * enable the keyboard port, but disable the keyboard intr. * the aux port (mouse port) is disabled too. */ - if (!set_controller_command_byte(sc_port, - c & ~(KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS), + if (!set_controller_command_byte(sc_kbdc, + KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS, KBD_ENABLE_KBD_PORT | KBD_DISABLE_KBD_INT - | KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { + | KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { /* CONTROLLER ERROR * there is very little we can do... */ printf("sc%d: unable to set the command byte.\n", dev->id_unit); goto fail; } + + /* + * Check if we have an XT keyboard before we attempt to reset it. + * The procedure assumes that the keyboard and the controller have + * been set up properly by BIOS and have not been messed up + * during the boot process. + */ + codeset = -1; + if (dev->id_flags & XT_KEYBD) + /* the user says there is a XT keyboard */ + codeset = 1; +#ifdef DETECT_XT_KEYBOARD + else if ((c & KBD_TRANSLATION) == 0) { + /* SET_SCANCODE_SET is not always supported; ignore error */ + if (send_kbd_command_and_data(sc_kbdc, KBDC_SET_SCANCODE_SET, 0) + == KBD_ACK) + codeset = read_kbd_data(sc_kbdc); + } + if (bootverbose) + printf("sc%d: keyboard scancode set %d\n", dev->id_unit, codeset); +#endif /* DETECT_XT_KEYBOARD */ /* reset keyboard hardware */ - if (!reset_kbd(sc_port)) { + if (!reset_kbd(sc_kbdc)) { /* KEYBOARD ERROR * Keyboard reset may fail either because the keyboard doen't exist, * or because the keyboard doesn't pass the self-test, or the keyboard @@ -347,14 +378,14 @@ scprobe(struct isa_device *dev) * test_controller() and test_kbd_port() appear to bring the keyboard * controller back (I don't know why and how, though.) */ - empty_both_buffers(sc_port, 10); - test_controller(sc_port); - test_kbd_port(sc_port); + empty_both_buffers(sc_kbdc, 10); + test_controller(sc_kbdc); + test_kbd_port(sc_kbdc); /* We could disable the keyboard port and interrupt... but, * the keyboard may still exist (see above). */ - if (bootverbose) - printf("sc%d: failed to reset the keyboard.\n", dev->id_unit); + if (bootverbose) + printf("sc%d: failed to reset the keyboard.\n", dev->id_unit); goto fail; } @@ -363,9 +394,9 @@ scprobe(struct isa_device *dev) * such as those on the IBM ThinkPad laptop computers can be used * with the standard console driver. */ - if (dev->id_flags & XT_KEYBD) { + if (codeset == 1) { if (send_kbd_command_and_data( - sc_port, KBDC_SET_SCAN_CODESET, 1) == KBD_ACK) { + sc_kbdc, KBDC_SET_SCANCODE_SET, codeset) == KBD_ACK) { /* XT kbd doesn't need scan code translation */ c &= ~KBD_TRANSLATION; } else { @@ -378,8 +409,10 @@ scprobe(struct isa_device *dev) } } /* enable the keyboard port and intr. */ - if (!set_controller_command_byte(sc_port, c & ~KBD_KBD_CONTROL_BITS, - KBD_ENABLE_KBD_PORT | KBD_ENABLE_KBD_INT)) { + if (!set_controller_command_byte(sc_kbdc, + KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS | KBD_OVERRIDE_KBD_LOCK, + (c & (KBD_AUX_CONTROL_BITS | KBD_OVERRIDE_KBD_LOCK)) + | KBD_ENABLE_KBD_PORT | KBD_ENABLE_KBD_INT)) { /* CONTROLLER ERROR * This is serious; we are left with the disabled keyboard intr. */ @@ -389,12 +422,17 @@ scprobe(struct isa_device *dev) } succeed: + kbdc_set_device_mask(sc_kbdc, m | KBD_KBD_CONTROL_BITS), + kbdc_lock(sc_kbdc, FALSE); return (IO_KBDSIZE); fail: if (c != -1) - /* try to restore the command byte as before, if possible */ - set_controller_command_byte(sc_port, c, 0); + /* try to restore the command byte as before, if possible */ + set_controller_command_byte(sc_kbdc, 0xff, c); + kbdc_set_device_mask(sc_kbdc, + (dev->id_flags & DETECT_KBD) ? m : m | KBD_KBD_CONTROL_BITS); + kbdc_lock(sc_kbdc, FALSE); return ((dev->id_flags & DETECT_KBD) ? 0 : IO_KBDSIZE); } @@ -423,14 +461,6 @@ scattach(struct isa_device *dev) if (crtc_vga) { cut_buffer = (char *)malloc(scp->xsize*scp->ysize, M_DEVBUF, M_NOWAIT); - font_8 = (char *)malloc(8*256, M_DEVBUF, M_NOWAIT); - font_14 = (char *)malloc(14*256, M_DEVBUF, M_NOWAIT); - font_16 = (char *)malloc(16*256, M_DEVBUF, M_NOWAIT); - copy_font(SAVE, FONT_16, font_16); - fonts_loaded = FONT_16; - scp->font_size = FONT_16; - palette = (char *)malloc(3*256, M_DEVBUF, M_NOWAIT); - save_palette(); } scp->scr_buf = (u_short *)malloc(scp->xsize*scp->ysize*sizeof(u_short), @@ -1106,7 +1136,7 @@ scioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) copy_font(LOAD, FONT_16, font_16); if (flags & CHAR_CURSOR) set_destructive_cursor(scp); - load_palette(); + load_palette(palette); } /* FALL THROUGH */ @@ -1155,9 +1185,8 @@ scioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) case KDSETRAD: /* set keyboard repeat & delay rates */ if (*data & 0x80) return EINVAL; - i = spltty(); - send_kbd_command_and_data(sc_port, KBDC_SET_TYPEMATIC, *data); - splx(i); + if (sc_kbdc != NULL) + set_keyboard(KBDC_SET_TYPEMATIC, *data); return 0; case KDSKBMODE: /* set keyboard mode */ @@ -1405,6 +1434,8 @@ sccnprobe(struct consdev *cp) /* initialize required fields */ cp->cn_dev = makedev(CDEV_MAJOR, SC_CONSOLE); cp->cn_pri = CN_INTERNAL; + + sc_kbdc = kbdc_open(sc_port); } void @@ -1499,8 +1530,21 @@ scrn_timer() * This ugly hack calls scintr if input is ready for the keyboard * and conveniently hides the problem. XXX */ - if ((inb(sc_port+KBD_STATUS_PORT)&KBDS_BUFFER_FULL) == KBDS_KBD_BUFFER_FULL) - scintr(0); + /* Try removing anything stuck in the keyboard controller; whether + * it's a keyboard scan code or mouse data. `scintr()' doesn't + * read the mouse data directly, but `kbdio' routines will, as a + * side effect. + */ + if (kbdc_lock(sc_kbdc, TRUE)) { + /* + * We have seen the lock flag is not set. Let's reset the flag early; + * otherwise `update_led()' failes which may want the lock + * during `scintr()'. + */ + kbdc_lock(sc_kbdc, FALSE); + if (kbdc_data_ready(sc_kbdc)) + scintr(0); + } /* should we just return ? */ if ((scp->status&UNKNOWN_MODE) || blink_in_progress || switch_in_progress) { @@ -1659,7 +1703,7 @@ exchange_scr(void) if ((old_scp->status & UNKNOWN_MODE) && crtc_vga) { if (flags & CHAR_CURSOR) set_destructive_cursor(new_scp); - load_palette(); + load_palette(palette); } if (old_scp->status & KBD_RAW_MODE || new_scp->status & KBD_RAW_MODE) shfts = ctls = alts = agrs = metas = 0; @@ -2354,9 +2398,8 @@ scinit(void) u_long segoff; crtc_vga = TRUE; - /* - * Get the BIOS video mode pointer. - */ + + /* Get the BIOS video mode pointer */ segoff = *(u_long *)pa_to_va(0x4a8); pa = (((segoff & 0xffff0000) >> 12) + (segoff & 0xffff)); if (ISMAPPED(pa, sizeof(u_long))) { @@ -2374,6 +2417,13 @@ scinit(void) bcopyw(Crtat, sc_buffer, console[0]->xsize * console[0]->ysize * sizeof(u_short)); + /* Save font and palette if VGA */ + if (crtc_vga) { + copy_font(SAVE, FONT_16, font_16); + fonts_loaded = FONT_16; + save_palette(); + } + console[0]->scr_buf = console[0]->mouse_pos = sc_buffer; console[0]->cursor_pos = console[0]->cursor_oldpos = sc_buffer + hw_cursor; console[0]->xpos = hw_cursor % COL; @@ -2387,6 +2437,7 @@ scinit(void) kernel_console.cur_color = kernel_console.std_color = kernel_default.std_color; kernel_console.rev_color = kernel_default.rev_color; + /* initialize mapscrn arrays to a one to one map */ for (i=0; imode = M_VGA_M80x25; else - scp->mode = M_VGA_C80x25; + scp->mode = M_VGA_C80x25; else if (crtc_addr == MONO_BASE) scp->mode = M_B80x25; @@ -2542,12 +2593,12 @@ scgetc(u_int flags) next_code: /* first see if there is something in the keyboard port */ if (flags & SCGETC_NONBLOCK) { - c = read_kbd_data_no_wait(sc_port); + c = read_kbd_data_no_wait(sc_kbdc); if (c == -1) return(NOKEY); } else { do { - c = read_kbd_data(sc_port); + c = read_kbd_data(sc_kbdc); } while(c == -1); } scancode = (u_char)c; @@ -3001,9 +3052,54 @@ mask2attr(struct term_stat *term) } static void -update_leds(int which) +set_keyboard(int command, int data) { int s; + int c; + + if (sc_kbdc == NULL) + return; + + /* prevent the timeout routine from polling the keyboard */ + if (!kbdc_lock(sc_kbdc, TRUE)) + return; + + /* disable the keyboard and mouse interrupt */ + s = spltty(); + c = get_controller_command_byte(sc_kbdc); + if ((c == -1) + || !set_controller_command_byte(sc_kbdc, + kbdc_get_device_mask(sc_kbdc), + KBD_ENABLE_KBD_PORT | KBD_DISABLE_KBD_INT + | KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { + /* CONTROLLER ERROR */ + kbdc_lock(sc_kbdc, FALSE); + splx(s); + return; + } + /* + * 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); + + send_kbd_command_and_data(sc_kbdc, command, data); + + /* restore the interrupts */ + if (!set_controller_command_byte(sc_kbdc, + kbdc_get_device_mask(sc_kbdc), + c & (KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS))) { + /* CONTROLLER ERROR */ + } + kbdc_lock(sc_kbdc, FALSE); +} + +static void +update_leds(int which) +{ static u_char xlate_leds[8] = { 0, 4, 2, 6, 1, 5, 3, 7 }; /* replace CAPS led with ALTGR led for ALTGR keyboards */ @@ -3014,10 +3110,7 @@ update_leds(int which) which &= ~CLKED; } - s = spltty(); - send_kbd_command_and_data(sc_port, KBDC_SET_LEDS, - xlate_leds[which & LED_MASK]); - splx(s); + set_keyboard(KBDC_SET_LEDS, xlate_leds[which & LED_MASK]); } void @@ -3595,7 +3688,7 @@ save_palette(void) } void -load_palette(void) +load_palette(char *palette) { int i; @@ -3658,6 +3751,7 @@ toggle_splash_screen(scr_stat *scp) scp->mode = save_mode; scp->status &= ~UNKNOWN_MODE; set_mode(scp); + load_palette(palette); toggle = 0; } else { diff --git a/sys/isa/syscons.h b/sys/isa/syscons.h index a9d5a04e6f01..9af7e26c5860 100644 --- a/sys/isa/syscons.h +++ b/sys/isa/syscons.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1995-1996 Søren Schmidt + * Copyright (c) 1995-1997 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -192,6 +192,6 @@ typedef struct default_attr { void set_border(u_char color); void set_mode(scr_stat *scp); void copy_font(int operation, int font_type, char* font_image); -void load_palette(void); +void load_palette(char *palette); #endif /* !_I386_ISA_SYSCONS_H_ */ diff --git a/sys/modules/syscons/fade/fade_saver.c b/sys/modules/syscons/fade/fade_saver.c index 524022d8d136..64291d9eee88 100644 --- a/sys/modules/syscons/fade/fade_saver.c +++ b/sys/modules/syscons/fade/fade_saver.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1995 Søren Schmidt + * Copyright (c) 1995-1997 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -68,7 +68,7 @@ fade_saver(int blank) } } else { - load_palette(); + load_palette(palette); count = scrn_blanked = 0; } } diff --git a/sys/modules/syscons/saver.h b/sys/modules/syscons/saver.h index e190d99981b5..b43c5627551d 100644 --- a/sys/modules/syscons/saver.h +++ b/sys/modules/syscons/saver.h @@ -1,4 +1,32 @@ -/* $FreeBSD$ */ +/*- + * Copyright (c) 1995-1997 Søren Schmidt + * All rights reserved. + * + * 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 + * in this position and unchanged. + * 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. The name of the author may not be used to endorse or promote products + * derived from this software withough specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * $FreeBSD$ + */ #include #include @@ -14,6 +42,10 @@ extern scr_stat *cur_console; extern u_short *Crtat; extern u_int crtc_addr; +extern char crtc_vga; extern char scr_map[]; extern int scrn_blanked; -extern char palette[]; +extern int fonts_loaded; +extern char *font_8, *font_14, *font_16; +extern char *palette; +extern char *video_mode_ptr;