aboutsummaryrefslogtreecommitdiff
path: root/i386/i386at/kd.c
diff options
context:
space:
mode:
authorPasha <pasha@member.fsf.org>2024-02-20 18:49:50 +0000
committerPasha <pasha@member.fsf.org>2024-02-20 18:49:50 +0000
commit5e0b8d508ed51004bd836384293be00950ee62c9 (patch)
treee3f16b1aa8b7177032ce3ec429fbad2b1d92a876 /i386/i386at/kd.c
downloadgnumach-riscv-5e0b8d508ed51004bd836384293be00950ee62c9.tar.gz
gnumach-riscv-5e0b8d508ed51004bd836384293be00950ee62c9.tar.bz2
init gnumach copy
Diffstat (limited to 'i386/i386at/kd.c')
-rw-r--r--i386/i386at/kd.c3059
1 files changed, 3059 insertions, 0 deletions
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 <sys/types.h>
+#include <kern/debug.h>
+#include <kern/mach_clock.h>
+#include <kern/printf.h>
+#include <device/conf.h>
+#include <device/tty.h>
+#include <device/io_req.h>
+#include <device/buf.h>
+#include <vm/vm_kern.h>
+#include <i386/db_interface.h>
+#include <i386/locore.h>
+#include <i386/loose_ends.h>
+#include <i386/vm_param.h>
+#include <i386/machspl.h>
+#include <i386/pio.h>
+#include <i386at/cram.h>
+#include <i386at/kd.h>
+#include <i386at/kd_event.h>
+#include <i386at/kd_mouse.h>
+#include <i386at/kdsoft.h>
+#include <device/cons.h>
+#include <util/atoi.h>
+
+#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);
+ }
+ }
+ }
+}