Source to pexpert/i386/kd.c
/*
* Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* The contents of this file constitute Original Code as defined in and
* are subject to the Apple Public Source License Version 1.1 (the
* "License"). You may not use this file except in compliance with the
* License. Please obtain a copy of the License at
* http://www.apple.com/publicsource and read it before using this file.
*
* This Original Code and all software distributed under the License are
* distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
* License for the specific language governing rights and limitations
* under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
* @OSF_COPYRIGHT@
*/
/*
*/
/*
* 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 <string.h>
#include "kd.h"
#include <mach/i386/vm_param.h>
#define at386_io_lock_state()
#define at386_io_lock(op) (TRUE)
#define at386_io_unlock()
typedef unsigned short i386_ioport_t;
/* read a byte */
extern unsigned char inb(
i386_ioport_t port);
/* write a longword */
extern void outb(
i386_ioport_t port,
unsigned char datum);
extern __inline__ unsigned char inb(
i386_ioport_t port)
{
unsigned char datum;
__asm__ volatile("inb %1, %0" : "=a" (datum) : "d" (port));
return(datum);
}
extern __inline__ void outb(
i386_ioport_t port,
unsigned char datum)
{
__asm__ volatile("outb %0, %1" : : "a" (datum), "d" (port));
}
/* Forward */
extern void kd_sendcmd(unsigned char ch);
extern void kdreboot(void);
extern int kd_dogetc(int wait);
extern void kd_handle_ack(void);
extern void kd_resend(void);
extern int do_modifier(
int state,
Scancode c,
int up);
extern int kdcheckmagic(
Scancode sc,
int * regs);
extern int kdstate2idx(
int state,
int extended);
extern void kdinit(void);
extern void kd_belloff(void);
extern void kd_bellon(void);
extern void kd_senddata(unsigned char c);
extern unsigned char kd_getdata(void);
extern unsigned char kd_cmdreg_read(void);
extern void set_kd_state(
int newstate);
extern unsigned char state2leds(
int state);
extern void kd_setleds1(
unsigned char val);
extern void kd_setleds2(void);
extern void cnsetleds(
unsigned char val);
extern int kd_kbd_magic(
int scancode);
extern int cngetc(void);
extern int cnmaygetc(void);
extern void kdreboot(void);
extern int kd_dogetc(int wait);
/* reboot on CTL-ALT-DEL ? */
extern int rebootflag;
/* enter kernel debugger on CTR-ALT-d ? */
int kbdkdbflag = 1;
/* allow keyboard mouse ? */
int kbdmouseflag = 0;
/*
* 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 */
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;
unsigned char last_sent = 0;
unsigned 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.
*/
int kd_initialized = FALSE; /* driver initialized? */
int kd_extended = FALSE;
/*
* 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.
*/
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, K_ESC,NC,NC, K_ESC,NC,NC},
{K_ONE,NC,NC, K_BANG,NC,NC, K_ONE,NC,NC, 0x1b,0x4e,0x31, 0x1b,0x4e,0x21},
{K_TWO,NC,NC, K_ATSN,NC,NC, K_NUL,NC,NC, 0x1b,0x4e,0x32, 0x1b,0x4e,0x40},
{K_THREE,NC,NC, K_POUND,NC,NC, K_THREE,NC,NC, 0x1b,0x4e,0x33, 0x1b,0x4e,0x23},
{K_FOUR,NC,NC, K_DOLLAR,NC,NC, K_FOUR,NC,NC, 0x1b,0x4e,0x34, 0x1b,0x4e,0x24},
{K_FIVE,NC,NC, K_PERC,NC,NC, K_FIVE,NC,NC, 0x1b,0x4e,0x35, 0x1b,0x4e,0x25},
{K_SIX,NC,NC, K_CARET,NC,NC, K_RS,NC,NC, 0x1b,0x4e,0x36, 0x1b,0x4e,0x5e},
{K_SEVEN,NC,NC, K_AMPER,NC,NC, K_SEVEN,NC,NC, 0x1b,0x4e,0x37, 0x1b,0x4e,0x26},
{K_EIGHT,NC,NC, K_ASTER,NC,NC, K_EIGHT,NC,NC, 0x1b,0x4e,0x38, 0x1b,0x4e,0x2a},
{K_NINE,NC,NC, K_LPAREN,NC,NC, K_NINE,NC,NC, 0x1b,0x4e,0x39,0x1b,0x4e,0x28},
{K_ZERO,NC,NC, K_RPAREN,NC,NC, K_ZERO,NC,NC, 0x1b,0x4e,0x30,0x1b,0x4e,0x29},
{K_MINUS,NC,NC, K_UNDSC,NC,NC, K_US,NC,NC, 0x1b,0x4e,0x2d, 0x1b,0x4e,0x5f},
{K_EQL,NC,NC, K_PLUS,NC,NC, K_EQL,NC,NC, 0x1b,0x4e,0x3d, 0x1b,0x4e,0x2b},
{K_BS,NC,NC, K_BS,NC,NC, K_BS,NC,NC, K_BS,NC,NC, K_BS,NC,NC},
{K_HT,NC,NC, K_GS,NC,NC, K_HT,NC,NC, K_HT,NC,NC, K_GS,NC,NC},
{K_q,NC,NC, K_Q,NC,NC, K_DC1,NC,NC, 0x1b,0x4e,0x71, 0x1b,0x4e,0x51},
{K_w,NC,NC, K_W,NC,NC, K_ETB,NC,NC, 0x1b,0x4e,0x77, 0x1b,0x4e,0x57},
{K_e,NC,NC, K_E,NC,NC, K_ENQ,NC,NC, 0x1b,0x4e,0x65, 0x1b,0x4e,0x45},
{K_r,NC,NC, K_R,NC,NC, K_DC2,NC,NC, 0x1b,0x4e,0x72, 0x1b,0x4e,0x52},
{K_t,NC,NC, K_T,NC,NC, K_DC4,NC,NC, 0x1b,0x4e,0x74, 0x1b,0x4e,0x54},
{K_y,NC,NC, K_Y,NC,NC, K_EM,NC,NC, 0x1b,0x4e,0x79, 0x1b,0x4e,0x59},
{K_u,NC,NC, K_U,NC,NC, K_NAK,NC,NC, 0x1b,0x4e,0x75, 0x1b,0x4e,0x55},
{K_i,NC,NC, K_I,NC,NC, K_HT,NC,NC, 0x1b,0x4e,0x69, 0x1b,0x4e,0x49},
{K_o,NC,NC, K_O,NC,NC, K_SI,NC,NC, 0x1b,0x4e,0x6f, 0x1b,0x4e,0x4f},
{K_p,NC,NC, K_P,NC,NC, K_DLE,NC,NC, 0x1b,0x4e,0x70, 0x1b,0x4e,0x50},
{K_LBRKT,NC,NC, K_LBRACE,NC,NC, K_ESC,NC,NC, 0x1b,0x4e,0x5b, 0x1b,0x4e,0x7b},
{K_RBRKT,NC,NC, K_RBRACE,NC,NC, K_GS,NC,NC, 0x1b,0x4e,0x5d, 0x1b,0x4e,0x7d},
{K_CR,NC,NC, K_CR,NC,NC, K_CR,NC,NC, K_CR,NC,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,0x4e,0x61, 0x1b,0x4e,0x41},
{K_s,NC,NC, K_S,NC,NC, K_DC3,NC,NC, 0x1b,0x4e,0x73, 0x1b,0x4e,0x53},
{K_d,NC,NC, K_D,NC,NC, K_EOT,NC,NC, 0x1b,0x4e,0x65, 0x1b,0x4e,0x45},
{K_f,NC,NC, K_F,NC,NC, K_ACK,NC,NC, 0x1b,0x4e,0x66, 0x1b,0x4e,0x46},
{K_g,NC,NC, K_G,NC,NC, K_BEL,NC,NC, 0x1b,0x4e,0x67, 0x1b,0x4e,0x47},
{K_h,NC,NC, K_H,NC,NC, K_BS,NC,NC, 0x1b,0x4e,0x68, 0x1b,0x4e,0x48},
{K_j,NC,NC, K_J,NC,NC, K_LF,NC,NC, 0x1b,0x4e,0x6a, 0x1b,0x4e,0x4a},
{K_k,NC,NC, K_K,NC,NC, K_VT,NC,NC, 0x1b,0x4e,0x6b, 0x1b,0x4e,0x4b},
{K_l,NC,NC, K_L,NC,NC, K_FF,NC,NC, 0x1b,0x4e,0x6c, 0x1b,0x4e,0x4c},
{K_SEMI,NC,NC, K_COLON,NC,NC, K_SEMI,NC,NC, 0x1b,0x4e,0x3b, 0x1b,0x4e,0x3a},
{K_SQUOTE,NC,NC,K_DQUOTE,NC,NC,K_SQUOTE,NC,NC,0x1b,0x4e,0x27,0x1b,0x4e,0x22},
{K_GRAV,NC,NC, K_TILDE,NC,NC, K_RS,NC,NC, 0x1b,0x4e,0x60, 0x1b,0x4e,0x7e},
{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,0x4e,0x5c, 0x1b,0x4e,0x7c},
{K_z,NC,NC, K_Z,NC,NC, K_SUB,NC,NC, 0x1b,0x4e,0x7a, 0x1b,0x4e,0x5a},
{K_x,NC,NC, K_X,NC,NC, K_CAN,NC,NC, 0x1b,0x4e,0x78, 0x1b,0x4e,0x58},
{K_c,NC,NC, K_C,NC,NC, K_ETX,NC,NC, 0x1b,0x4e,0x63, 0x1b,0x4e,0x43},
{K_v,NC,NC, K_V,NC,NC, K_SYN,NC,NC, 0x1b,0x4e,0x76, 0x1b,0x4e,0x56},
{K_b,NC,NC, K_B,NC,NC, K_STX,NC,NC, 0x1b,0x4e,0x62, 0x1b,0x4e,0x42},
{K_n,NC,NC, K_N,NC,NC, K_SO,NC,NC, 0x1b,0x4e,0x6e, 0x1b,0x4e,0x4e},
{K_m,NC,NC, K_M,NC,NC, K_CR,NC,NC, 0x1b,0x4e,0x6d, 0x1b,0x4e,0x4d},
{K_COMMA,NC,NC, K_LTHN,NC,NC, K_COMMA,NC,NC, 0x1b,0x4e,0x2c, 0x1b,0x4e,0x3c},
{K_PERIOD,NC,NC, K_GTHN,NC,NC, K_PERIOD,NC,NC,0x1b,0x4e,0x2e,0x1b,0x4e,0x3e},
{K_SLASH,NC,NC, K_QUES,NC,NC, K_SLASH,NC,NC, 0x1b,0x4e,0x2f, 0x1b,0x4e,0x3f},
{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,0x4e,0x2a,0x1b,0x4e,0x2a},
{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, K_SPACE,NC,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_F1, K_F1S},
{K_F2, K_F2S, K_F2, K_F2, K_F2S},
{K_F3, K_F3S, K_F3, K_F3, K_F3S},
{K_F4, K_F4S, K_F4, K_F4, K_F4S},
{K_F5, K_F5S, K_F5, K_F5, K_F5S},
{K_F6, K_F6S, K_F6, K_F6, K_F6S},
{K_F7, K_F7S, K_F7, K_F7, K_F7S},
{K_F8, K_F8S, K_F8, K_F8, K_F8S},
{K_F9, K_F9S, K_F9, K_F9, K_F9S},
{K_F10, K_F10S, K_F10, K_F10, 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,0x37},
{K_UA, K_EIGHT,NC,NC, K_UA, K_UA, 0x1b,0x4e,0x38},
{K_PUP, K_NINE,NC,NC, K_PUP, K_PUP, 0x1b,0x4e,0x39},
{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,0x34},
{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,0x36},
{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,0x31},
{K_DA, K_TWO,NC,NC, K_DA, K_DA, 0x1b,0x4e,0x32},
{K_PDN, K_THREE,NC,NC, K_PDN, K_PDN, 0x1b,0x4e,0x33},
{K_INS, K_ZERO,NC,NC, K_INS, K_INS, 0x1b,0x4e,0x30},
{K_DEL,NC,NC, K_PERIOD,NC,NC, K_DEL,NC,NC, K_DEL,NC,NC, 0x1b,0x4e,0x2e},
{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_F11, K_F11S},
{K_F12, K_F12S, K_F12, K_F12, K_F12S}
};
extern void cnputc(unsigned char ch);
/*
* Switch for poll vs. interrupt.
*/
int kd_pollc = 0;
int (*cgetc)(
int wait) = kd_dogetc;
/* get a char. from console */
void (*cputc)(
char ch) = cnputc;
/* put a char. to console */
/*
* cngetc:
*
* 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
cngetc(void)
{
int ret;
ret = (*cgetc)(TRUE);
return ret;
}
int
cnmaygetc(void)
{
int ret;
ret = (*cgetc)(FALSE);
return ret;
}
int
kd_dogetc(
int wait)
{
unsigned char c;
unsigned char scancode;
unsigned int char_idx;
int up;
kdinit();
kd_extended = FALSE;
for ( ; ; ) {
while (!(inb(K_STATUS) & K_OBUF_FUL))
if (!wait)
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("kd_getc: resend"); */
kd_resend();
continue;
} else if (scancode == K_ACKSC) {
/* printf("kd_getc: 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) {
/* regular key-down */
if (c == K_CR)
c = K_LF;
#ifdef notdef
splx(o_pri);
#endif
return(c & 0177);
}
}
}
}
int old_kb_mode;
#if MACH_KDB
#define poll_spl() db_splhigh() /* prevent race w/ kdintr() */
#define poll_splx(s) db_splx(s)
#else /* MACH_KDB */
#define poll_spl() SPLKD()
#define poll_splx(s) splx(s)
#endif /* MACH_KDB */
void
cnpollc(
int on)
{
int old_spl; /* spl we're called at... */
if (cpu_number()) {
return;
}
if (on) {
old_spl = poll_spl();
old_kb_mode = kb_mode;
kb_mode = KB_ASCII;
poll_splx(old_spl);
kd_pollc++;
} else {
--kd_pollc;
old_spl = poll_spl();
kb_mode = old_kb_mode;
poll_splx(old_spl);
}
}
/*
* 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,
int 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.
*/
int
kdcheckmagic(
Scancode scancode,
int *regs)
{
static int magic_state = KS_NORMAL; /* like kd_state */
int up = FALSE;
extern int rebootflag;
if (scancode == 0x46 && kbdmouseflag) /* scroll lock */
{
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 */
if (!kbdkdbflag)
return(FALSE);
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 */
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.
*/
int
kdstate2idx(
int state, /* bit vector, not a state index */
int 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;
else if (state&KS_SHIFTED)
state_idx = SHIFT_STATE;
else if (state&KS_ALTED)
state_idx = ALT_STATE;
else if (state&KS_CTLED)
state_idx = CTRL_STATE;
}
return (CHARIDX(state_idx));
}
/*
* 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 */
unsigned char kd_stat;
if (kd_initialized)
return;
kd_initialized = TRUE;
/* get rid of any garbage in output buffer */
if (inb(K_STATUS) & K_OBUF_FUL)
(void)inb(K_RDWR);
cnsetleds(kd_state = KS_NORMAL);
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);
/* set_kd_state(KS_NORMAL); does only HALF of set-leds sequence -
leaves kbd dead */
/* get rid of any garbage in output buffer */
(void)inb(K_RDWR);
}
/*
* kd_belloff:
*
* This routine shuts the bell off, by sending the appropriate code
* to the speaker port.
*
* input : None
* output : bell is turned off
*
*/
void
kd_belloff(void)
{
unsigned char status;
status = (inb(K_PORTB) & ~(K_SPKRDATA | K_ENABLETMR2));
outb(K_PORTB, status);
}
/*
* 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;
}
/*
* 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;
}
/*
* 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);
}
/*
* 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));
}
unsigned char
kd_cmdreg_read(void)
{
int ch=KC_CMD_READ;
while (inb(K_STATUS) & (K_IBUF_FUL | K_OBUF_FUL));
outb(K_CMD, ch);
while ((inb(K_STATUS) & K_OBUF_FUL) == 0);
return(inb(K_RDWR));
}
void
kd_cmdreg_write(
unsigned char 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);
}
int kd_mouse_write_no_ack = 0;
int
kd_mouse_write(
unsigned char val)
{
int ch=0xd4; /* output byte to aux device (i.e. mouse) */
int ret = 0;
while (inb(K_STATUS) & K_IBUF_FUL);
outb(K_CMD, ch);
while (inb(K_STATUS) & K_IBUF_FUL);
outb(K_RDWR, val);
if (kd_mouse_write_no_ack) goto done;
while ((inb(K_STATUS) & K_OBUF_FUL) == 0);
if ((inb(K_STATUS) & 0x20) == 0x20) {
switch (ret = inb(K_RDWR)) {
case 0xfa:
break;
case 0xfe:
case 0xfc:
default:
printf("kd_mouse_write: saw %x for %x\n",
ret, val);
}
} else { /* abort */
printf("kd_mouse_write: sync error ??? on %x\n", val);
}
done:
return ret;
}
void
kd_mouse_read(
int no,
char *buf)
{
while (no-- > 0) {
while ((inb(K_STATUS) & K_OBUF_FUL) == 0);
/*
* We may have seen a mouse event.
*/
if ((inb(K_STATUS) & 0x20) == 0x20) {
*buf++ = (unsigned char)inb(K_RDWR);
} else { /* abort */
int junk = inb(K_RDWR);
printf("kd_mouse_read: sync error, received: 0x%x\n",
junk);
break;
}
}
}
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.
*/
unsigned char
state2leds(
int state)
{
unsigned 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(
unsigned char val)
{
if (kd_ack != NOT_WAITING) {
printf("kd_setleds1: unexpected state (%d)\n", kd_ack);
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(
unsigned 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_sendcmd(0xFE); /* XXX - magic # */
/*
* DRAT. We're still here. Let's try a "CPU shutdown", which consists
* of clearing the IDTR and causing an exception. It's in locore.s
*/
cpu_shutdown();
/*NOTREACHED*/
}
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 */
}
/* normal */
if (kd_kbd_magic_button == new_button) {
kd_kbd_magic_button = 0;
} else {
kd_kbd_magic_button = new_button;
}
break;
default:
return 0;
}
return 1;
}