From 5e0b8d508ed51004bd836384293be00950ee62c9 Mon Sep 17 00:00:00 2001 From: Pasha Date: Tue, 20 Feb 2024 18:49:50 +0000 Subject: init gnumach copy --- i386/i386at/kd.c | 3059 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 3059 insertions(+) create mode 100644 i386/i386at/kd.c (limited to 'i386/i386at/kd.c') diff --git a/i386/i386at/kd.c b/i386/i386at/kd.c new file mode 100644 index 0000000..2bea3c8 --- /dev/null +++ b/i386/i386at/kd.c @@ -0,0 +1,3059 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * Olivetti Mach Console driver v0.0 + * Copyright Ing. C. Olivetti & C. S.p.A. 1988, 1989 + * All rights reserved. + * + */ +/* + Copyright 1988, 1989 by Olivetti Advanced Technology Center, Inc., +Cupertino, California. + + All Rights Reserved + + Permission to use, copy, modify, and distribute this software and +its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appears in all +copies and that both the copyright notice and this permission notice +appear in supporting documentation, and that the name of Olivetti +not be used in advertising or publicity pertaining to distribution +of the software without specific, written prior permission. + + OLIVETTI DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, +IN NO EVENT SHALL OLIVETTI BE LIABLE FOR ANY SPECIAL, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, +NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUR OF OR IN CONNECTION +WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +/* + Copyright 1988, 1989 by Intel Corporation, Santa Clara, California. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and +its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appears in all +copies and that both the copyright notice and this permission notice +appear in supporting documentation, and that the name of Intel +not be used in advertising or publicity pertaining to distribution +of the software without specific, written prior permission. + +INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, +IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, +NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION +WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +/* $ Header: $ */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEBUG 1 /* export feep() */ + +#if 0 +#define BROKEN_KEYBOARD_RESET +#endif + +struct tty kd_tty; +extern boolean_t rebootflag; + +static void charput(csrpos_t pos, char ch, char chattr); +static void charmvup(csrpos_t from, csrpos_t to, int count); +static void charmvdown(csrpos_t from, csrpos_t to, int count); +static void charclear(csrpos_t to, int count, char chattr); +static void charsetcursor(csrpos_t newpos); +static void kd_noopreset(void); + +/* + * These routines define the interface to the device-specific layer. + * See kdsoft.h for a more complete description of what each routine does. + */ +void (*kd_dput)(csrpos_t, char, char) = charput; /* put attributed char */ +void (*kd_dmvup)(csrpos_t, csrpos_t, int) = charmvup; /* block move up */ +void (*kd_dmvdown)(csrpos_t, csrpos_t, int) = charmvdown; /* block move down */ +void (*kd_dclear)(csrpos_t, int, char) = charclear; /* block clear */ +void (*kd_dsetcursor)(csrpos_t) = charsetcursor; + /* set cursor position on displayed page */ +void (*kd_dreset)(void) = kd_noopreset; /* prepare for reboot */ + +/* + * Globals used for both character-based controllers and bitmap-based + * controllers. Default is EGA. + */ + +vm_offset_t kd_bitmap_start = (vm_offset_t)0xa0000; /* XXX - put in kd.h */ +u_char *vid_start = (u_char *)EGA_START; + /* VM start of video RAM or frame buffer */ +csrpos_t kd_curpos = 0; /* set indirectly by kd_setpos--see kdsoft.h */ +short kd_lines = 25; +short kd_cols = 80; +char kd_attr = KA_NORMAL; /* current attribute */ +char kd_color = KA_NORMAL; +char kd_attrflags = 0; /* Not reverse, underline, blink */ + +/* + * kd_state shows the state of the modifier keys (ctrl, caps lock, + * etc.) It should normally be changed by calling set_kd_state(), so + * that the keyboard status LEDs are updated correctly. + */ +int kd_state = KS_NORMAL; +int kb_mode = KB_ASCII; /* event/ascii */ + +/* + * State for the keyboard "mouse". + */ +int kd_kbd_mouse = 0; +int kd_kbd_magic_scale = 6; +int kd_kbd_magic_button = 0; + +/* + * Some keyboard commands work by sending a command, waiting for an + * ack (handled by kdintr), then sending data, which generates a + * second ack. If we are in the middle of such a sequence, kd_ack + * shows what the ack is for. + * + * When a byte is sent to the keyboard, it is kept around in last_sent + * in case it needs to be resent. + * + * The rest of the variables here hold the data required to complete + * the sequence. + * + * XXX - the System V driver keeps a command queue, I guess in case we + * want to start a command while another is in progress. Is this + * something we should worry about? + */ +enum why_ack {NOT_WAITING, SET_LEDS, DATA_ACK}; +enum why_ack kd_ack = NOT_WAITING; + +u_char last_sent = 0; + +u_char kd_nextled = 0; + +/* + * We don't provide any mutex protection for this flag because we know + * that this module will have been initialized by the time multiple + * threads are running. + */ +boolean_t kd_initialized = FALSE; /* driver initialized? */ +boolean_t kd_extended = FALSE; + +/* Array for processing escape sequences. */ +#define K_MAXESC 32 +u_char esc_seq[K_MAXESC]; +u_char *esc_spt = (u_char *)0; + +/* + * This array maps scancodes to Ascii characters (or character + * sequences). + * Each row corresponds to one key. There are NUMOUTPUT bytes per key + * state. The states are ordered: Normal, SHIFT, CTRL, ALT, + * SHIFT/ALT. + */ + +/* This new keymap from Tudor Hulubei (tudor@cs.unh.edu) makes the + following changes to the keyboard driver: + + - Alt + key (m-key) returns `ESC key' instead of `ESC N key'. + - Backspace returns 0x7f instead of 0x08. + - Delete returns `ESC [ 9' instead of 0x7f. + - Alt + function keys return key sequences that are different + from the key sequences returned by the function keys alone. + This is done with the idea of allowing a terminal server to + implement multiple virtual consoles mapped on Alt+F1, Alt+F2, + etc, as in Linux. + + -- Derek Upham 1997/06/25 */ + +unsigned char key_map[NUMKEYS][WIDTH_KMAP] = { +{NC,NC,NC, NC,NC,NC, NC,NC,NC, NC,NC,NC, NC,NC,NC}, +{K_ESC,NC,NC, K_ESC,NC,NC, K_ESC,NC,NC, 0x1b,K_ESC,NC, K_ESC,NC,NC}, +{K_ONE,NC,NC, K_BANG,NC,NC, K_ONE,NC,NC, 0x1b,K_ONE,NC, 0x1b,0x4e,K_BANG}, +{K_TWO,NC,NC, K_ATSN,NC,NC, K_NUL,NC,NC, 0x1b,K_TWO,NC, 0x1b,0x4e,K_ATSN}, +{K_THREE,NC,NC, K_POUND,NC,NC, K_THREE,NC,NC, 0x1b,K_THREE,NC, 0x1b,0x4e,K_POUND}, +{K_FOUR,NC,NC, K_DOLLAR,NC,NC, K_FOUR,NC,NC, 0x1b,K_FOUR,NC, 0x1b,0x4e,K_DOLLAR}, +{K_FIVE,NC,NC, K_PERC,NC,NC, K_FIVE,NC,NC, 0x1b,K_FIVE,NC, 0x1b,0x4e,K_PERC}, +{K_SIX,NC,NC, K_CARET,NC,NC, K_RS,NC,NC, 0x1b,K_SIX,NC, 0x1b,0x4e,K_CARET}, +{K_SEVEN,NC,NC, K_AMPER,NC,NC, K_SEVEN,NC,NC, 0x1b,K_SEVEN,NC, 0x1b,0x4e,K_AMPER}, +{K_EIGHT,NC,NC, K_ASTER,NC,NC, K_EIGHT,NC,NC, 0x1b,K_EIGHT,NC, 0x1b,0x4e,K_ASTER}, +{K_NINE,NC,NC, K_LPAREN,NC,NC, K_NINE,NC,NC, 0x1b,K_NINE,NC, 0x1b,0x4e,K_LPAREN}, +{K_ZERO,NC,NC, K_RPAREN,NC,NC, K_ZERO,NC,NC, 0x1b,K_ZERO,NC, 0x1b,0x4e,K_RPAREN}, +{K_MINUS,NC,NC, K_UNDSC,NC,NC, K_US,NC,NC, 0x1b,K_MINUS,NC, 0x1b,0x4e,K_UNDSC}, +{K_EQL,NC,NC, K_PLUS,NC,NC, K_EQL,NC,NC, 0x1b,K_EQL,NC, 0x1b,0x4e,K_PLUS}, +{K_DEL,NC,NC, K_DEL,NC,NC, K_DEL,NC,NC, 0x1b,K_DEL,NC, K_DEL,NC,NC}, +{K_HT,NC,NC, K_GS,NC,NC, K_HT,NC,NC, 0x1b,K_HT,NC, K_GS,NC,NC}, +{K_q,NC,NC, K_Q,NC,NC, K_DC1,NC,NC, 0x1b,K_q,NC, 0x1b,0x4e,K_Q}, +{K_w,NC,NC, K_W,NC,NC, K_ETB,NC,NC, 0x1b,K_w,NC, 0x1b,0x4e,K_W}, +{K_e,NC,NC, K_E,NC,NC, K_ENQ,NC,NC, 0x1b,K_e,NC, 0x1b,0x4e,K_E}, +{K_r,NC,NC, K_R,NC,NC, K_DC2,NC,NC, 0x1b,K_r,NC, 0x1b,0x4e,K_R}, +{K_t,NC,NC, K_T,NC,NC, K_DC4,NC,NC, 0x1b,K_t,NC, 0x1b,0x4e,K_T}, +{K_y,NC,NC, K_Y,NC,NC, K_EM,NC,NC, 0x1b,K_y,NC, 0x1b,0x4e,K_Y}, +{K_u,NC,NC, K_U,NC,NC, K_NAK,NC,NC, 0x1b,K_u,NC, 0x1b,0x4e,K_U}, +{K_i,NC,NC, K_I,NC,NC, K_HT,NC,NC, 0x1b,K_i,NC, 0x1b,0x4e,K_I}, +{K_o,NC,NC, K_O,NC,NC, K_SI,NC,NC, 0x1b,K_o,NC, 0x1b,0x4e,K_O}, +{K_p,NC,NC, K_P,NC,NC, K_DLE,NC,NC, 0x1b,K_p,NC, 0x1b,0x4e,K_P}, +{K_LBRKT,NC,NC, K_LBRACE,NC,NC, K_ESC,NC,NC, 0x1b,K_LBRKT,NC, 0x1b,0x4e,K_LBRACE}, +{K_RBRKT,NC,NC, K_RBRACE,NC,NC, K_GS,NC,NC, 0x1b,K_RBRKT,NC, 0x1b,0x4e,K_RBRACE}, +{K_CR,NC,NC, K_CR,NC,NC, K_CR,NC,NC, 0x1b,K_CR,NC, K_CR,NC,NC}, +{K_SCAN,K_CTLSC,NC, K_SCAN,K_CTLSC,NC, K_SCAN,K_CTLSC,NC, K_SCAN,K_CTLSC,NC, K_SCAN,K_CTLSC,NC}, +{K_a,NC,NC, K_A,NC,NC, K_SOH,NC,NC, 0x1b,K_a,NC, 0x1b,0x4e,K_A}, +{K_s,NC,NC, K_S,NC,NC, K_DC3,NC,NC, 0x1b,K_s,NC, 0x1b,0x4e,K_S}, +{K_d,NC,NC, K_D,NC,NC, K_EOT,NC,NC, 0x1b,K_d,NC, 0x1b,0x4e,K_D}, +{K_f,NC,NC, K_F,NC,NC, K_ACK,NC,NC, 0x1b,K_f,NC, 0x1b,0x4e,K_F}, +{K_g,NC,NC, K_G,NC,NC, K_BEL,NC,NC, 0x1b,K_g,NC, 0x1b,0x4e,K_G}, +{K_h,NC,NC, K_H,NC,NC, K_BS,NC,NC, 0x1b,K_h,NC, 0x1b,0x4e,K_H}, +{K_j,NC,NC, K_J,NC,NC, K_LF,NC,NC, 0x1b,K_j,NC, 0x1b,0x4e,K_J}, +{K_k,NC,NC, K_K,NC,NC, K_VT,NC,NC, 0x1b,K_k,NC, 0x1b,0x4e,K_K}, +{K_l,NC,NC, K_L,NC,NC, K_FF,NC,NC, 0x1b,K_l,NC, 0x1b,0x4e,K_L}, +{K_SEMI,NC,NC, K_COLON,NC,NC, K_SEMI,NC,NC, 0x1b,K_SEMI,NC, 0x1b,0x4e,K_COLON}, +{K_SQUOTE,NC,NC,K_DQUOTE,NC,NC, K_SQUOTE,NC,NC,0x1b,K_SQUOTE,NC, 0x1b,0x4e,K_DQUOTE}, +{K_GRAV,NC,NC, K_TILDE,NC,NC, K_RS,NC,NC, 0x1b,K_GRAV,NC, 0x1b,0x4e,K_TILDE}, +{K_SCAN,K_LSHSC,NC, K_SCAN,K_LSHSC,NC, K_SCAN,K_LSHSC,NC, K_SCAN,K_LSHSC,NC, K_SCAN,K_LSHSC,NC}, +{K_BSLSH,NC,NC, K_PIPE,NC,NC, K_FS,NC,NC, 0x1b,K_BSLSH,NC, 0x1b,0x4e,K_PIPE}, +{K_z,NC,NC, K_Z,NC,NC, K_SUB,NC,NC, 0x1b,K_z,NC, 0x1b,0x4e,K_Z}, +{K_x,NC,NC, K_X,NC,NC, K_CAN,NC,NC, 0x1b,K_x,NC, 0x1b,0x4e,K_X}, +{K_c,NC,NC, K_C,NC,NC, K_ETX,NC,NC, 0x1b,K_c,NC, 0x1b,0x4e,K_C}, +{K_v,NC,NC, K_V,NC,NC, K_SYN,NC,NC, 0x1b,K_v,NC, 0x1b,0x4e,K_V}, +{K_b,NC,NC, K_B,NC,NC, K_STX,NC,NC, 0x1b,K_b,NC, 0x1b,0x4e,K_B}, +{K_n,NC,NC, K_N,NC,NC, K_SO,NC,NC, 0x1b,K_n,NC, 0x1b,0x4e,K_N}, +{K_m,NC,NC, K_M,NC,NC, K_CR,NC,NC, 0x1b,K_m,NC, 0x1b,0x4e,K_M}, +{K_COMMA,NC,NC, K_LTHN,NC,NC, K_COMMA,NC,NC, 0x1b,K_COMMA,NC, 0x1b,0x4e,K_LTHN}, +{K_PERIOD,NC,NC,K_GTHN,NC,NC, K_PERIOD,NC,NC,0x1b,K_PERIOD,NC, 0x1b,0x4e,K_GTHN}, +{K_SLASH,NC,NC, K_QUES,NC,NC, K_SLASH,NC,NC, 0x1b,K_SLASH,NC, 0x1b,0x4e,K_QUES}, +{K_SCAN,K_RSHSC,NC, K_SCAN,K_RSHSC,NC, K_SCAN,K_RSHSC,NC, K_SCAN,K_RSHSC,NC, K_SCAN,K_RSHSC,NC}, +{K_ASTER,NC,NC, K_ASTER,NC,NC, K_ASTER,NC,NC, 0x1b,K_ASTER,NC, 0x1b,0x4e,K_ASTER}, +{K_SCAN,K_ALTSC,NC, K_SCAN,K_ALTSC,NC, K_SCAN,K_ALTSC,NC, K_SCAN,K_ALTSC,NC, K_SCAN,K_ALTSC,NC}, +{K_SPACE,NC,NC, K_SPACE,NC,NC, K_NUL,NC,NC, 0x1b,K_SPACE,NC, K_SPACE,NC,NC}, +{K_SCAN,K_CLCKSC,NC, K_SCAN,K_CLCKSC,NC, K_SCAN,K_CLCKSC,NC, K_SCAN,K_CLCKSC,NC, K_SCAN,K_CLCKSC,NC}, +{K_F1, K_F1S, K_F1, K_F1A, K_F1S}, +{K_F2, K_F2S, K_F2, K_F2A, K_F2S}, +{K_F3, K_F3S, K_F3, K_F3A, K_F3S}, +{K_F4, K_F4S, K_F4, K_F4A, K_F4S}, +{K_F5, K_F5S, K_F5, K_F5A, K_F5S}, +{K_F6, K_F6S, K_F6, K_F6A, K_F6S}, +{K_F7, K_F7S, K_F7, K_F7A, K_F7S}, +{K_F8, K_F8S, K_F8, K_F8A, K_F8S}, +{K_F9, K_F9S, K_F9, K_F9A, K_F9S}, +{K_F10, K_F10S, K_F10, K_F10A, K_F10S}, +{K_SCAN,K_NLCKSC,NC, K_SCAN,K_NLCKSC,NC, K_SCAN,K_NLCKSC,NC, K_SCAN,K_NLCKSC,NC, K_SCAN,K_NLCKSC,NC}, +{K_SCRL, K_NUL,NC,NC, K_SCRL, K_SCRL, K_NUL,NC,NC}, +{K_HOME, K_SEVEN,NC,NC, K_HOME, K_HOME, 0x1b,0x4e,K_SEVEN}, +{K_UA, K_EIGHT,NC,NC, K_UA, K_UA, 0x1b,0x4e,K_EIGHT}, +{K_PUP, K_NINE,NC,NC, K_PUP, K_PUP, 0x1b,0x4e,K_NINE}, +{0x1b,0x5b,0x53, K_MINUS,NC,NC, 0x1b,0x5b,0x53, 0x1b,0x5b,0x53, 0x1b,0x4e,0x2d}, +{K_LA, K_FOUR,NC,NC, K_LA, K_LA, 0x1b,0x4e,K_FOUR}, +{0x1b,0x5b,0x47, K_FIVE,NC,NC, 0x1b,0x5b,0x47, 0x1b,0x5b,0x47, 0x1b,0x4e,0x35}, +{K_RA, K_SIX,NC,NC, K_RA, K_RA, 0x1b,0x4e,K_SIX}, +{0x1b,0x5b,0x54, K_PLUS,NC,NC, 0x1b,0x5b,0x54, 0x1b,0x5b,0x54, 0x1b,0x4e,0x2b}, +{K_END, K_ONE,NC,NC, K_END, K_END, 0x1b,0x4e,K_ONE}, +{K_DA, K_TWO,NC,NC, K_DA, K_DA, 0x1b,0x4e,K_TWO}, +{K_PDN, K_THREE,NC,NC, K_PDN, K_PDN, 0x1b,0x4e,K_THREE}, +{K_INS, K_ZERO,NC,NC, K_INS, K_INS, 0x1b,0x4e,K_ZERO}, +{0x1b,0x5b,0x39, K_PERIOD,NC,NC, K_DEL,NC,NC, K_DEL,NC,NC, 0x1b,0x4e,K_PERIOD}, +{NC,NC,NC, NC,NC,NC, NC,NC,NC, NC,NC,NC, NC,NC,NC}, +{NC,NC,NC, NC,NC,NC, NC,NC,NC, NC,NC,NC, NC,NC,NC}, +{NC,NC,NC, NC,NC,NC, NC,NC,NC, NC,NC,NC, NC,NC,NC}, +{K_F11, K_F11S, K_F11, K_F11A, K_F11S}, +{K_F12, K_F12S, K_F12, K_F12A, K_F12S} +}; + + +/* + * Globals used only for character-based controllers. + */ + +short kd_index_reg = EGA_IDX_REG; +short kd_io_reg = EGA_IO_REG; + + +/* + * Globals used only for bitmap-based controllers. See kdsoft.h for + * an explanation of what some of these variables are used for. + */ + +u_char *font_start = 0; /* starting addr of font */ + +short fb_width = 0; /* bits in frame buffer scan line */ +short fb_height = 0; /* scan lines in frame buffer*/ +short char_width = 0; /* bit width of 1 char */ +short char_height = 0; /* bit height of 1 char */ +short chars_in_font = 0; +short cursor_height = 0; /* bit height of cursor */ + +/* These initial values are simply guesses. */ +u_char char_black = 0; +u_char char_white = 0xff; + +short xstart = 0; +short ystart = 0; + +short char_byte_width = 0; /* char_width/NBBY */ +short fb_byte_width = 0; /* fb_width/NBBY */ +short font_byte_width = 0; /* num bytes in 1 scan line of font */ + +/* + * Switch for poll vs. interrupt. + */ +int kd_pollc = 0; + +#ifdef DEBUG +static void +pause(void) +{ + int i; + + for (i = 0; i < 50000; ++i) + ; +} + +/* + * feep: + * + * Ring the bell for a short time. + * Warning: uses outb(). You may prefer to use kd_debug_put. + */ +void +feep(void) +{ + kd_bellon(); + pause(); + kd_belloff(NULL); +} + +/* + * Put a debugging character on the screen. + * LOC=0 means put it in the bottom right corner, LOC=1 means put it + * one column to the left, etc. + */ +void +kd_debug_put( + int loc, + char c) +{ + csrpos_t pos = ONE_PAGE - (loc+1) * ONE_SPACE; + + (*kd_dput)(pos, c, KA_NORMAL); +} +#endif /* DEBUG */ + + +extern boolean_t mouse_in_use; +int old_kb_mode; + +void +cnpollc(boolean_t on) +{ + if (mouse_in_use) { + if (on) { + /* switch into X */ + old_kb_mode = kb_mode; + kb_mode = KB_ASCII; + X_kdb_enter(); + + kd_pollc++; + } else { + --kd_pollc; + + /* switch out of X */ + X_kdb_exit(); + kb_mode = old_kb_mode; + } + } else { + if (on) { + kd_pollc++; + } else { + --kd_pollc; + } + } +} + + + +/* + * kdopen: + * + * This opens the console driver and sets up the tty and other + * rudimentary stuff including calling the line discipline for + * setting up the device independent stuff for a tty driver. + * + * input: device number 'dev', and flag + * + * output: device is opened and setup + * + */ +int +kdopen( + dev_t dev, + int flag, + io_req_t ior) +{ + struct tty *tp; + spl_t o_pri; + + tp = &kd_tty; + o_pri = simple_lock_irq(&tp->t_lock); + if (!(tp->t_state & (TS_ISOPEN|TS_WOPEN))) { + /* XXX ttychars allocates memory */ + simple_unlock_nocheck(&tp->t_lock.slock); + ttychars(tp); + simple_lock_nocheck(&tp->t_lock.slock); + /* + * Special support for boot-time rc scripts, which don't + * stty the console. + */ + tp->t_oproc = kdstart; + tp->t_stop = kdstop; + tp->t_ospeed = tp->t_ispeed = B115200; + tp->t_flags = ODDP|EVENP|ECHO|CRMOD|XTABS|LITOUT; + kdinit(); + } + tp->t_state |= TS_CARR_ON; + simple_unlock_irq(o_pri, &tp->t_lock); + return (char_open(dev, tp, flag, ior)); +} + + +/* + * kdclose: + * + * This function merely executes the device independent code for + * closing the line discipline. + * + * input: device number 'dev', and flag + * + * output: device is closed + * + */ +/*ARGSUSED*/ +void +kdclose(dev_t dev, int flag) +{ + struct tty *tp; + + tp = &kd_tty; + { + spl_t s; + s = simple_lock_irq(&tp->t_lock); + ttyclose(tp); + simple_unlock_irq(s, &tp->t_lock); + } + + return; +} + + +/* + * kdread: + * + * This function executes the device independent code to read from + * the tty. + * + * input: device number 'dev' + * + * output: characters are read from tty clists + * + */ +/*ARGSUSED*/ +int +kdread(dev_t dev, io_req_t uio) +{ + struct tty *tp; + + tp = &kd_tty; + tp->t_state |= TS_CARR_ON; + return((*linesw[kd_tty.t_line].l_read)(tp, uio)); +} + + +/* + * kdwrite: + * + * This function does the device independent write action for this + * console (tty) driver. + * + * input: device number 'dev' + * + * output: characters are written to tty clists + * + */ +/*ARGSUSED*/ +int +kdwrite(dev_t dev, io_req_t uio) +{ + return((*linesw[kd_tty.t_line].l_write)(&kd_tty, uio)); +} + +/* + * Mmap. + */ + +/*ARGSUSED*/ +vm_offset_t +kdmmap(dev_t dev, vm_offset_t off, vm_prot_t prot) +{ + if (off >= (128*1024)) + return(-1); + + /* Get page frame number for the page to be mapped. */ + return(i386_btop(kd_bitmap_start+off)); +} + +int +kdportdeath( + dev_t dev, + mach_port_t port) +{ + return (tty_portdeath(&kd_tty, (ipc_port_t)port)); +} + +/*ARGSUSED*/ +io_return_t kdgetstat( + dev_t dev, + dev_flavor_t flavor, + dev_status_t data, /* pointer to OUT array */ + mach_msg_type_number_t *count) /* OUT */ +{ + io_return_t result; + + switch (flavor) { + case KDGSTATE: + if (*count < 1) + return (D_INVALID_OPERATION); + *data = kd_state; + *count = 1; + result = D_SUCCESS; + break; + + case KDGKBENT: + result = kdgetkbent((struct kbentry *)data); + *count = sizeof(struct kbentry)/sizeof(int); + break; + + default: + result = tty_get_status(&kd_tty, flavor, data, count); + break; + } + return (result); +} + +/*ARGSUSED*/ +io_return_t kdsetstat( + dev_t dev, + dev_flavor_t flavor, + dev_status_t data, + mach_msg_type_number_t count) +{ + io_return_t result; + + switch (flavor) { + case KDSKBENT: + if (count < sizeof(struct kbentry)/sizeof(int)) { + return (D_INVALID_OPERATION); + } + result = kdsetkbent((struct kbentry *)data, 0); + break; + + case KDSETBELL: + if (count < 1) + return (D_INVALID_OPERATION); + result = kdsetbell(*data, 0); + break; + + default: + result = tty_set_status(&kd_tty, flavor, data, count); + } + return (result); +} + + + +/* + * kdsetbell: + * + * Turn the bell on or off. Returns error code, if given bogus + * on/off value. + */ +int +kdsetbell( + int val, /* on or off */ + int flags) /* flags set for console */ +{ + int err = 0; + + if (val == KD_BELLON) + kd_bellon(); + else if (val == KD_BELLOFF) + kd_belloff(NULL); + else + err = D_INVALID_OPERATION; + + return(err); +} + +/* + * kdgetkbent: + * + * Get entry from key mapping table. Returns error code, if any. + */ +int +kdgetkbent(struct kbentry *kbent) +{ + u_char *cp; + spl_t o_pri = SPLKD(); /* probably superfluous */ + + cp = &key_map[kbent->kb_index][CHARIDX(kbent->kb_state)]; + kbent->kb_value[0] = *cp++; + kbent->kb_value[1] = *cp++; + kbent->kb_value[2] = *cp; + (void)splx(o_pri); + return(0); +} + + +/* + * kdsetkbent: + * + * Set entry in key mapping table. Return error code, if any. + */ +int +kdsetkbent( + struct kbentry *kbent, + int flags) /* flags set for console */ +{ + u_char *cp; + spl_t o_pri; + + o_pri = SPLKD(); + cp = &key_map[kbent->kb_index][CHARIDX(kbent->kb_state)]; + *cp++ = kbent->kb_value[0]; + *cp++ = kbent->kb_value[1]; + *cp = kbent->kb_value[2]; + (void)splx(o_pri); + return(0); +} + +/* + * kdintr: + * + * This function is the interrupt code for the driver. Since this is + * a special tty (console), interrupts are only for input, so we read in + * the character. If in ascii mode, we then do the mapping translation + * from the keyboard switch table and place the characters on the tty's + * input switch table. If in event mode, we create and queue a kd_event. + * + * input: interrupt vector 'vec' + * + * output: character or sequence is placed on appropriate queue + * + */ +/*ARGSUSED*/ +void +kdintr(int vec) +{ + struct tty *tp; + unsigned char c; + unsigned char scancode; + unsigned int char_idx; + boolean_t up = FALSE; /* key-up event */ + + if (kd_pollc) + return; /* kdb polling kbd */ + + if (!kd_initialized) + return; + + tp = &kd_tty; +#ifdef old + while ((inb(K_STATUS) & K_OBUF_FUL) == 0) + ; /* this should never loop */ +#else /* old */ + { + /* + * Allow for keyboards that raise interrupt before + * the character gets to the buffer. But don't wait + * forever if grabbing the character by polling leaves + * the interrupt on but buffer empty. + */ + /* + * Micronics VLB motherboard with 486DX2 can report keyboard + * interrupt before K_STATUS register indicates that the + * output buffer is full. Moreover, the bus won't settle w + * while we poll K_STATUS at speed. Temporary fix is to break + * out after safety runs out and pick up keyboard event. This + * should be fixed eventually by putting a 1us timout between + * inb's to K_STATUS and fix the pic initialization order to + * avoid bootup keyboard wedging (ie make kd a real device) + */ + int safety = 1000; + while ((inb(K_STATUS) & K_OBUF_FUL) == 0) + if (!safety--) break; /* XXX */ + } +#endif /* old */ + /* + * We may have seen a mouse event. + */ + if ((inb(K_STATUS) & 0x20) == 0x20) { + if (mouse_in_use) { + mouse_handle_byte((u_char)inb(K_RDWR)); + return; + } else { + printf("M%xI", inb(K_RDWR)); + return; + } + } + + scancode = inb(K_RDWR); + if (scancode == K_EXTEND && kb_mode != KB_EVENT) { + kd_extended = TRUE; + goto done; + } else if (scancode == K_RESEND) { + kd_resend(); + goto done; + } else if (scancode == K_ACKSC) { + kd_handle_ack(); + goto done; + } else if (kd_kbd_mouse && kd_kbd_magic(scancode)) { + goto done; + } else if (kdcheckmagic(scancode)) { + goto done; + } else if (kb_mode == KB_EVENT) { + kd_enqsc(scancode); + goto done; + } /* else... */ + + if (scancode & K_UP) { + up = TRUE; + scancode &= ~K_UP; + } + if (scancode < NUMKEYS) { + /* Lookup in map, then process. */ + char_idx = kdstate2idx(kd_state, kd_extended); + c = key_map[scancode][char_idx]; + if (c == K_SCAN) { + c = key_map[scancode][++char_idx]; + set_kd_state(do_modifier(kd_state, c, up)); + } else if (!up) { + /* regular key-down */ + unsigned int max; /* max index for char sequence */ + + max = char_idx + NUMOUTPUT; + char_idx++; + if (!kd_extended) { + if (kd_state&KS_CLKED) { + if (kd_isupper(c)) { + c += ('a' - 'A'); + max = char_idx; + } + else if (kd_islower(c)) { + c -= ('a' - 'A'); + max = char_idx; + } + } + /* + * Notice that even if the keypad is remapped, + * NumLock only effects the keys that are + * physically part of the keypad. Is this + * The Right Thing? + */ + if ((kd_state&KS_NLKED) && + (((K_HOMESC) <= scancode) && + (scancode <= (K_DELSC)))) { + char_idx = CHARIDX(SHIFT_STATE); + c = key_map[scancode][char_idx]; + max = char_idx + NUMOUTPUT; + char_idx++; + } + } + + /* + * here's where we actually put the char (or + * char sequence, for function keys) onto the + * input queue. + */ + for ( ; (c != K_DONE) && (char_idx <= max); + c = key_map[scancode][char_idx++]) { + (*linesw[tp->t_line].l_rint)(c, tp); + } + kd_extended = FALSE; + } + } + + done: + return; +} + +/* + * kd_handle_ack: + * + * For pending commands, complete the command. For data bytes, + * drop the ack on the floor. + */ +void +kd_handle_ack(void) +{ + switch (kd_ack) { + case SET_LEDS: + kd_setleds2(); + kd_ack = DATA_ACK; + break; + case DATA_ACK: + kd_ack = NOT_WAITING; + break; + case NOT_WAITING: + printf("unexpected ACK from keyboard\n"); + break; + default: + panic("bogus kd_ack\n"); + break; + } +} + +/* + * kd_resend: + * + * Resend a missed keyboard command or data byte. + */ +void +kd_resend(void) +{ + if (kd_ack == NOT_WAITING) + printf("unexpected RESEND from keyboard\n"); + else + kd_senddata(last_sent); +} + + +/* + * do_modifier: + * + * Change keyboard state according to which modifier key and + * whether it went down or up. + * + * input: the current state, the key, and the key's direction. + * The key can be any key, not just a modifier key. + * + * output: the new state + */ +int +do_modifier( + int state, + Scancode c, + boolean_t up) +{ + switch (c) { + case (K_ALTSC): + if (up) + state &= ~KS_ALTED; + else + state |= KS_ALTED; + kd_extended = FALSE; + break; +#ifndef ORC + case (K_CLCKSC): +#endif /* ORC */ + case (K_CTLSC): + if (up) + state &= ~KS_CTLED; + else + state |= KS_CTLED; + kd_extended = FALSE; + break; +#ifdef ORC + case (K_CLCKSC): + if (!up) + state ^= KS_CLKED; + break; +#endif /* ORC */ + case (K_NLCKSC): + if (!up) + state ^= KS_NLKED; + break; + case (K_LSHSC): + case (K_RSHSC): + if (up) + state &= ~KS_SHIFTED; + else + state |= KS_SHIFTED; + kd_extended = FALSE; + break; + } + + return(state); +} + + +/* + * kdcheckmagic: + * + * Check for magic keystrokes for invoking the debugger or + * rebooting or ... + * + * input: an unprocessed scancode + * + * output: TRUE if a magic key combination was recognized and + * processed. FALSE otherwise. + * + * side effects: + * various actions possible, depending on which keys are + * pressed. If the debugger is called, steps are taken + * to ensure that the system doesn't think the magic keys + * are still held down. + */ +boolean_t +kdcheckmagic(Scancode scancode) +{ + static int magic_state = KS_NORMAL; /* like kd_state */ + boolean_t up = FALSE; + + if (scancode == 0x46) /* scroll lock */ +/* if (scancode == 0x52) ** insert key */ + { + kd_kbd_mouse = !kd_kbd_mouse; + kd_kbd_magic_button = 0; + return(TRUE); + } + if (scancode & K_UP) { + up = TRUE; + scancode &= ~K_UP; + } + magic_state = do_modifier(magic_state, scancode, up); + + if ((magic_state&(KS_CTLED|KS_ALTED)) == (KS_CTLED|KS_ALTED)) { + switch (scancode) { +#if MACH_KDB + case K_dSC: /* ctl-alt-d */ + kdb_kintr(); /* invoke debugger */ + /* Returned from debugger, so reset kbd state. */ + (void)SPLKD(); + magic_state = KS_NORMAL; + if (kb_mode == KB_ASCII) + kd_state = KS_NORMAL; + /* setting leds kills kbd */ + else { + kd_enqsc(K_ALTSC | K_UP); + kd_enqsc(K_CTLSC | K_UP); + kd_enqsc(K_dSC | K_UP); + } + return(TRUE); + break; +#endif /* MACH_KDB */ + case K_DELSC: /* ctl-alt-del */ + /* if rebootflag is on, reboot the system */ + if (rebootflag) + kdreboot(); + break; + } + } + return(FALSE); +} + + +/* + * kdstate2idx: + * + * Return the value for the 2nd index into key_map that + * corresponds to the given state. + */ +unsigned int +kdstate2idx(unsigned int state, /* bit vector, not a state index */ + boolean_t extended) +{ + int state_idx = NORM_STATE; + + if ((!extended) && state != KS_NORMAL) { + if ((state&(KS_SHIFTED|KS_ALTED)) == (KS_SHIFTED|KS_ALTED)) + state_idx = SHIFT_ALT; + /* CTRL should have higher priority than SHIFT. That + way, CTRL-SHIFT-2 and CTRL-2 produce the same keycode. + --Derek Upham 1997/06/25 */ + else if (state&KS_CTLED) + state_idx = CTRL_STATE; + else if (state&KS_SHIFTED) + state_idx = SHIFT_STATE; + else if (state&KS_ALTED) + state_idx = ALT_STATE; + } + + return (CHARIDX(state_idx)); +} + +/* + * kdstart: + * + * This function does the general processing of characters and other + * operations for the device driver. The device independent portion of + * the tty driver calls this routine (it's setup in kdinit) with a + * given command. That command is then processed, and control is passed + * back to the kernel. + * + * input: tty pointer 'tp', and command to execute 'cmd' + * + * output: command is executed + * + * Entered and left at spltty. Drops priority to spl0 to display character. + * ASSUMES that it is never called from interrupt-driven code. + */ +void +kdstart(struct tty *tp) +{ + spl_t o_pri; + int ch; + + if (tp->t_state & TS_TTSTOP) + return; + for ( ; ; ) { + tp->t_state &= ~TS_BUSY; + if (tp->t_state & TS_TTSTOP) + break; + if ((tp->t_outq.c_cc <= 0) || (ch = getc(&tp->t_outq)) == -1) + break; + /* + * Drop priority for long screen updates. ttstart() calls us at + * spltty. + */ + o_pri = splsoftclock(); /* block timeout */ + kd_putc_esc(ch); + splx(o_pri); + } + if (tp->t_outq.c_cc <= TTLOWAT(tp)) { + tt_write_wakeup(tp); + } +} + +/*ARGSUSED*/ +void +kdstop( + struct tty *tp, + int flags) +{ + /* + * do nothing - all characters are output by one call to + * kdstart. + */ +} + +/* + * kdinit: + * + * This code initializes the structures and sets up the port registers + * for the console driver. + * + * Each bitmap-based graphics card is likely to require a unique + * way to determine the card's presence. The driver runs through + * each "special" card that it knows about and uses the first one + * that it finds. If it doesn't find any, it assumes that an + * EGA-like card is installed. + * + * input : None. Interrupts are assumed to be disabled + * output : Driver is initialized + * + */ +void +kdinit(void) +{ + unsigned char k_comm; /* keyboard command byte */ + + if (kd_initialized) + return; + + esc_spt = esc_seq; + kd_attr = KA_NORMAL; + + kd_attrflags = 0; + kd_color = KA_NORMAL; + /* + * board specific initialization: set up globals and kd_dxxx + * pointers, and synch displayed cursor with logical cursor. + */ + kd_xga_init(); + + /* get rid of any garbage in output buffer */ + if (inb(K_STATUS) & K_OBUF_FUL) + (void)inb(K_RDWR); + + kd_sendcmd(KC_CMD_READ); /* ask for the ctlr command byte */ + k_comm = kd_getdata(); + k_comm &= ~K_CB_DISBLE; /* clear keyboard disable bit */ + k_comm |= K_CB_ENBLIRQ; /* enable interrupt */ + kd_sendcmd(KC_CMD_WRITE); /* write new ctlr command byte */ + kd_senddata(k_comm); + unmask_irq(KBD_IRQ); + kd_initialized = TRUE; + +#if ENABLE_IMMEDIATE_CONSOLE + /* Now that we're set up, we no longer need or want the + immediate console. */ + { + extern boolean_t immediate_console_enable; + immediate_console_enable = FALSE; + } + + /* The immediate console printed stuff at the bottom of the + screen rather than at the cursor position, so that's where + we should start. */ + kd_setpos(ONE_PAGE - ONE_LINE); printf("\n"); +#endif /* ENABLE_IMMEDIATE_CONSOLE */ + + cnsetleds(kd_state = KS_NORMAL); + /* clear the LEDs AFTER we + enable the keyboard controller. + This keeps NUM-LOCK from being + set on the NEC Versa. */ + + /* Allocate the input buffer. */ + ttychars(&kd_tty); +} + +/* + * kd_belloff: + * + * This routine shuts the bell off, by sending the appropriate code + * to the speaker port. + * + * input : None + * output : bell is turned off + * + */ +static boolean_t kd_bellstate = FALSE; + +void +kd_belloff(void * param) +{ + unsigned char status; + + status = (inb(K_PORTB) & ~(K_SPKRDATA | K_ENABLETMR2)); + outb(K_PORTB, status); + kd_bellstate = FALSE; + return; +} + + +/* + * kd_bellon: + * + * This routine turns the bell on. + * + * input : None + * output : bell is turned on + * + */ +void +kd_bellon(void) +{ + unsigned char status; + + /* program timer 2 */ + outb(K_TMRCTL, K_SELTMR2 | K_RDLDTWORD | K_TSQRWAVE | K_TBINARY); + outb(K_TMR2, 1500 & 0xff); /* LSB */ + outb(K_TMR2, (int)1500 >> 8); /* MSB */ + + /* start speaker - why must we turn on K_SPKRDATA? */ + status = (inb(K_PORTB)| K_ENABLETMR2 | K_SPKRDATA); + outb(K_PORTB, status); + return; +} + +/* + * + * Function kd_putc_esc(): + * + * This function puts a character on the screen, handling escape + * sequences. + * + * input : character to be displayed (or part of an escape code) + * output : character is displayed, or some action is taken + * + */ +void +kd_putc_esc(u_char c) +{ + if (c == (K_ESC)) { + if (esc_spt == esc_seq) { + *(esc_spt++)=(K_ESC); + *(esc_spt) = '\0'; + } else { + kd_putc((K_ESC)); + esc_spt = esc_seq; + } + } else { + if (esc_spt - esc_seq) { + if (esc_spt - esc_seq > K_MAXESC - 1) + esc_spt = esc_seq; + else { + *(esc_spt++) = c; + *(esc_spt) = '\0'; + kd_parseesc(); + } + } else { + kd_putc(c); + } + } +} + +/* + * + * Function kd_putc(): + * + * This function simply puts a character on the screen. It does some + * special processing for linefeed, carriage return, backspace and + * the bell. + * + * input : character to be displayed + * output : character is displayed, or some action is taken + * + */ +int sit_for_0 = 1; + +void +kd_putc(u_char ch) +{ + if ((!ch) && sit_for_0) + return; + + switch (ch) { + case ((K_LF)): + kd_down(); + break; + case ((K_CR)): + kd_cr(); + break; + case ((K_BS)): + kd_left(); + break; + case ((K_HT)): + kd_tab(); + break; + case ((K_BEL)): + /* + * Similar problem to K_BS here (behavior might depend + * on tty setting). Also check LF and CR. + */ + if (!kd_bellstate) + { + kd_bellon(); + timeout(kd_belloff, 0, hz/8 ); + kd_bellstate = TRUE; + } + break; + default: + (*kd_dput)(kd_curpos, ch, kd_attr); + kd_right(); + break; + } + return; +} + + +/* + * kd_setpos: + * + * This function sets the software and hardware cursor position + * on the screen, using device-specific code to actually move and + * display the cursor. + * + * input : position on (or off) screen to move the cursor to + * output : cursor position is updated, screen has been scrolled + * if necessary to bring cursor position back onto + * screen. + * + */ +void +kd_setpos(csrpos_t newpos) +{ + if (newpos > ONE_PAGE) { + kd_scrollup(); + newpos = BOTTOM_LINE; + } + if (newpos < 0) { + kd_scrolldn(); + newpos = 0; + } + + (*kd_dsetcursor)(newpos); +} + + +/* + * kd_scrollup: + * + * This function scrolls the screen up one line using a DMA memory + * copy. + * + * input : None + * output : lines on screen appear to be shifted up one line + * + */ +void +kd_scrollup(void) +{ + csrpos_t to; + csrpos_t from; + int count; + + /* scroll up */ + to = 0; + from = ONE_LINE; + count = (ONE_PAGE - ONE_LINE)/ONE_SPACE; + (*kd_dmvup)(from, to, count); + + /* clear bottom line */ + to = BOTTOM_LINE; + count = ONE_LINE/ONE_SPACE; + (*kd_dclear)(to, count, kd_attr); + return; +} + + +/* + * kd_scrolldn: + * + * Scrolls the characters on the screen down one line. + * + * input : None + * output : Lines on screen appear to be moved down one line + * + */ +void +kd_scrolldn(void) +{ + csrpos_t to; + csrpos_t from; + int count; + + /* move down */ + to = ONE_PAGE - ONE_SPACE; + from = ONE_PAGE - ONE_LINE - ONE_SPACE; + count = (ONE_PAGE - ONE_LINE) / ONE_SPACE; + (*kd_dmvdown)(from, to, count); + + /* clear top line */ + to = 0; + count = ONE_LINE/ONE_SPACE; + (*kd_dclear)(to, count, kd_attr); + return; + +} + + +/* + * kd_parseesc: + * + * This routine begins the parsing of an escape sequence. It uses the + * escape sequence array and the escape spot pointer to handle + * asynchronous parsing of escape sequences. + * + * input : String of characters prepended by an escape + * output : Appropriate actions are taken depending on the string as + * defined by the ansi terminal specification + * + */ +void +kd_parseesc(void) +{ + u_char *escp; + + escp = esc_seq + 1; /* point to char following ESC */ + switch(*(escp)) { + case 'c': + kd_cls(); + kd_home(); + esc_spt = esc_seq; /* reset spot in ESC sequence */ + break; + case '[': + escp++; + kd_parserest(escp); + break; + case '\0': + break; /* not enough info yet */ + default: + kd_putc(*escp); + esc_spt = esc_seq; /* inv sequence char, reset */ + break; + } + return; + +} + + +/* kd_update_kd_attr: + * + * Updates kd_attr according to kd_attrflags and kd_color. + * This code has its origin from console.c and selection.h in + * linux 2.2 drivers/char/. + * Modified for GNU Mach by Marcus Brinkmann. + */ + +#define reverse_video_char(a) (((a) & 0x88) | ((((a) >> 4) | ((a) << 4)) & 0x77)) +static void +kd_update_kd_attr(void) +{ + kd_attr = kd_color; + if (kd_attrflags & KAX_UNDERLINE) + kd_attr = (kd_attr & 0xf0) | KAX_COL_UNDERLINE; + else if (kd_attrflags & KAX_DIM) + kd_attr = (kd_attr & 0xf0) | KAX_COL_DIM; + if (kd_attrflags & KAX_REVERSE) + kd_attr = reverse_video_char(kd_attr); + if (kd_attrflags & KAX_BLINK) + kd_attr ^= 0x80; + if (kd_attrflags & KAX_BOLD) + kd_attr ^= 0x08; +} + +/* color_table added by Julio Merino to take proper color order. + * I get this code from Linux 2.2 source code in file: + * linux/drivers/char/console.c + */ +unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7, + 8,12,10,14, 9,13,11,15 }; +/* + * kd_parserest: + * + * This function will complete the parsing of an escape sequence and + * call the appropriate support routine if it matches a character. This + * function could be greatly improved by using a function jump table, and + * removing this bulky switch statement. + * + * input : An string + * output : Appropriate action based on whether the string matches a + * sequence acceptable to the ansi terminal specification + * + */ +void +kd_parserest(u_char *cp) +{ + int number[16], npar = 0, i; + csrpos_t newpos; + + for(i=0;i<=15;i++) + number[i] = MACH_ATOI_DEFAULT; + + do { + cp += mach_atoi(cp, &number[npar]); + } while (*cp == ';' && ++npar <= 15 && cp++); + + switch(*cp) { + case 'm': + for (i=0;i<=npar;i++) + switch(number[i]) { + case MACH_ATOI_DEFAULT: + case 0: + kd_attrflags = 0; + kd_color = KA_NORMAL; + break; + case 1: + kd_attrflags |= KAX_BOLD; + kd_attrflags &= ~KAX_DIM; + break; + case 2: + kd_attrflags |= KAX_DIM; + kd_attrflags &= ~KAX_BOLD; + break; + case 4: + kd_attrflags |= KAX_UNDERLINE; + break; + case 5: + kd_attrflags |= KAX_BLINK; + break; + case 7: + kd_attrflags |= KAX_REVERSE; + break; + case 8: + kd_attrflags |= KAX_INVISIBLE; + break; + case 21: + case 22: + kd_attrflags &= ~(KAX_BOLD | KAX_DIM); + break; + case 24: + kd_attrflags &= ~KAX_UNDERLINE; + break; + case 25: + kd_attrflags &= ~KAX_BLINK; + break; + case 27: + kd_attrflags &= ~KAX_REVERSE; + break; + case 38: + kd_attrflags |= KAX_UNDERLINE; + kd_color = (kd_color & 0xf0) | (KA_NORMAL & 0x0f); + break; + case 39: + kd_attrflags &= ~KAX_UNDERLINE; + kd_color = (kd_color & 0xf0) | (KA_NORMAL & 0x0f); + break; + default: + if (number[i] >= 30 && number[i] <= 37) { + /* foreground color */ + kd_color = (kd_color & 0xf0) | color_table[(number[i] - 30)]; + } else if (number[i] >= 40 && number[i] <= 47) { + /* background color */ + kd_color = (kd_color & 0x0f) | (color_table[(number[i] - 40)] << 4); + } + break; + } + kd_update_kd_attr(); + esc_spt = esc_seq; + break; + case '@': + if (number[0] == MACH_ATOI_DEFAULT) + kd_insch(1); + else + kd_insch(number[0]); + esc_spt = esc_seq; + break; + case 'A': + if (number[0] == MACH_ATOI_DEFAULT) + kd_up(); + else + while (number[0]--) + kd_up(); + esc_spt = esc_seq; + break; + case 'B': + if (number[0] == MACH_ATOI_DEFAULT) + kd_down(); + else + while (number[0]--) + kd_down(); + esc_spt = esc_seq; + break; + case 'C': + if (number[0] == MACH_ATOI_DEFAULT) + kd_right(); + else + while (number[0]--) + kd_right(); + esc_spt = esc_seq; + break; + case 'D': + if (number[0] == MACH_ATOI_DEFAULT) + kd_left(); + else + while (number[0]--) + kd_left(); + esc_spt = esc_seq; + break; + case 'E': + kd_cr(); + if (number[0] == MACH_ATOI_DEFAULT) + kd_down(); + else + while (number[0]--) + kd_down(); + esc_spt = esc_seq; + break; + case 'F': + kd_cr(); + if (number[0] == MACH_ATOI_DEFAULT) + kd_up(); + else + while (number[0]--) + kd_up(); + esc_spt = esc_seq; + break; + case 'G': + if (number[0] == MACH_ATOI_DEFAULT) + number[0] = 0; + else + if (number[0] > 0) + --number[0]; /* because number[0] is from 1 */ + kd_setpos(BEG_OF_LINE(kd_curpos) + number[0] * ONE_SPACE); + esc_spt = esc_seq; + break; + case 'f': + case 'H': + if (number[0] == MACH_ATOI_DEFAULT && number[1] == MACH_ATOI_DEFAULT) + { + kd_home(); + esc_spt = esc_seq; + break; + } + if (number[0] == MACH_ATOI_DEFAULT) + number[0] = 0; + else if (number[0] > 0) + --number[0]; /* numbered from 1 */ + newpos = (number[0] * ONE_LINE); /* setup row */ + if (number[1] == MACH_ATOI_DEFAULT) + number[1] = 0; + else if (number[1] > 0) + number[1]--; + newpos += (number[1] * ONE_SPACE); /* setup column */ + if (newpos < 0) + newpos = 0; /* upper left */ + if (newpos > ONE_PAGE) + newpos = (ONE_PAGE - ONE_SPACE); /* lower right */ + kd_setpos(newpos); + esc_spt = esc_seq; + break; /* done or not ready */ + case 'J': + switch(number[0]) { + case MACH_ATOI_DEFAULT: + case 0: + kd_cltobcur(); /* clears from current + pos to bottom. + */ + break; + case 1: + kd_cltopcur(); /* clears from top to + current pos. + */ + break; + case 2: + kd_cls(); + break; + default: + break; + } + esc_spt = esc_seq; /* reset it */ + break; + case 'K': + switch(number[0]) { + case MACH_ATOI_DEFAULT: + case 0: + kd_cltoecur(); /* clears from current + pos to eoln. + */ + break; + case 1: + kd_clfrbcur(); /* clears from begin + of line to current + pos. + */ + break; + case 2: + kd_eraseln(); /* clear entire line */ + break; + default: + break; + } + esc_spt = esc_seq; + break; + case 'L': + if (number[0] == MACH_ATOI_DEFAULT) + kd_insln(1); + else + kd_insln(number[0]); + esc_spt = esc_seq; + break; + case 'M': + if (number[0] == MACH_ATOI_DEFAULT) + kd_delln(1); + else + kd_delln(number[0]); + esc_spt = esc_seq; + break; + case 'P': + if (number[0] == MACH_ATOI_DEFAULT) + kd_delch(1); + else + kd_delch(number[0]); + esc_spt = esc_seq; + break; + case 'S': + if (number[0] == MACH_ATOI_DEFAULT) + kd_scrollup(); + else + while (number[0]--) + kd_scrollup(); + esc_spt = esc_seq; + break; + case 'T': + if (number[0] == MACH_ATOI_DEFAULT) + kd_scrolldn(); + else + while (number[0]--) + kd_scrolldn(); + esc_spt = esc_seq; + break; + case 'X': + if (number[0] == MACH_ATOI_DEFAULT) + kd_erase(1); + else + kd_erase(number[0]); + esc_spt = esc_seq; + break; + case '\0': + break; /* not enough yet */ + default: + kd_putc(*cp); /* show inv character */ + esc_spt = esc_seq; /* inv entry, reset */ + break; + } + return; +} + +void +kd_tab(void) +{ + int i; + + for (i = 8 - (CURRENT_COLUMN(kd_curpos) % 8); i > 0; i--) { + kd_putc(' '); + } + +} + + +/* + * kd_cls: + * + * This function clears the screen with spaces and the current attribute. + * + * input : None + * output : Screen is cleared + * + */ +void +kd_cls(void) +{ + (*kd_dclear)(0, ONE_PAGE/ONE_SPACE, kd_attr); + return; +} + + +/* + * kd_home: + * + * This function will move the cursor to the home position on the screen, + * as well as set the internal cursor position (kd_curpos) to home. + * + * input : None + * output : Cursor position is moved + * + */ +void +kd_home(void) +{ + kd_setpos(0); + return; +} + + +/* + * kd_up: + * + * This function moves the cursor up one line position. + * + * input : None + * output : Cursor moves up one line, or screen is scrolled + * + */ +void +kd_up(void) +{ + if (kd_curpos < ONE_LINE) + kd_scrolldn(); + else + kd_setpos(kd_curpos - ONE_LINE); + return; +} + + +/* + * kd_down: + * + * This function moves the cursor down one line position. + * + * input : None + * output : Cursor moves down one line or the screen is scrolled + * + */ +void +kd_down(void) +{ + if (kd_curpos >= (ONE_PAGE - ONE_LINE)) + kd_scrollup(); + else + kd_setpos(kd_curpos + ONE_LINE); + return; +} + + +/* + * kd_right: + * + * This function moves the cursor one position to the right. + * + * input : None + * output : Cursor moves one position to the right + * + */ +void +kd_right(void) +{ + if (kd_curpos < (ONE_PAGE - ONE_SPACE)) + kd_setpos(kd_curpos + ONE_SPACE); + else { + kd_scrollup(); + kd_setpos(BEG_OF_LINE(kd_curpos)); + } + return; +} + + +/* + * kd_left: + * + * This function moves the cursor one position to the left. + * + * input : None + * output : Cursor moves one position to the left + * + */ +void +kd_left(void) +{ + if (0 < kd_curpos) + kd_setpos(kd_curpos - ONE_SPACE); + return; +} + + +/* + * kd_cr: + * + * This function moves the cursor to the beginning of the current + * line. + * + * input : None + * output : Cursor moves to the beginning of the current line + * + */ +void +kd_cr(void) +{ + kd_setpos(BEG_OF_LINE(kd_curpos)); + return; +} + + +/* + * kd_cltobcur: + * + * This function clears from the current cursor position to the bottom + * of the screen. + * + * input : None + * output : Screen is cleared from current cursor position to bottom + * + */ +void +kd_cltobcur(void) +{ + csrpos_t start; + int count; + + start = kd_curpos; + count = (ONE_PAGE - kd_curpos)/ONE_SPACE; + (*kd_dclear)(start, count, kd_attr); + return; +} + + +/* + * kd_cltopcur: + * + * This function clears from the current cursor position to the top + * of the screen. + * + * input : None + * output : Screen is cleared from current cursor position to top + * + */ +void +kd_cltopcur(void) +{ + int count; + + count = (kd_curpos + ONE_SPACE) / ONE_SPACE; + (*kd_dclear)(0, count, kd_attr); + return; +} + + +/* + * kd_cltoecur: + * + * This function clears from the current cursor position to eoln. + * + * input : None + * output : Line is cleared from current cursor position to eoln + * + */ +void +kd_cltoecur(void) +{ + csrpos_t i; + csrpos_t hold; + + hold = BEG_OF_LINE(kd_curpos) + ONE_LINE; + for (i = kd_curpos; i < hold; i += ONE_SPACE) { + (*kd_dput)(i, K_SPACE, kd_attr); + } +} + + +/* + * kd_clfrbcur: + * + * This function clears from the beginning of the line to the current + * cursor position. + * + * input : None + * output : Line is cleared from beginning to current position + * + */ +void +kd_clfrbcur(void) +{ + csrpos_t i; + + for (i = BEG_OF_LINE(kd_curpos); i <= kd_curpos; i += ONE_SPACE) { + (*kd_dput)(i, K_SPACE, kd_attr); + } +} + + +/* + * kd_delln: + * + * This function deletes 'number' lines on the screen by effectively + * scrolling the lines up and replacing the old lines with spaces. + * + * input : number of lines to delete + * output : lines appear to be deleted + * + */ +void +kd_delln(int number) +{ + csrpos_t to; + csrpos_t from; + int delbytes; /* num of bytes to delete */ + int count; /* num of words to move or fill */ + + if (number <= 0) + return; + + delbytes = number * ONE_LINE; + to = BEG_OF_LINE(kd_curpos); + if (to + delbytes >= ONE_PAGE) + delbytes = ONE_PAGE - to; + if (to + delbytes < ONE_PAGE) { + from = to + delbytes; + count = (ONE_PAGE - from) / ONE_SPACE; + (*kd_dmvup)(from, to, count); + } + + to = ONE_PAGE - delbytes; + count = delbytes / ONE_SPACE; + (*kd_dclear)(to, count, kd_attr); + return; +} + + +/* + * kd_insln: + * + * This function inserts a line above the current one by + * scrolling the current line and all the lines below it down. + * + * input : number of lines to insert + * output : New lines appear to be inserted + * + */ +void +kd_insln(int number) +{ + csrpos_t to; + csrpos_t from; + int count; + csrpos_t top; /* top of block to be moved */ + int insbytes; /* num of bytes inserted */ + + if (number <= 0) + return; + + top = BEG_OF_LINE(kd_curpos); + insbytes = number * ONE_LINE; + if (top + insbytes > ONE_PAGE) + insbytes = ONE_PAGE - top; + to = ONE_PAGE - ONE_SPACE; + from = to - insbytes; + if (from > top) { + count = (from - top + ONE_SPACE) / ONE_SPACE; + (*kd_dmvdown)(from, to, count); + } + + count = insbytes / ONE_SPACE; + (*kd_dclear)(top, count, kd_attr); + return; +} + + +/* + * kd_delch: + * + * This function deletes a number of characters from the current + * position in the line. + * + * input : number of characters to delete + * output : characters appear to be deleted + * + */ +void +kd_delch(int number) +{ + int count; /* num words moved/filled */ + int delbytes; /* bytes to delete */ + csrpos_t to; + csrpos_t from; + csrpos_t nextline; /* start of next line */ + + if (number <= 0) + return; + + nextline = BEG_OF_LINE(kd_curpos) + ONE_LINE; + delbytes = number * ONE_SPACE; + if (kd_curpos + delbytes > nextline) + delbytes = nextline - kd_curpos; + if (kd_curpos + delbytes < nextline) { + from = kd_curpos + delbytes; + to = kd_curpos; + count = (nextline - from) / ONE_SPACE; + (*kd_dmvup)(from, to, count); + } + + to = nextline - delbytes; + count = delbytes / ONE_SPACE; + (*kd_dclear)(to, count, kd_attr); + return; + +} + + +/* + * kd_erase: + * + * This function overwrites characters with a space starting with the + * current cursor position and ending in number spaces away. + * + * input : number of characters to erase + * output : characters appear to be blanked or erased + * + */ +void +kd_erase(int number) +{ + csrpos_t i; + csrpos_t stop; + + stop = kd_curpos + (ONE_SPACE * number); + if (stop > BEG_OF_LINE(kd_curpos) + ONE_LINE) + stop = BEG_OF_LINE(kd_curpos) + ONE_LINE; + for (i = kd_curpos; i < stop; i += ONE_SPACE) { + (*kd_dput)(i, K_SPACE, kd_attr); + } + return; +} + + +/* + * kd_eraseln: + * + * This function erases the current line with spaces. + * + * input : None + * output : Current line is erased + * + */ +void +kd_eraseln(void) +{ + csrpos_t i; + csrpos_t stop; + + stop = BEG_OF_LINE(kd_curpos) + ONE_LINE; + for (i = BEG_OF_LINE(kd_curpos); i < stop; i += ONE_SPACE) { + (*kd_dput)(i, K_SPACE, kd_attr); + } + return; +} + + +/* + * kd_insch: + * + * This function inserts a blank at the current cursor position + * and moves all other characters on the line over. + * + * input : number of blanks to insert + * output : Blanks are inserted at cursor position + * + */ +void +kd_insch(int number) +{ + csrpos_t to; + csrpos_t from; + int count; + csrpos_t nextline; /* start of next line */ + int insbytes; /* num of bytes inserted */ + + if (number <= 0) + return; + + nextline = BEG_OF_LINE(kd_curpos) + ONE_LINE; + insbytes = number * ONE_SPACE; + if (kd_curpos + insbytes > nextline) + insbytes = nextline - kd_curpos; + + to = nextline - ONE_SPACE; + from = to - insbytes; + if (from >= kd_curpos) { + count = (from - kd_curpos + ONE_SPACE) / ONE_SPACE; + (*kd_dmvdown)(from, to, count); + } + + count = insbytes / ONE_SPACE; + (*kd_dclear)(kd_curpos, count, kd_attr); + return; +} + + +/* + * kd_isupper, kd_islower: + * + * Didn't want to include ctype.h because it brings in stdio.h, and + * only want to see if the darn character is uppercase or lowercase. + * + * input : Character 'c' + * output : isuuper gives TRUE if character is uppercase, islower + * returns TRUE if character is lowercase + * + */ +boolean_t +kd_isupper(u_char c) +{ + if (('A' <= c) && (c <= 'Z')) + return(TRUE); + return(FALSE); +} + +boolean_t +kd_islower(u_char c) +{ + if (('a' <= c) && (c <= 'z')) + return(TRUE); + return(FALSE); +} + +/* + * kd_senddata: + * + * This function sends a byte to the keyboard RDWR port, but + * first waits until the input/output data buffer is clear before + * sending the data. Note that this byte can be either data or a + * keyboard command. + * + */ +void +kd_senddata(unsigned char ch) +{ + while (inb(K_STATUS) & K_IBUF_FUL) + ; + outb(K_RDWR, ch); + last_sent = ch; + return; +} + +/* + * kd_sendcmd: + * + * This function sends a command byte to the keyboard command + * port, but first waits until the input/output data buffer is + * clear before sending the data. + * + */ +void +kd_sendcmd(unsigned char ch) +{ + while (inb(K_STATUS) & K_IBUF_FUL) + ; + outb(K_CMD, ch); + return; +} + + +/* + * kd_getdata: + * + * This function returns a data byte from the keyboard RDWR port, + * after waiting until the port is flagged as having something to + * read. + */ +unsigned char +kd_getdata(void) +{ + while ((inb(K_STATUS) & K_OBUF_FUL) == 0) + ; + return(inb(K_RDWR)); +} + +void +kd_cmdreg_write(int val) +{ +int ch=KC_CMD_WRITE; + + while (inb(K_STATUS) & K_IBUF_FUL) + ; + outb(K_CMD, ch); + + while (inb(K_STATUS) & K_IBUF_FUL) + ; + outb(K_RDWR, val); +} + +void +kd_mouse_drain(void) +{ + int i; + while(inb(K_STATUS) & K_IBUF_FUL) + ; + while((i = inb(K_STATUS)) & K_OBUF_FUL) + printf("kbd: S = %x D = %x\n", i, inb(K_RDWR)); +} + +/* + * set_kd_state: + * + * Set kd_state and update the keyboard status LEDs. + */ +void +set_kd_state(int newstate) +{ + kd_state = newstate; + kd_setleds1(state2leds(newstate)); +} + +/* + * state2leds: + * + * Return a byte containing LED settings for the keyboard, given + * a state vector. + */ +u_char +state2leds(int state) +{ + u_char result = 0; + + if (state & KS_NLKED) + result |= K_LED_NUMLK; + if (state & KS_CLKED) + result |= K_LED_CAPSLK; + return(result); +} + +/* + * kd_setleds[12]: + * + * Set the keyboard LEDs according to the given byte. + */ +void +kd_setleds1(u_char val) +{ + if (kd_ack != NOT_WAITING) { +#ifdef MACH_KBD + printf("kd_setleds1: unexpected state (%d)\n", kd_ack); +#endif + return; + } + + kd_ack = SET_LEDS; + kd_nextled = val; + kd_senddata(K_CMD_LEDS); +} + +void +kd_setleds2(void) +{ + kd_senddata(kd_nextled); +} + + +/* + * cnsetleds: + * + * like kd_setleds[12], but not interrupt-based. + * Currently disabled because cngetc ignores caps lock and num + * lock anyway. + */ +void +cnsetleds(u_char val) +{ + kd_senddata(K_CMD_LEDS); + (void)kd_getdata(); /* XXX - assume is ACK */ + kd_senddata(val); + (void)kd_getdata(); /* XXX - assume is ACK */ +} + +void +kdreboot(void) +{ + (*kd_dreset)(); + +#ifndef BROKEN_KEYBOARD_RESET + kd_sendcmd(0xFE); /* XXX - magic # */ + delay(1000000); /* wait to see if anything happens */ +#endif + /* + * If that didn't work, then we'll just have to try and + * do it the hard way. + */ + cpu_shutdown(); +} + +static int which_button[] = {0, MOUSE_LEFT, MOUSE_MIDDLE, MOUSE_RIGHT}; +static struct mouse_motion moved; + +int +kd_kbd_magic(int scancode) +{ +int new_button = 0; + + if (kd_kbd_mouse == 2) + printf("sc = %x\n", scancode); + + switch (scancode) { +/* f1 f2 f3 */ + case 0x3d: + new_button++; + case 0x3c: + new_button++; + case 0x3b: + new_button++; + if (kd_kbd_magic_button && (new_button != kd_kbd_magic_button)) { + /* down w/o up */ + mouse_button(which_button[kd_kbd_magic_button], 1); + } + /* normal */ + if (kd_kbd_magic_button == new_button) { + mouse_button(which_button[new_button], 1); + kd_kbd_magic_button = 0; + } else { + mouse_button(which_button[new_button], 0); + kd_kbd_magic_button = new_button; + } + break; + +/* right left up down */ + case 0x4d: + moved.mm_deltaX = kd_kbd_magic_scale; + moved.mm_deltaY = 0; + mouse_moved(moved); + break; + case 0x4b: + moved.mm_deltaX = -kd_kbd_magic_scale; + moved.mm_deltaY = 0; + mouse_moved(moved); + break; + case 0x48: + moved.mm_deltaX = 0; + moved.mm_deltaY = kd_kbd_magic_scale; + mouse_moved(moved); + break; + case 0x50: + moved.mm_deltaX = 0; + moved.mm_deltaY = -kd_kbd_magic_scale; + mouse_moved(moved); + break; +/* home pageup end pagedown */ + case 0x47: + moved.mm_deltaX = -2*kd_kbd_magic_scale; + moved.mm_deltaY = 2*kd_kbd_magic_scale; + mouse_moved(moved); + break; + case 0x49: + moved.mm_deltaX = 2*kd_kbd_magic_scale; + moved.mm_deltaY = 2*kd_kbd_magic_scale; + mouse_moved(moved); + break; + case 0x4f: + moved.mm_deltaX = -2*kd_kbd_magic_scale; + moved.mm_deltaY = -2*kd_kbd_magic_scale; + mouse_moved(moved); + break; + case 0x51: + moved.mm_deltaX = 2*kd_kbd_magic_scale; + moved.mm_deltaY = -2*kd_kbd_magic_scale; + mouse_moved(moved); + break; + + default: + return 0; + } + return 1; +} + + + +/* + * Code specific to EGA/CGA/VGA boards. This code relies on the fact + * that the "slam" functions take a word count and ONE_SPACE takes up + * 1 word. + */ +#define SLAMBPW 2 /* bytes per word for "slam" fcns */ + +/* + * xga_getpos: + * + * This function returns the current hardware cursor position on the + * screen, scaled for compatibility with kd_curpos. + * + * input : None + * output : returns the value of cursor position on screen + * + */ +static csrpos_t +xga_getpos(void) + +{ + unsigned char low; + unsigned char high; + short pos; + + outb(kd_index_reg, C_HIGH); + high = inb(kd_io_reg); + outb(kd_index_reg, C_LOW); + low = inb(kd_io_reg); + pos = (0xff&low) + ((unsigned short)high<<8); + + return(ONE_SPACE * (csrpos_t)pos); +} + + +/* + * kd_xga_init: + * + * Initialization specific to character-based graphics adapters. + */ +void +kd_xga_init(void) +{ + unsigned char start, stop; + +#if 0 + unsigned char screen; + + /* XXX: this conflicts with read/writing the RTC */ + + outb(CMOS_ADDR, CMOS_EB); + screen = inb(CMOS_DATA) & CM_SCRMSK; + switch(screen) { + default: + printf("kd: unknown screen type, defaulting to EGA\n"); + /* FALLTHROUGH */ + case CM_EGA_VGA: +#endif + /* + * Here we'll want to query to bios on the card + * itself, because then we can figure out what + * type we have exactly. At this point we only + * know that the card is NOT CGA or MONO. For + * now, however, we assume backwards compatibility + * with 0xb8000 as the starting screen offset + * memory location for these cards. + * + */ + + vid_start = (u_char *)phystokv(EGA_START); + kd_index_reg = EGA_IDX_REG; + kd_io_reg = EGA_IO_REG; + kd_lines = 25; + kd_cols = 80; + kd_bitmap_start = 0xa0000; /* XXX - magic numbers */ + { /* XXX - is there a cleaner way to do this? */ + char *addr = (char *)phystokv(kd_bitmap_start); + int i; + for (i = 0; i < 200; i++) + addr[i] = 0x00; + } +#if 0 + break; + /* XXX: some buggy BIOSes report these... */ + case CM_CGA_40: + vid_start = (u_char *)phystokv(CGA_START); + kd_index_reg = CGA_IDX_REG; + kd_io_reg = CGA_IO_REG; + kd_lines = 25; + kd_cols = 40; + break; + case CM_CGA_80: + vid_start = (u_char *)phystokv(CGA_START); + kd_index_reg = CGA_IDX_REG; + kd_io_reg = CGA_IO_REG; + kd_lines = 25; + kd_cols = 80; + break; + case CM_MONO_80: + vid_start = (u_char *)phystokv(MONO_START); + kd_index_reg = MONO_IDX_REG; + kd_io_reg = MONO_IO_REG; + kd_lines = 25; + kd_cols = 80; + break; + } +#endif + + outb(kd_index_reg, C_START); + start = inb(kd_io_reg); + /* Make sure cursor is enabled */ + start &= ~0x20; + outb(kd_io_reg, start); + outb(kd_index_reg, C_STOP); + stop = inb(kd_io_reg); + + if (!start && !stop) + { + /* Some firmware seem not to be initializing the cursor size + * any more... Try using standard values. */ + outb(kd_index_reg, C_START); + outb(kd_io_reg, 14); + outb(kd_index_reg, C_STOP); + outb(kd_io_reg, 15); + } + + kd_setpos(xga_getpos()); +} + + +/* + * charput: + * + * Put attributed character for EGA/CGA/etc. + */ +static void +charput(csrpos_t pos, char ch, char chattr) +{ + *(vid_start + pos) = ch; + *(vid_start + pos + 1) = chattr; +} + + +/* + * charsetcursor: + * + * Set hardware cursor position for EGA/CGA/etc. + */ +static void +charsetcursor(csrpos_t newpos) +{ + short curpos; /* position, not scaled for attribute byte */ + + curpos = newpos / ONE_SPACE; + outb(kd_index_reg, C_HIGH); + outb(kd_io_reg, (u_char)(curpos>>8)); + outb(kd_index_reg, C_LOW); + outb(kd_io_reg, (u_char)(curpos&0xff)); + + kd_curpos = newpos; +} + + +/* + * charmvup: + * + * Block move up for EGA/CGA/etc. + */ +static void +charmvup(csrpos_t from, csrpos_t to, int count) +{ + kd_slmscu(vid_start+from, vid_start+to, count); +} + + +/* + * charmvdown: + * + * Block move down for EGA/CGA/etc. + */ +static void +charmvdown(csrpos_t from, csrpos_t to, int count) +{ + kd_slmscd(vid_start+from, vid_start+to, count); +} + + +/* + * charclear: + * + * Fast clear for CGA/EGA/etc. + */ +static void +charclear(csrpos_t to, int count, char chattr) +{ + kd_slmwd(vid_start+to, count, ((unsigned short)chattr<<8)+K_SPACE); +} + + +/* + * kd_noopreset: + * + * No-op reset routine for kd_dreset. + */ +static void +kd_noopreset(void) +{ +} + + +/* + * bmpput: Copy a character from the font to the frame buffer. + */ + +void +bmpput( + csrpos_t pos, + char ch, + char chattr) +{ + short xbit, ybit; /* u/l corner of char pos */ + u_char *to, *from; + short i, j; + u_char mask = (chattr == KA_REVERSE ? 0xff : 0); + + if ((u_char)ch >= chars_in_font) + ch = K_QUES; + + bmpch2bit(pos, &xbit, &ybit); + to = bit2fbptr(xbit, ybit); + from = font_start + ch * char_byte_width; + for (i = 0; i < char_height; ++i) { + for (j = 0; j < char_byte_width; ++j) + *(to+j) = *(from+j) ^ mask; + to += fb_byte_width; + from += font_byte_width; + } +} + +/* + * bmpcp1char: copy 1 char from one place in the frame buffer to + * another. + */ +static void +bmpcp1char( + csrpos_t from, + csrpos_t to) +{ + short from_xbit, from_ybit; + short to_xbit, to_ybit; + u_char *tp, *fp; + short i, j; + + bmpch2bit(from, &from_xbit, &from_ybit); + bmpch2bit(to, &to_xbit, &to_ybit); + + tp = bit2fbptr(to_xbit, to_ybit); + fp = bit2fbptr(from_xbit, from_ybit); + + for (i = 0; i < char_height; ++i) { + for (j = 0; j < char_byte_width; ++j) + *(tp+j) = *(fp+j); + tp += fb_byte_width; + fp += fb_byte_width; + } +} + +/* + * bmpvmup: Copy a block of character positions upwards. + */ +void +bmpmvup( + csrpos_t from, + csrpos_t to, + int count) +{ + short from_xbit, from_ybit; + short to_xbit, to_ybit; + short i; + + bmpch2bit(from, &from_xbit, &from_ybit); + bmpch2bit(to, &to_xbit, &to_ybit); + + if (from_xbit == xstart && to_xbit == xstart && count%kd_cols == 0) { + /* fast case - entire lines */ + from_xbit = to_xbit = 0; + bmppaintcsr(kd_curpos, char_black); /* don't copy cursor */ + count /= kd_cols; /* num lines */ + count *= fb_byte_width * (char_height+cursor_height); + kd_slmscu(bit2fbptr(from_xbit, from_ybit), + bit2fbptr(to_xbit, to_ybit), + count/SLAMBPW); + bmppaintcsr(kd_curpos, char_white); + } else { + /* slow case - everything else */ + for (i=0; i < count; ++i) { + bmpcp1char(from, to); + from += ONE_SPACE; + to += ONE_SPACE; + } + } +} + +/* + * bmpmvdown: copy a block of characters down. + */ +void +bmpmvdown( + csrpos_t from, + csrpos_t to, + int count) +{ + short from_xbit, from_ybit; + short to_xbit, to_ybit; + short i; + + bmpch2bit(from, &from_xbit, &from_ybit); + bmpch2bit(to, &to_xbit, &to_ybit); + + if (from_xbit == xstart + (kd_cols - 1) * char_width + && to_xbit == xstart + (kd_cols - 1) * char_width + && count%kd_cols == 0) { + /* fast case - entire lines*/ + from_xbit = to_xbit = 8 * (fb_byte_width - 1); + /* last byte on line */ + bmppaintcsr(kd_curpos, char_black); /* don't copy cursor */ + count /= kd_cols; /* num lines */ + count *= fb_byte_width * (char_height+cursor_height); + kd_slmscd(bit2fbptr(from_xbit, from_ybit), + bit2fbptr(to_xbit, to_ybit), + count/SLAMBPW); + bmppaintcsr(kd_curpos, char_white); + } else { + /* slow case - everything else */ + for (i=0; i < count; ++i) { + bmpcp1char(from, to); + from -= ONE_SPACE; + to -= ONE_SPACE; + } + } +} + +/* + * bmpclear: clear one or more character positions. + */ +void +bmpclear( + csrpos_t to, /* 1st char */ + int count, /* num chars */ + char chattr) /* reverse or normal */ +{ + short i; + u_short clearval; + u_short clearbyte = (chattr == KA_REVERSE ? char_white : char_black); + + clearval = (u_short)(clearbyte<<8) + clearbyte; + if (to == 0 && count >= kd_lines * kd_cols) { + /* fast case - entire page */ + kd_slmwd(vid_start, (fb_byte_width * fb_height)/SLAMBPW, + clearval); + } else + /* slow case */ + for (i = 0; i < count; ++i) { + bmpput(to, K_SPACE, chattr); + to += ONE_SPACE; + } +} + +/* + * bmpsetcursor: update the display and set the logical cursor. + */ +void +bmpsetcursor(csrpos_t pos) +{ + /* erase old cursor & paint new one */ + bmppaintcsr(kd_curpos, char_black); + bmppaintcsr(pos, char_white); + kd_curpos = pos; +} + +/* + * bmppaintcsr: paint cursor bits. + */ +void +bmppaintcsr( + csrpos_t pos, + u_char val) +{ + short xbit, ybit; + u_char *cp; + short line, byte; + + bmpch2bit(pos, &xbit, &ybit); + ybit += char_height; /* position at bottom of line */ + cp = bit2fbptr(xbit, ybit); + for (line = 0; line < cursor_height; ++line) { + for (byte = 0; byte < char_byte_width; ++byte) + *(cp+byte) = val; + cp += fb_byte_width; + } +} + +/* + * bmpch2bit: convert character position to x and y bit addresses. + * (0, 0) is the upper left corner. + */ +void +bmpch2bit( + csrpos_t pos, + short *xb, + short *yb) /* x, y bit positions, u/l corner */ +{ + short xch, ych; + + xch = (pos / ONE_SPACE) % kd_cols; + ych = pos / (ONE_SPACE * kd_cols); + *xb = xstart + xch * char_width; + *yb = ystart + ych * (char_height + cursor_height); +} + +/* + * bit2fbptr: return a pointer into the frame buffer corresponding to + * the bit address (x, y). + * Assumes that xb and yb don't point to the middle of a + * byte. + */ +u_char * +bit2fbptr( + short xb, + short yb) +{ + return(vid_start + yb * fb_byte_width + xb/8); +} + + +/* + * console stuff + */ + +/* + * XXX we assume that pcs *always* have a console + */ +int +kdcnprobe(struct consdev *cp) +{ + int maj, unit, pri; + + maj = 0; + unit = 0; + pri = CN_INTERNAL; + + cp->cn_dev = makedev(maj, unit); + cp->cn_pri = pri; + return 0; +} + +int +kdcninit(struct consdev *cp) +{ + kdinit(); + return 0; +} + +int +kdcngetc(dev_t dev, int wait) +{ + if (wait) { + int c; + while ((c = kdcnmaygetc()) < 0) + continue; + return c; + } + else + return kdcnmaygetc(); +} + +int +kdcnputc(dev_t dev, int c) +{ + if (!kd_initialized) + return -1; + + /* Note that tab is handled in kd_putc */ + if (c == '\n') + kd_putc('\r'); + kd_putc_esc(c); + + return 0; +} + +/* + * kdcnmaygetc: + * + * Get one character using polling, rather than interrupts. Used + * by the kernel debugger. Note that Caps Lock is ignored. + * Normally this routine is called with interrupts already + * disabled, but there is code in place so that it will be more + * likely to work even if interrupts are turned on. + */ +int +kdcnmaygetc(void) +{ + unsigned char c; + unsigned char scancode; + unsigned int char_idx; +#ifdef notdef + spl_t o_pri; +#endif + boolean_t up; + + if (! kd_initialized) + return -1; + + kd_extended = FALSE; +#ifdef notdef + o_pri = splhi(); +#endif + for ( ; ; ) { + if (!(inb(K_STATUS) & K_OBUF_FUL)) + return -1; + + up = FALSE; + /* + * We'd come here for mouse events in debugger, if + * the mouse were on. + */ + if ((inb(K_STATUS) & 0x20) == 0x20) { + printf("M%xP", inb(K_RDWR)); + continue; + } + scancode = inb(K_RDWR); + /* + * Handle extend modifier and + * ack/resend, otherwise we may never receive + * a key. + */ + if (scancode == K_EXTEND) { + kd_extended = TRUE; + continue; + } else if (scancode == K_RESEND) { + printf("cngetc: resend"); + kd_resend(); + continue; + } else if (scancode == K_ACKSC) { + printf("cngetc: handle_ack"); + kd_handle_ack(); + continue; + } + if (scancode & K_UP) { + up = TRUE; + scancode &= ~K_UP; + } + if (kd_kbd_mouse) + kd_kbd_magic(scancode); + if (scancode < NUMKEYS) { + /* Lookup in map, then process. */ + char_idx = kdstate2idx(kd_state, kd_extended); + c = key_map[scancode][char_idx]; + if (c == K_SCAN) { + c = key_map[scancode][++char_idx]; + kd_state = do_modifier(kd_state, c, up); +#ifdef notdef + cnsetleds(state2leds(kd_state)); +#endif + } else if (! up + && c == K_ESC + && key_map[scancode][char_idx+1] == 0x5b) { + /* As a convenience for the nice + people using our debugger, remap + some keys to the readline-like + shortcuts supported by dde. + + XXX This is a workaround for the + limited kernel getchar interface. + It is only used by the debugger. */ + c = key_map[scancode][char_idx+2]; + switch (c) { +#define _MAP(A,B,C) (C) +#define MAP(T) _MAP(T) +#define CTRL(c) ((c) & 0x1f) + case MAP(K_HOME): c = CTRL('a'); break; + case MAP(K_UA): c = CTRL('p'); break; + case MAP(K_LA): c = CTRL('b'); break; + case MAP(K_RA): c = CTRL('f'); break; + case MAP(K_DA): c = CTRL('n'); break; + case MAP(K_END): c = CTRL('e'); break; + /* delete */ + case 0x39: c = CTRL('d'); break; +#undef CTRL +#undef MAP +#undef _MAP + default: + /* Retain the old behavior. */ + c = K_ESC; + } + + return(c); + } else if (!up) { + /* regular key-down */ + if (c == K_CR) + c = K_LF; +#ifdef notdef + splx(o_pri); +#endif + return(c & 0177); + } + } + } +} -- cgit v1.2.1