NetBSD/sys/arch/i386/isa/pccons.c
jdolecek 2b7d2123cd Make console polling (cnpollc/cngetc) work on IBM PS/2 keyboard controller
using level triggered interrupts, which livelocks calling intr routine
if the data register is not read in the interrupt routine, as it's case
when polling after interrupts are enabled during boot.

Block all interrupts when polling for keypress, and modify intr routine
to read and store value from data register. The latter one is to avoid
losing a keypress when one would manage to press a key when kernel is
not in spl-guarded code section.

Tested with classic pccons, 'pcconskbd at pckbc' and 'pckbd at pckbc'
configurations, on i386.
2001-07-31 13:15:28 +00:00

2719 lines
70 KiB
C

/* $NetBSD: pccons.c,v 1.149 2001/07/31 13:15:29 jdolecek Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Charles M. Hannum.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*-
* Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* William Jolitz and Don Ahn.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)pccons.c 5.11 (Berkeley) 5/21/91
*/
/*
* code to work keyboard & display for PC-style console
*
* "NPCCONSKBD > 0" means that we access the keyboard through the MI keyboard
* controller driver, ==0 that we access it directly.
* XXX Only one of these attachments can be used in one kernel configuration.
*/
#include "opt_ddb.h"
#include "opt_xserver.h"
#include "opt_compat_netbsd.h"
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/proc.h>
#include <sys/user.h>
#include <sys/select.h>
#include <sys/tty.h>
#include <sys/fcntl.h>
#include <sys/uio.h>
#include <sys/callout.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/syslog.h>
#include <sys/device.h>
#include <dev/cons.h>
#include "pc.h"
#if (NPCCONSKBD > 0)
#include <machine/bus.h>
#include <dev/ic/pckbcvar.h>
#else
/* consistency check: plain pccons can't coexist with pckbc */
#include "pckbc.h"
#if (NPCKBC > 0)
#error "(pc without pcconskbd) and pckbc can't coexist"
#endif
#endif /* NPCCONSKBD */
/* consistency check: pccons can't coexist with vga or pcdisplay */
#include "vga.h"
#include "pcdisplay.h"
#if (NVGA > 0) || (NPCDISPLAY > 0)
#error "pc and (vga or pcdisplay) can't coexist"
#endif
#include <machine/cpu.h>
#include <machine/intr.h>
#include <machine/pio.h>
#include <machine/pccons.h>
#include <machine/conf.h>
#include <dev/isa/isareg.h>
#include <dev/isa/isavar.h>
#include <dev/ic/pcdisplay.h>
#include <dev/ic/i8042reg.h>
#include <dev/pckbc/pckbdreg.h>
#define XFREE86_BUG_COMPAT
#ifndef BEEP_FREQ
#define BEEP_FREQ 1500
#endif
#ifndef BEEP_TIME
#define BEEP_TIME (hz/5)
#endif
#define PCBURST 128
/*
* Non-US keyboards definition
*/
#if defined(FRENCH_KBD) || defined(GERMAN_KBD) || defined(NORWEGIAN_KBD) || defined(FINNISH_KBD)
# define NONUS_KBD
# define DISPLAY_ISO8859
# define NUMERIC_SLASH_FIX
#endif
static u_short *Crtat; /* pointer to backing store */
static u_short *crtat; /* pointer to current char */
#if (NPCCONSKBD == 0)
static volatile u_char ack, nak; /* Don't ask. */
static int poll_data = -1;
#endif
static u_char async, kernel, polling; /* Really, you don't want to know. */
static u_char lock_state = 0x00; /* all off */
#if (NPCCONSKBD == 0)
static u_char old_lock_state = 0xff,
typematic_rate = 0xff, /* don't update until set by user */
old_typematic_rate = 0xff;
#endif
static u_short cursor_shape = 0xffff, /* don't update until set by user */
old_cursor_shape = 0xffff;
#ifdef XSERVER
int pc_xmode = 0;
#endif
int pccons_is_console = 0;
#if (NPCCONSKBD > 0)
static pckbc_tag_t kbctag;
static pckbc_slot_t kbcslot;
static int kbc_attached;
#endif
#define PCUNIT(x) (minor(x))
static struct video_state {
int cx, cy; /* escape parameters */
int row, col; /* current cursor position */
int nrow, ncol, nchr; /* current screen geometry */
u_char state; /* parser state */
#define VSS_ESCAPE 1
#define VSS_EBRACE 2
#define VSS_EPARAM 3
char so; /* in standout mode? */
char color; /* color or mono display */
char at; /* normal attributes */
char so_at; /* standout attributes */
} vs;
struct pc_softc {
struct device sc_dev;
void *sc_ih;
struct tty *sc_tty;
};
static struct callout async_update_ch = CALLOUT_INITIALIZER;
int pcprobe __P((struct device *, struct cfdata *, void *));
void pcattach __P((struct device *, struct device *, void *));
int pcintr __P((void *));
void pcinit __P((void));
struct cfattach pc_ca = {
sizeof(struct pc_softc), pcprobe, pcattach
};
extern struct cfdriver pc_cd;
#if (NPCCONSKBD > 0)
struct pcconskbd_softc {
struct device sc_dev;
};
int pcconskbdprobe __P((struct device *, struct cfdata *, void *));
void pcconskbdattach __P((struct device *, struct device *, void *));
void pcinput __P((void *, int));
struct cfattach pcconskbd_ca = {
sizeof(struct pcconskbd_softc), pcconskbdprobe, pcconskbdattach
};
extern struct cfdriver pcconskbd_cd;
#endif
#define COL 80
#define ROW 25
#define CHR 2
/*
* DANGER WIL ROBINSON -- the values of SCROLL, NUM, CAPS, and ALT are
* important.
*/
#define SCROLL 0x0001 /* stop output */
#define NUM 0x0002 /* numeric shift cursors vs. numeric */
#define CAPS 0x0004 /* caps shift -- swaps case of letter */
#define SHIFT 0x0008 /* keyboard shift */
#define CTL 0x0010 /* control shift -- allows ctl function */
#define ASCII 0x0020 /* ascii code for this key */
#define ALT 0x0080 /* alternate shift -- alternate chars */
#define FUNC 0x0100 /* function key */
#define KP 0x0200 /* Keypad keys */
#define NONE 0x0400 /* no function */
#ifdef NONUS_KBD
#define ALTGR 0x0040 /* Alt graphic */
#endif
static unsigned int addr_6845 = MONO_BASE;
#if (NPCCONSKBD == 0)
char *sget __P((void));
#endif
char *strans __P((u_char));
void sput __P((u_char *, int));
#ifdef XSERVER
void pc_xmode_on __P((void));
void pc_xmode_off __P((void));
#endif
void pcstart __P((struct tty *));
int pcparam __P((struct tty *, struct termios *));
#if (NPCCONSKBD == 0)
int kbd_cmd __P((u_char, u_char));
#endif
void set_cursor_shape __P((void));
#ifdef XSERVER
#ifdef XFREE86_BUG_COMPAT
void get_cursor_shape __P((void));
#endif
#endif
void do_async_update __P((void *));
void async_update __P((void));
#if (NPCCONSKBD > 0)
void update_leds __P((void));
#else
#define update_leds async_update
#endif
#if (NPCCONSKBD == 0)
static __inline int kbd_wait_output __P((void));
static __inline int kbd_wait_input __P((void));
static __inline void kbd_flush_input __P((void));
static u_char kbc_get8042cmd __P((void));
static int kbc_put8042cmd __P((u_char));
#endif
void pccnprobe __P((struct consdev *));
void pccninit __P((struct consdev *));
void pccnputc __P((dev_t, int));
int pccngetc __P((dev_t));
void pccnpollc __P((dev_t, int));
#if (NPCCONSKBD == 0)
#define KBD_DELAY \
{ u_char x = inb(0x84); (void) x; } \
{ u_char x = inb(0x84); (void) x; } \
{ u_char x = inb(0x84); (void) x; } \
{ u_char x = inb(0x84); (void) x; } \
{ u_char x = inb(0x84); (void) x; } \
{ u_char x = inb(0x84); (void) x; }
static __inline int
kbd_wait_output()
{
u_int i;
for (i = 100000; i; i--)
if ((inb(IO_KBD + KBSTATP) & KBS_IBF) == 0) {
KBD_DELAY;
return (1);
}
return (0);
}
static __inline int
kbd_wait_input()
{
u_int i;
for (i = 100000; i; i--)
if ((inb(IO_KBD + KBSTATP) & KBS_DIB) != 0) {
KBD_DELAY;
return (1);
}
return (0);
}
static __inline void
kbd_flush_input()
{
u_int i;
for (i = 10; i; i--) {
if ((inb(IO_KBD + KBSTATP) & KBS_DIB) == 0)
return;
KBD_DELAY;
(void) inb(IO_KBD + KBDATAP);
}
}
#if 1
/*
* Get the current command byte.
*/
static u_char
kbc_get8042cmd()
{
if (!kbd_wait_output())
return (-1);
outb(IO_KBD + KBCMDP, K_RDCMDBYTE);
if (!kbd_wait_input())
return (-1);
return (inb(IO_KBD + KBDATAP));
}
#endif
/*
* Pass command byte to keyboard controller (8042).
*/
static int
kbc_put8042cmd(val)
u_char val;
{
if (!kbd_wait_output())
return (0);
outb(IO_KBD + KBCMDP, K_LDCMDBYTE);
if (!kbd_wait_output())
return (0);
outb(IO_KBD + KBOUTP, val);
return (1);
}
/*
* Pass command to keyboard itself
*/
int
kbd_cmd(val, polling)
u_char val;
u_char polling;
{
u_int retries = 3;
register u_int i;
do {
if (!kbd_wait_output())
return (0);
ack = nak = 0;
outb(IO_KBD + KBOUTP, val);
if (polling)
for (i = 100000; i; i--) {
if (inb(IO_KBD + KBSTATP) & KBS_DIB) {
register u_char c;
KBD_DELAY;
c = inb(IO_KBD + KBDATAP);
if (c == KBR_ACK || c == KBR_ECHO) {
ack = 1;
return (1);
}
if (c == KBR_RESEND) {
nak = 1;
break;
}
#ifdef DIAGNOSTIC
printf("kbd_cmd: input char %x lost\n", c);
#endif
}
}
else
for (i = 100000; i; i--) {
(void) inb(IO_KBD + KBSTATP);
if (ack)
return (1);
if (nak)
break;
}
if (!nak)
return (0);
} while (--retries);
return (0);
}
#endif /* NPCCONSKBD == 0 */
void
set_cursor_shape()
{
register int iobase = addr_6845;
outb(iobase, 10);
outb(iobase+1, cursor_shape >> 8);
outb(iobase, 11);
outb(iobase+1, cursor_shape);
old_cursor_shape = cursor_shape;
}
#ifdef XSERVER
#ifdef XFREE86_BUG_COMPAT
void
get_cursor_shape()
{
register int iobase = addr_6845;
outb(iobase, 10);
cursor_shape = inb(iobase+1) << 8;
outb(iobase, 11);
cursor_shape |= inb(iobase+1);
/*
* real 6845's, as found on, MDA, Hercules or CGA cards, do
* not support reading the cursor shape registers. the 6845
* tri-states it's data bus. This is _normally_ read by the
* cpu as either 0x00 or 0xff.. in which case we just use
* a line cursor.
*/
if (cursor_shape == 0x0000 || cursor_shape == 0xffff)
cursor_shape = 0x0b10;
else
cursor_shape &= 0x1f1f;
}
#endif /* XFREE86_BUG_COMPAT */
#endif /* XSERVER */
void
do_async_update(v)
void *v;
{
#if (NPCCONSKBD == 0)
u_char poll = v ? 1 : 0;
#endif
int pos;
static int old_pos = -1;
async = 0;
#if (NPCCONSKBD == 0)
if (lock_state != old_lock_state) {
old_lock_state = lock_state;
if (!kbd_cmd(KBC_MODEIND, poll) ||
!kbd_cmd(lock_state, poll)) {
printf("pc: timeout updating leds\n");
(void) kbd_cmd(KBC_ENABLE, poll);
}
}
if (typematic_rate != old_typematic_rate) {
old_typematic_rate = typematic_rate;
if (!kbd_cmd(KBC_TYPEMATIC, poll) ||
!kbd_cmd(typematic_rate, poll)) {
printf("pc: timeout updating typematic rate\n");
(void) kbd_cmd(KBC_ENABLE, poll);
}
}
#else
/*
* If the mi pckbc driver is used, keyboard commands are handled
* there. The commands are issued synchronously (in update_leds()
* and pcioctl()).
*/
#endif
#ifdef XSERVER
if (pc_xmode > 0)
return;
#endif
pos = crtat - Crtat;
if (pos != old_pos) {
register int iobase = addr_6845;
outb(iobase, 14);
outb(iobase+1, pos >> 8);
outb(iobase, 15);
outb(iobase+1, pos);
old_pos = pos;
}
if (cursor_shape != old_cursor_shape)
set_cursor_shape();
}
void
async_update()
{
if (kernel || polling) {
if (async)
callout_stop(&async_update_ch);
do_async_update((void *)1);
} else {
if (async)
return;
async = 1;
callout_reset(&async_update_ch, 1, do_async_update, NULL);
}
}
#if (NPCCONSKBD > 0)
void update_leds()
{
u_char cmd[2];
cmd[0] = KBC_MODEIND;
cmd[1] = lock_state & 7;
pckbc_enqueue_cmd(kbctag, kbcslot, cmd, 2, 0, 0, 0);
}
#endif
/*
* these are both bad jokes
*/
int
pcprobe(parent, match, aux)
struct device *parent;
struct cfdata *match;
void *aux;
{
struct isa_attach_args *ia = aux;
#if (NPCCONSKBD == 0)
u_int i;
#else
u_char cmd[2], resp[1];
int res;
#endif
#if (NPCCONSKBD == 0)
/* Enable interrupts and keyboard, etc. */
if (!kbc_put8042cmd(CMDBYTE)) {
printf("pcprobe: command error\n");
return (0);
}
#else
if (!kbc_attached) {
printf("pcprobe: no keyboard\n");
return (0);
}
#endif
#if 1
/* Flush any garbage. */
#if (NPCCONSKBD == 0)
kbd_flush_input();
#else
pckbc_flush(kbctag, kbcslot);
#endif
/* Reset the keyboard. */
#if (NPCCONSKBD == 0)
if (!kbd_cmd(KBC_RESET, 1)) {
printf("pcprobe: reset error %d\n", 1);
goto lose;
}
for (i = 600000; i; i--)
if ((inb(IO_KBD + KBSTATP) & KBS_DIB) != 0) {
KBD_DELAY;
break;
}
if (i == 0 || inb(IO_KBD + KBDATAP) != KBR_RSTDONE) {
printf("pcprobe: reset error %d\n", 2);
goto lose;
}
#else
cmd[0] = KBC_RESET;
res = pckbc_poll_cmd(kbctag, kbcslot, cmd, 1, 1, resp, 1);
if (res) {
printf("pcprobe: reset error %d\n", 1);
/*
* XXX The keyboard is not present. Try to set the
* controller to "translating" anyway in case it is
* connected later. This should be done in attach().
*/
(void) pckbc_xt_translation(kbctag, kbcslot, 1);
goto lose;
}
if (resp[0] != KBR_RSTDONE) {
printf("pcprobe: reset error %d\n", 2);
goto lose;
}
#endif
/*
* Some keyboards seem to leave a second ack byte after the reset.
* This is kind of stupid, but we account for them anyway by just
* flushing the buffer.
*/
#if (NPCCONSKBD == 0)
kbd_flush_input();
#else
pckbc_flush(kbctag, kbcslot);
#endif
/* Just to be sure. */
#if (NPCCONSKBD == 0)
if (!kbd_cmd(KBC_ENABLE, 1)) {
printf("pcprobe: reset error %d\n", 3);
goto lose;
}
#else
cmd[0] = KBC_ENABLE;
res = pckbc_poll_cmd(kbctag, kbcslot, cmd, 1, 0, 0, 0);
if (res) {
printf("pcprobe: reset error %d\n", 3);
goto lose;
}
#endif
/*
* Some keyboard/8042 combinations do not seem to work if the keyboard
* is set to table 1; in fact, it would appear that some keyboards just
* ignore the command altogether. So by default, we use the AT scan
* codes and have the 8042 translate them. Unfortunately, this is
* known to not work on some PS/2 machines. We try desparately to deal
* with this by checking the (lack of a) translate bit in the 8042 and
* attempting to set the keyboard to XT mode. If this all fails, well,
* tough luck.
*
* XXX It would perhaps be a better choice to just use AT scan codes
* and not bother with this.
*/
#if (NPCCONSKBD == 0)
if (kbc_get8042cmd() & KC8_TRANS) {
/* The 8042 is translating for us; use AT codes. */
if (!kbd_cmd(KBC_SETTABLE, 1) || !kbd_cmd(2, 1)) {
printf("pcprobe: reset error %d\n", 4);
goto lose;
}
} else {
/* Stupid 8042; set keyboard to XT codes. */
if (!kbd_cmd(KBC_SETTABLE, 1) || !kbd_cmd(1, 1)) {
printf("pcprobe: reset error %d\n", 5);
goto lose;
}
}
#else
if (pckbc_xt_translation(kbctag, kbcslot, 1)) {
/* The 8042 is translating for us; use AT codes. */
cmd[0] = KBC_SETTABLE;
cmd[1] = 2;
res = pckbc_poll_cmd(kbctag, kbcslot, cmd, 2, 0, 0, 0);
if (res) {
printf("pcprobe: reset error %d\n", 4);
goto lose;
}
} else {
/* Stupid 8042; set keyboard to XT codes. */
cmd[0] = KBC_SETTABLE;
cmd[1] = 1;
res = pckbc_poll_cmd(kbctag, kbcslot, cmd, 2, 0, 0, 0);
if (res) {
printf("pcprobe: reset error %d\n", 5);
goto lose;
}
}
#endif
lose:
/*
* Technically, we should probably fail the probe. But we'll be nice
* and allow keyboard-less machines to boot with the console.
*/
#endif /* 1 */
#if (NPCCONSKBD > 0)
ia->ia_iosize = 0;
#else
ia->ia_iosize = 16;
#endif
ia->ia_msize = 0;
return (1);
}
void
pcattach(parent, self, aux)
struct device *parent, *self;
void *aux;
{
struct pc_softc *sc = (void *)self;
#if (NPCCONSKBD == 0)
struct isa_attach_args *ia = aux;
#endif
if (crtat == 0)
pcinit();
printf(": %s\n", vs.color ? "color" : "mono");
do_async_update((void *)1);
#if (NPCCONSKBD > 0)
pckbc_set_inputhandler(kbctag, kbcslot, pcinput, sc, sc->sc_dev.dv_xname);
#else
sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE,
IPL_TTY, pcintr, sc);
/*
* Look for children of the keyboard controller.
* XXX Really should decouple keyboard controller
* from the console code.
*/
while (config_found(self, ia->ia_ic, NULL) != NULL) { /* XXX */
/* Will break when no more children. */
;
}
#endif
if (pccons_is_console) {
int maj;
/* Locate the major number. */
for (maj = 0; maj < nchrdev; maj++)
if (cdevsw[maj].d_open == pcopen)
break;
/* There can be only one, but it can have any unit number. */
cn_tab->cn_dev = makedev(maj, sc->sc_dev.dv_unit);
printf("%s: console\n", sc->sc_dev.dv_xname);
}
}
#if (NPCCONSKBD > 0)
int
pcconskbdprobe(parent, match, aux)
struct device *parent;
struct cfdata *match;
void *aux;
{
struct pckbc_attach_args *pka = aux;
if (pka->pa_slot != PCKBC_KBD_SLOT)
return (0);
return (1);
}
void
pcconskbdattach(parent, self, aux)
struct device *parent, *self;
void *aux;
{
struct pckbc_attach_args *pka = aux;
printf("\n");
kbctag = pka->pa_tag;
kbcslot = pka->pa_slot;
kbc_attached = 1;
}
int
pcconskbd_cnattach(tag, slot)
pckbc_tag_t tag;
pckbc_slot_t slot;
{
kbctag = tag;
kbcslot = slot;
kbc_attached = 1;
return (0);
}
#endif
int
pcopen(dev, flag, mode, p)
dev_t dev;
int flag, mode;
struct proc *p;
{
struct pc_softc *sc;
int unit = PCUNIT(dev);
struct tty *tp;
if (unit >= pc_cd.cd_ndevs)
return (ENXIO);
sc = pc_cd.cd_devs[unit];
if (sc == 0)
return (ENXIO);
if (!sc->sc_tty) {
tp = sc->sc_tty = ttymalloc();
tty_attach(tp);
} else
tp = sc->sc_tty;
tp->t_oproc = pcstart;
tp->t_param = pcparam;
tp->t_dev = dev;
if ((tp->t_state & TS_ISOPEN) == 0) {
ttychars(tp);
tp->t_iflag = TTYDEF_IFLAG;
tp->t_oflag = TTYDEF_OFLAG;
tp->t_cflag = TTYDEF_CFLAG;
tp->t_lflag = TTYDEF_LFLAG;
tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
pcparam(tp, &tp->t_termios);
ttsetwater(tp);
} else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0)
return (EBUSY);
tp->t_state |= TS_CARR_ON;
return ((*tp->t_linesw->l_open)(dev, tp));
}
int
pcclose(dev, flag, mode, p)
dev_t dev;
int flag, mode;
struct proc *p;
{
struct pc_softc *sc = pc_cd.cd_devs[PCUNIT(dev)];
struct tty *tp = sc->sc_tty;
if (tp == NULL)
return (0);
(*tp->t_linesw->l_close)(tp, flag);
ttyclose(tp);
#ifdef notyet /* XXX */
ttyfree(tp);
#endif
return (0);
}
int
pcread(dev, uio, flag)
dev_t dev;
struct uio *uio;
int flag;
{
struct pc_softc *sc = pc_cd.cd_devs[PCUNIT(dev)];
struct tty *tp = sc->sc_tty;
return ((*tp->t_linesw->l_read)(tp, uio, flag));
}
int
pcwrite(dev, uio, flag)
dev_t dev;
struct uio *uio;
int flag;
{
struct pc_softc *sc = pc_cd.cd_devs[PCUNIT(dev)];
struct tty *tp = sc->sc_tty;
return ((*tp->t_linesw->l_write)(tp, uio, flag));
}
int
pcpoll(dev, events, p)
dev_t dev;
int events;
struct proc *p;
{
struct pc_softc *sc = pc_cd.cd_devs[PCUNIT(dev)];
struct tty *tp = sc->sc_tty;
return ((*tp->t_linesw->l_poll)(tp, events, p));
}
struct tty *
pctty(dev)
dev_t dev;
{
struct pc_softc *sc = pc_cd.cd_devs[PCUNIT(dev)];
struct tty *tp = sc->sc_tty;
return (tp);
}
/*
* Got a console receive interrupt -
* the console processor wants to give us a character.
* Catch the character, and see who it goes to.
*/
#if (NPCCONSKBD > 0)
void
pcinput(arg, data)
void *arg;
int data;
{
struct pc_softc *sc = arg;
register struct tty *tp = sc->sc_tty;
u_char *cp;
if (!tp || (tp->t_state & TS_ISOPEN) == 0)
return;
cp = strans(data);
if (cp)
do
(*tp->t_linesw->l_rint)(*cp++, tp);
while (*cp);
}
#else
int
pcintr(arg)
void *arg;
{
struct pc_softc *sc = arg;
register struct tty *tp = sc->sc_tty;
u_char *cp;
if ((inb(IO_KBD + KBSTATP) & KBS_DIB) == 0)
return (0);
do {
cp = sget();
if (polling) {
poll_data = *cp;
return (1);
}
if (!tp || (tp->t_state & TS_ISOPEN) == 0)
return (1);
if (cp)
do
(*tp->t_linesw->l_rint)(*cp++, tp);
while (*cp);
} while (inb(IO_KBD + KBSTATP) & KBS_DIB);
return (1);
}
#endif
int
pcioctl(dev, cmd, data, flag, p)
dev_t dev;
u_long cmd;
caddr_t data;
int flag;
struct proc *p;
{
struct pc_softc *sc = pc_cd.cd_devs[PCUNIT(dev)];
struct tty *tp = sc->sc_tty;
int error;
error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, p);
if (error >= 0)
return (error);
error = ttioctl(tp, cmd, data, flag, p);
if (error >= 0)
return (error);
switch (cmd) {
#ifdef XSERVER
case CONSOLE_X_MODE_ON:
pc_xmode_on();
ttyflush(tp, FREAD);
return (0);
case CONSOLE_X_MODE_OFF:
pc_xmode_off();
ttyflush(tp, FREAD);
return (0);
case CONSOLE_X_BELL:
/*
* If set, data is a pointer to a length 2 array of
* integers. data[0] is the pitch in Hz and data[1]
* is the duration in msec.
*/
if (data)
sysbeep(((int*)data)[0],
(((int*)data)[1] * hz) / 1000);
else
sysbeep(BEEP_FREQ, BEEP_TIME);
return (0);
#endif /* XSERVER */
case CONSOLE_SET_TYPEMATIC_RATE: {
u_char rate;
if (!data)
return (EINVAL);
rate = *((u_char *)data);
/*
* Check that it isn't too big (which would cause it to be
* confused with a command).
*/
if (rate & 0x80)
return (EINVAL);
#if (NPCCONSKBD > 0)
{
u_char cmd[2];
cmd[0] = KBC_TYPEMATIC;
cmd[1] = rate;
return (pckbc_enqueue_cmd(kbctag, kbcslot, cmd, 2, 0,
1, 0));
}
#else
typematic_rate = rate;
async_update();
return (0);
#endif
}
default:
return (ENOTTY);
}
#ifdef DIAGNOSTIC
panic("pcioctl: impossible");
#endif
}
void
pcstart(tp)
struct tty *tp;
{
struct clist *cl;
int s, len;
u_char buf[PCBURST];
s = spltty();
if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))
goto out;
tp->t_state |= TS_BUSY;
splx(s);
lock_state &= ~SCROLL;
/*
* We need to do this outside spl since it could be fairly
* expensive and we don't want our serial ports to overflow.
*/
cl = &tp->t_outq;
len = q_to_b(cl, buf, PCBURST);
sput(buf, len);
s = spltty();
tp->t_state &= ~TS_BUSY;
if (cl->c_cc) {
tp->t_state |= TS_TIMEOUT;
callout_reset(&tp->t_rstrt_ch, 1, ttrstrt, tp);
}
if (cl->c_cc <= tp->t_lowat) {
if (tp->t_state & TS_ASLEEP) {
tp->t_state &= ~TS_ASLEEP;
wakeup(cl);
}
selwakeup(&tp->t_wsel);
}
out:
splx(s);
}
void
pcstop(tp, flag)
struct tty *tp;
int flag;
{
lock_state |= SCROLL;
async_update();
}
int
pccnattach()
{
static struct consdev pccons = {
NULL, NULL, pccngetc, pccnputc, pccnpollc,
NULL, NODEV, CN_NORMAL
};
cn_tab = &pccons;
pccons_is_console = 1;
return (0);
}
/* ARGSUSED */
void
pccnputc(dev, c)
dev_t dev;
int c;
{
u_char oldkernel = kernel;
char help = c;
kernel = 1;
if (help == '\n')
sput("\r\n", 2);
else
sput(&help, 1);
kernel = oldkernel;
}
/*
* Note: the spl games here are to deal with some strange PC kbd controllers
* in some system configurations.
* This is not canonical way to handle polling input.
*/
/* ARGSUSED */
int
pccngetc(dev)
dev_t dev;
{
register char *cp;
#ifdef XSERVER
if (pc_xmode > 0)
return (0);
#endif
do {
/* wait for byte */
#if (NPCCONSKBD == 0)
int s = splhigh();
if (poll_data != -1) {
int data = poll_data;
poll_data = -1;
splx(s);
return (data);
}
while ((inb(IO_KBD + KBSTATP) & KBS_DIB) == 0);
/* see if it's worthwhile */
cp = sget();
splx(s);
#else
int data;
do {
data = pckbc_poll_data(kbctag, kbcslot);
} while (data == -1);
cp = strans(data);
#endif
} while (!cp);
if (*cp == '\r')
return ('\n');
return (*cp);
}
void
pccnpollc(dev, on)
dev_t dev;
int on;
{
polling = on;
#if (NPCCONSKBD > 0)
pckbc_set_poll(kbctag, kbcslot, on);
#else
if (on)
poll_data = -1;
else {
int unit;
struct pc_softc *sc;
int s;
/*
* If disabling polling on a device that's been configured,
* make sure there are no bytes left in the FIFO, holding up
* the interrupt line. Otherwise we won't get any further
* interrupts.
*/
unit = PCUNIT(dev);
if (pc_cd.cd_ndevs > unit) {
sc = pc_cd.cd_devs[unit];
if (sc != 0) {
s = spltty();
pcintr(sc);
splx(s);
}
}
}
#endif
}
/*
* Set line parameters.
*/
int
pcparam(tp, t)
struct tty *tp;
struct termios *t;
{
tp->t_ispeed = t->c_ispeed;
tp->t_ospeed = t->c_ospeed;
tp->t_cflag = t->c_cflag;
return (0);
}
void
pcinit()
{
u_short volatile *cp;
u_short was;
unsigned cursorat;
cp = ISA_HOLE_VADDR(CGA_BUF);
was = *cp;
*cp = (u_short) 0xA55A;
if (*cp != 0xA55A) {
cp = ISA_HOLE_VADDR(MONO_BUF);
addr_6845 = MONO_BASE;
vs.color = 0;
} else {
*cp = was;
addr_6845 = CGA_BASE;
vs.color = 1;
}
/* Extract cursor location */
outb(addr_6845, 14);
cursorat = inb(addr_6845+1) << 8;
outb(addr_6845, 15);
cursorat |= inb(addr_6845+1);
if (cursorat > COL * ROW)
cursorat = 0;
#ifdef FAT_CURSOR
cursor_shape = 0x0012;
#endif
Crtat = (u_short *)cp;
crtat = (u_short *)(cp + cursorat);
vs.ncol = COL;
vs.nrow = ROW;
vs.nchr = COL * ROW;
vs.at = FG_LIGHTGREY | BG_BLACK;
if (vs.color == 0)
vs.so_at = FG_BLACK | BG_LIGHTGREY;
else
vs.so_at = FG_YELLOW | BG_BLACK;
fillw((vs.at << 8) | ' ', crtat, vs.nchr - cursorat);
}
#define wrtchar(c, at) do {\
char *cp = (char *)crtat; *cp++ = (c); *cp = (at); crtat++; vs.col++; \
} while (0)
/* translate ANSI color codes to standard pc ones */
static char fgansitopc[] = {
FG_BLACK, FG_RED, FG_GREEN, FG_BROWN, FG_BLUE,
FG_MAGENTA, FG_CYAN, FG_LIGHTGREY
};
static char bgansitopc[] = {
BG_BLACK, BG_RED, BG_GREEN, BG_BROWN, BG_BLUE,
BG_MAGENTA, BG_CYAN, BG_LIGHTGREY
};
#ifdef DISPLAY_ISO8859
static u_char iso2ibm437[] =
{
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0xff, 0xad, 0x9b, 0x9c, 0, 0x9d, 0, 0x40,
0x6f, 0x63, 0x61, 0xae, 0, 0, 0, 0,
0xf8, 0xf1, 0xfd, 0x33, 0, 0xe6, 0, 0xfa,
0, 0x31, 0x6f, 0xaf, 0xac, 0xab, 0, 0xa8,
0x41, 0x41, 0x41, 0x41, 0x8e, 0x8f, 0x92, 0x80,
0x45, 0x90, 0x45, 0x45, 0x49, 0x49, 0x49, 0x49,
0x81, 0xa5, 0x4f, 0x4f, 0x4f, 0x4f, 0x99, 0x4f,
0x4f, 0x55, 0x55, 0x55, 0x9a, 0x59, 0, 0xe1,
0x85, 0xa0, 0x83, 0x61, 0x84, 0x86, 0x91, 0x87,
0x8a, 0x82, 0x88, 0x89, 0x8d, 0xa1, 0x8c, 0x8b,
0, 0xa4, 0x95, 0xa2, 0x93, 0x6f, 0x94, 0x6f,
0x6f, 0x97, 0xa3, 0x96, 0x81, 0x98, 0, 0
};
#endif
/*
* `pc3' termcap emulation.
*/
void
sput(cp, n)
u_char *cp;
int n;
{
u_char c, scroll = 0;
#ifdef XSERVER
if (pc_xmode > 0)
return;
#endif
if (crtat == 0)
pcinit();
while (n--) {
if (!(c = *cp++))
continue;
switch (c) {
case 0x1B:
if (vs.state >= VSS_ESCAPE) {
wrtchar(c, vs.so_at);
vs.state = 0;
goto maybe_scroll;
} else
vs.state = VSS_ESCAPE;
break;
case '\t': {
int inccol = 8 - (vs.col & 7);
crtat += inccol;
vs.col += inccol;
}
maybe_scroll:
if (vs.col >= COL) {
vs.col -= COL;
scroll = 1;
}
break;
case '\010':
if (crtat <= Crtat)
break;
--crtat;
if (--vs.col < 0)
vs.col += COL; /* non-destructive backspace */
break;
case '\r':
crtat -= vs.col;
vs.col = 0;
break;
case '\n':
crtat += vs.ncol;
scroll = 1;
break;
default:
switch (vs.state) {
case 0:
if (c == '\a')
sysbeep(BEEP_FREQ, BEEP_TIME);
else {
/*
* If we're outputting multiple printed
* characters, just blast them to the
* screen until we reach the end of the
* buffer or a control character. This
* saves time by short-circuiting the
* switch.
* If we reach the end of the line, we
* break to do a scroll check.
*/
for (;;) {
#ifdef DISPLAY_ISO8859
if (c & 0x80)
c = iso2ibm437[c&0x7f];
#endif
if (vs.so)
wrtchar(c, vs.so_at);
else
wrtchar(c, vs.at);
if (vs.col >= vs.ncol) {
vs.col = 0;
scroll = 1;
break;
}
if (!n || (c = *cp) < ' ')
break;
n--, cp++;
}
}
break;
case VSS_ESCAPE:
if (c == '[') { /* Start ESC [ sequence */
vs.cx = vs.cy = 0;
vs.state = VSS_EBRACE;
} else if (c == 'c') { /* Clear screen & home */
fillw((vs.at << 8) | ' ',
Crtat, vs.nchr);
crtat = Crtat;
vs.col = 0;
vs.state = 0;
} else { /* Invalid, clear state */
wrtchar(c, vs.so_at);
vs.state = 0;
goto maybe_scroll;
}
break;
default: /* VSS_EBRACE or VSS_EPARAM */
switch (c) {
int pos;
case 'm':
if (!vs.cx)
vs.so = 0;
else
vs.so = 1;
vs.state = 0;
break;
case 'A': { /* back cx rows */
int cx = vs.cx;
if (cx <= 0)
cx = 1;
else
cx %= vs.nrow;
pos = crtat - Crtat;
pos -= vs.ncol * cx;
if (pos < 0)
pos += vs.nchr;
crtat = Crtat + pos;
vs.state = 0;
break;
}
case 'B': { /* down cx rows */
int cx = vs.cx;
if (cx <= 0)
cx = 1;
else
cx %= vs.nrow;
pos = crtat - Crtat;
pos += vs.ncol * cx;
if (pos >= vs.nchr)
pos -= vs.nchr;
crtat = Crtat + pos;
vs.state = 0;
break;
}
case 'C': { /* right cursor */
int cx = vs.cx,
col = vs.col;
if (cx <= 0)
cx = 1;
else
cx %= vs.ncol;
pos = crtat - Crtat;
pos += cx;
col += cx;
if (col >= vs.ncol) {
pos -= vs.ncol;
col -= vs.ncol;
}
vs.col = col;
crtat = Crtat + pos;
vs.state = 0;
break;
}
case 'D': { /* left cursor */
int cx = vs.cx,
col = vs.col;
if (cx <= 0)
cx = 1;
else
cx %= vs.ncol;
pos = crtat - Crtat;
pos -= cx;
col -= cx;
if (col < 0) {
pos += vs.ncol;
col += vs.ncol;
}
vs.col = col;
crtat = Crtat + pos;
vs.state = 0;
break;
}
case 'J': /* Clear ... */
switch (vs.cx) {
case 0:
/* ... to end of display */
fillw((vs.at << 8) | ' ',
crtat,
Crtat + vs.nchr - crtat);
break;
case 1:
/* ... to next location */
fillw((vs.at << 8) | ' ',
Crtat, crtat - Crtat + 1);
break;
case 2:
/* ... whole display */
fillw((vs.at << 8) | ' ',
Crtat, vs.nchr);
break;
}
vs.state = 0;
break;
case 'K': /* Clear line ... */
switch (vs.cx) {
case 0:
/* ... current to EOL */
fillw((vs.at << 8) | ' ',
crtat, vs.ncol - vs.col);
break;
case 1:
/* ... beginning to next */
fillw((vs.at << 8) | ' ',
crtat - vs.col, vs.col + 1);
break;
case 2:
/* ... entire line */
fillw((vs.at << 8) | ' ',
crtat - vs.col, vs.ncol);
break;
}
vs.state = 0;
break;
case 'f': /* in system V consoles */
case 'H': { /* Cursor move */
int cx = vs.cx,
cy = vs.cy;
if (!cx || !cy) {
crtat = Crtat;
vs.col = 0;
} else {
if (cx > vs.nrow)
cx = vs.nrow;
if (cy > vs.ncol)
cy = vs.ncol;
crtat = Crtat +
(cx - 1) * vs.ncol + cy - 1;
vs.col = cy - 1;
}
vs.state = 0;
break;
}
case 'M': { /* delete cx rows */
u_short *crtAt = crtat - vs.col;
int cx = vs.cx,
row = (crtAt - Crtat) / vs.ncol,
nrow = vs.nrow - row;
if (cx <= 0)
cx = 1;
else if (cx > nrow)
cx = nrow;
if (cx < nrow)
memmove(crtAt,
crtAt + vs.ncol * cx,
vs.ncol *
(nrow - cx) * CHR);
fillw((vs.at << 8) | ' ',
crtAt + vs.ncol * (nrow - cx),
vs.ncol * cx);
vs.state = 0;
break;
}
case 'S': { /* scroll up cx lines */
int cx = vs.cx;
if (cx <= 0)
cx = 1;
else if (cx > vs.nrow)
cx = vs.nrow;
if (cx < vs.nrow)
memmove(Crtat,
Crtat + vs.ncol * cx,
vs.ncol *
(vs.nrow - cx) * CHR);
fillw((vs.at << 8) | ' ',
Crtat + vs.ncol * (vs.nrow - cx),
vs.ncol * cx);
#if 0
crtat -= vs.ncol * cx; /* XXX */
#endif
vs.state = 0;
break;
}
case 'L': { /* insert cx rows */
u_short *crtAt = crtat - vs.col;
int cx = vs.cx,
row = (crtAt - Crtat) / vs.ncol,
nrow = vs.nrow - row;
if (cx <= 0)
cx = 1;
else if (cx > nrow)
cx = nrow;
if (cx < nrow)
memmove(crtAt + vs.ncol * cx,
crtAt,
vs.ncol * (nrow - cx) *
CHR);
fillw((vs.at << 8) | ' ',
crtAt, vs.ncol * cx);
vs.state = 0;
break;
}
case 'T': { /* scroll down cx lines */
int cx = vs.cx;
if (cx <= 0)
cx = 1;
else if (cx > vs.nrow)
cx = vs.nrow;
if (cx < vs.nrow)
memmove(Crtat + vs.ncol * cx,
Crtat,
vs.ncol * (vs.nrow - cx) *
CHR);
fillw((vs.at << 8) | ' ',
Crtat, vs.ncol * cx);
#if 0
crtat += vs.ncol * cx; /* XXX */
#endif
vs.state = 0;
break;
}
case ';': /* Switch params in cursor def */
vs.state = VSS_EPARAM;
break;
case 'r':
vs.so_at = (vs.cx & FG_MASK) |
((vs.cy << 4) & BG_MASK);
vs.state = 0;
break;
case 'x': /* set attributes */
switch (vs.cx) {
case 0:
vs.at = FG_LIGHTGREY | BG_BLACK;
break;
case 1:
/* ansi background */
if (!vs.color)
break;
vs.at &= FG_MASK;
vs.at |= bgansitopc[vs.cy & 7];
break;
case 2:
/* ansi foreground */
if (!vs.color)
break;
vs.at &= BG_MASK;
vs.at |= fgansitopc[vs.cy & 7];
break;
case 3:
/* pc text attribute */
if (vs.state >= VSS_EPARAM)
vs.at = vs.cy;
break;
}
vs.state = 0;
break;
default: /* Only numbers valid here */
if ((c >= '0') && (c <= '9')) {
if (vs.state >= VSS_EPARAM) {
vs.cy *= 10;
vs.cy += c - '0';
} else {
vs.cx *= 10;
vs.cx += c - '0';
}
} else
vs.state = 0;
break;
}
break;
}
}
if (scroll) {
scroll = 0;
/* scroll check */
if (crtat >= Crtat + vs.nchr) {
memmove(Crtat, Crtat + vs.ncol,
(vs.nchr - vs.ncol) * CHR);
fillw((vs.at << 8) | ' ',
Crtat + vs.nchr - vs.ncol,
vs.ncol);
crtat -= vs.ncol;
}
}
}
async_update();
}
#define CODE_SIZE 4 /* Use a max of 4 for now... */
#ifndef NONUS_KBD
typedef struct {
u_short type;
char unshift[CODE_SIZE];
char shift[CODE_SIZE];
char ctl[CODE_SIZE];
} Scan_def;
static Scan_def scan_codes[] = {
{ NONE, "", "", "" }, /* 0 unused */
{ ASCII,"\033", "\033", "\033" }, /* 1 ESCape */
{ ASCII,"1", "!", "!" }, /* 2 1 */
{ ASCII,"2", "@", "\000" }, /* 3 2 */
{ ASCII,"3", "#", "#" }, /* 4 3 */
{ ASCII,"4", "$", "$" }, /* 5 4 */
{ ASCII,"5", "%", "%" }, /* 6 5 */
{ ASCII,"6", "^", "\036" }, /* 7 6 */
{ ASCII,"7", "&", "&" }, /* 8 7 */
{ ASCII,"8", "*", "\010" }, /* 9 8 */
{ ASCII,"9", "(", "(" }, /* 10 9 */
{ ASCII,"0", ")", ")" }, /* 11 0 */
{ ASCII,"-", "_", "\037" }, /* 12 - */
{ ASCII,"=", "+", "+" }, /* 13 = */
#ifndef PCCONS_REAL_BS
{ ASCII,"\177", "\177", "\010" }, /* 14 backspace */
#else
{ ASCII,"\010", "\010", "\177" }, /* 14 backspace */
#endif
{ ASCII,"\t", "\177\t", "\t" }, /* 15 tab */
{ ASCII,"q", "Q", "\021" }, /* 16 q */
{ ASCII,"w", "W", "\027" }, /* 17 w */
{ ASCII,"e", "E", "\005" }, /* 18 e */
{ ASCII,"r", "R", "\022" }, /* 19 r */
{ ASCII,"t", "T", "\024" }, /* 20 t */
{ ASCII,"y", "Y", "\031" }, /* 21 y */
{ ASCII,"u", "U", "\025" }, /* 22 u */
{ ASCII,"i", "I", "\011" }, /* 23 i */
{ ASCII,"o", "O", "\017" }, /* 24 o */
{ ASCII,"p", "P", "\020" }, /* 25 p */
{ ASCII,"[", "{", "\033" }, /* 26 [ */
{ ASCII,"]", "}", "\035" }, /* 27 ] */
{ ASCII,"\r", "\r", "\n" }, /* 28 return */
#ifdef CAPS_IS_CONTROL
{ CAPS, "", "", "" }, /* 29 caps */
#else
{ CTL, "", "", "" }, /* 29 control */
#endif
{ ASCII,"a", "A", "\001" }, /* 30 a */
{ ASCII,"s", "S", "\023" }, /* 31 s */
{ ASCII,"d", "D", "\004" }, /* 32 d */
{ ASCII,"f", "F", "\006" }, /* 33 f */
{ ASCII,"g", "G", "\007" }, /* 34 g */
{ ASCII,"h", "H", "\010" }, /* 35 h */
{ ASCII,"j", "J", "\n" }, /* 36 j */
{ ASCII,"k", "K", "\013" }, /* 37 k */
{ ASCII,"l", "L", "\014" }, /* 38 l */
{ ASCII,";", ":", ";" }, /* 39 ; */
{ ASCII,"'", "\"", "'" }, /* 40 ' */
{ ASCII,"`", "~", "`" }, /* 41 ` */
{ SHIFT,"", "", "" }, /* 42 shift */
{ ASCII,"\\", "|", "\034" }, /* 43 \ */
{ ASCII,"z", "Z", "\032" }, /* 44 z */
{ ASCII,"x", "X", "\030" }, /* 45 x */
{ ASCII,"c", "C", "\003" }, /* 46 c */
{ ASCII,"v", "V", "\026" }, /* 47 v */
{ ASCII,"b", "B", "\002" }, /* 48 b */
{ ASCII,"n", "N", "\016" }, /* 49 n */
{ ASCII,"m", "M", "\r" }, /* 50 m */
{ ASCII,",", "<", "<" }, /* 51 , */
{ ASCII,".", ">", ">" }, /* 52 . */
{ ASCII,"/", "?", "\037" }, /* 53 / */
{ SHIFT,"", "", "" }, /* 54 shift */
{ KP, "*", "*", "*" }, /* 55 kp * */
{ ALT, "", "", "" }, /* 56 alt */
{ ASCII," ", " ", "\000" }, /* 57 space */
#ifdef CAPS_IS_CONTROL
{ CTL, "", "", "" }, /* 58 control */
#else
{ CAPS, "", "", "" }, /* 58 caps */
#endif
{ FUNC, "\033[M", "\033[Y", "\033[k" }, /* 59 f1 */
{ FUNC, "\033[N", "\033[Z", "\033[l" }, /* 60 f2 */
{ FUNC, "\033[O", "\033[a", "\033[m" }, /* 61 f3 */
{ FUNC, "\033[P", "\033[b", "\033[n" }, /* 62 f4 */
{ FUNC, "\033[Q", "\033[c", "\033[o" }, /* 63 f5 */
{ FUNC, "\033[R", "\033[d", "\033[p" }, /* 64 f6 */
{ FUNC, "\033[S", "\033[e", "\033[q" }, /* 65 f7 */
{ FUNC, "\033[T", "\033[f", "\033[r" }, /* 66 f8 */
{ FUNC, "\033[U", "\033[g", "\033[s" }, /* 67 f9 */
{ FUNC, "\033[V", "\033[h", "\033[t" }, /* 68 f10 */
{ NUM, "", "", "" }, /* 69 num lock */
{ SCROLL,"", "", "" }, /* 70 scroll lock */
{ KP, "7", "\033[H", "7" }, /* 71 kp 7 */
{ KP, "8", "\033[A", "8" }, /* 72 kp 8 */
{ KP, "9", "\033[I", "9" }, /* 73 kp 9 */
{ KP, "-", "-", "-" }, /* 74 kp - */
{ KP, "4", "\033[D", "4" }, /* 75 kp 4 */
{ KP, "5", "\033[E", "5" }, /* 76 kp 5 */
{ KP, "6", "\033[C", "6" }, /* 77 kp 6 */
{ KP, "+", "+", "+" }, /* 78 kp + */
{ KP, "1", "\033[F", "1" }, /* 79 kp 1 */
{ KP, "2", "\033[B", "2" }, /* 80 kp 2 */
{ KP, "3", "\033[G", "3" }, /* 81 kp 3 */
{ KP, "0", "\033[L", "0" }, /* 82 kp 0 */
{ KP, ".", "\177", "." }, /* 83 kp . */
{ NONE, "", "", "" }, /* 84 0 */
{ NONE, "100", "", "" }, /* 85 0 */
{ NONE, "101", "", "" }, /* 86 0 */
{ FUNC, "\033[W", "\033[i", "\033[u" }, /* 87 f11 */
{ FUNC, "\033[X", "\033[j", "\033[v" }, /* 88 f12 */
{ NONE, "102", "", "" }, /* 89 0 */
{ NONE, "103", "", "" }, /* 90 0 */
{ NONE, "", "", "" }, /* 91 0 */
{ NONE, "", "", "" }, /* 92 0 */
{ NONE, "", "", "" }, /* 93 0 */
{ NONE, "", "", "" }, /* 94 0 */
{ NONE, "", "", "" }, /* 95 0 */
{ NONE, "", "", "" }, /* 96 0 */
{ NONE, "", "", "" }, /* 97 0 */
{ NONE, "", "", "" }, /* 98 0 */
{ NONE, "", "", "" }, /* 99 0 */
{ NONE, "", "", "" }, /* 100 */
{ NONE, "", "", "" }, /* 101 */
{ NONE, "", "", "" }, /* 102 */
{ NONE, "", "", "" }, /* 103 */
{ NONE, "", "", "" }, /* 104 */
{ NONE, "", "", "" }, /* 105 */
{ NONE, "", "", "" }, /* 106 */
{ NONE, "", "", "" }, /* 107 */
{ NONE, "", "", "" }, /* 108 */
{ NONE, "", "", "" }, /* 109 */
{ NONE, "", "", "" }, /* 110 */
{ NONE, "", "", "" }, /* 111 */
{ NONE, "", "", "" }, /* 112 */
{ NONE, "", "", "" }, /* 113 */
{ NONE, "", "", "" }, /* 114 */
{ NONE, "", "", "" }, /* 115 */
{ NONE, "", "", "" }, /* 116 */
{ NONE, "", "", "" }, /* 117 */
{ NONE, "", "", "" }, /* 118 */
{ NONE, "", "", "" }, /* 119 */
{ NONE, "", "", "" }, /* 120 */
{ NONE, "", "", "" }, /* 121 */
{ NONE, "", "", "" }, /* 122 */
{ NONE, "", "", "" }, /* 123 */
{ NONE, "", "", "" }, /* 124 */
{ NONE, "", "", "" }, /* 125 */
{ NONE, "", "", "" }, /* 126 */
{ NONE, "", "", "" }, /* 127 */
};
#else /* NONUS_KBD */
typedef struct {
u_short type;
char unshift[CODE_SIZE];
char shift[CODE_SIZE];
char ctl[CODE_SIZE];
char altgr[CODE_SIZE];
} Scan_def;
#ifdef FRENCH_KBD
static Scan_def scan_codes[] = {
{ NONE, "", "", "", "" }, /* 0 unused */
{ ASCII, "\033", "\033", "\033", "\033" }, /* 1 ESCape */
{ ASCII, "&", "1", "&", "" }, /* 2 1 */
{ ASCII, "\351", "2", "\211", "~" }, /* 3 2 */
{ ASCII, "\"", "3", "\"", "#" }, /* 4 3 */
{ ASCII, "'", "4", "'", "{" }, /* 5 4 */
{ ASCII, "(", "5", "(", "[" }, /* 6 5 */
{ ASCII, "-", "6", "-", "|" }, /* 7 6 */
{ ASCII, "\350", "7", "\210", "`" }, /* 8 7 */
{ ASCII, "_", "8", "\037", "\\" }, /* 9 8 */
{ ASCII, "\347", "9", "\207", "^" }, /* 10 9 */
{ ASCII, "\340", "0", "\340", "@" }, /* 11 0 */
{ ASCII, ")", "\260", ")", "]" }, /* 12 - */
{ ASCII, "=", "+", "+", "}" }, /* 13 = */
{ ASCII, "\177", "\177", "\010", "\177" }, /* 14 backspace */
{ ASCII, "\t", "\177\t", "\t", "\t" }, /* 15 tab */
{ ASCII, "a", "A", "\001", "a" }, /* 16 q */
{ ASCII, "z", "Z", "\032", "z" }, /* 17 w */
{ ASCII, "e", "E", "\005", "e" }, /* 18 e */
{ ASCII, "r", "R", "\022", "r" }, /* 19 r */
{ ASCII, "t", "T", "\024", "t" }, /* 20 t */
{ ASCII, "y", "Y", "\031", "y" }, /* 21 y */
{ ASCII, "u", "U", "\025", "u" }, /* 22 u */
{ ASCII, "i", "I", "\011", "i" }, /* 23 i */
{ ASCII, "o", "O", "\017", "o" }, /* 24 o */
{ ASCII, "p", "P", "\020", "p" }, /* 25 p */
{ NONE, "", "", "", "" }, /* 26 [ */
{ ASCII, "$", "\243", "$", "$" }, /* 27 ] */
{ ASCII, "\r", "\r", "\n", "\r" }, /* 28 return */
{ CTL, "", "", "", "" }, /* 29 control */
{ ASCII, "q", "Q", "\021", "q" }, /* 30 a */
{ ASCII, "s", "S", "\023", "s" }, /* 31 s */
{ ASCII, "d", "D", "\004", "d" }, /* 32 d */
{ ASCII, "f", "F", "\006", "f" }, /* 33 f */
{ ASCII, "g", "G", "\007", "g" }, /* 34 g */
{ ASCII, "h", "H", "\010", "h" }, /* 35 h */
{ ASCII, "j", "J", "\n", "j" }, /* 36 j */
{ ASCII, "k", "K", "\013", "k" }, /* 37 k */
{ ASCII, "l", "L", "\014", "l" }, /* 38 l */
{ ASCII, "m", "M", "\r", "m" }, /* 39 ; */
{ ASCII, "\371", "%", "\231", "\371" }, /* 40 ' */
{ ASCII, "\262", "", "\262", "\262" }, /* 41 ` */
{ SHIFT, "", "", "", "" }, /* 42 shift */
{ ASCII, "*", "\265", "*", "*" }, /* 43 \ */
{ ASCII, "w", "W", "\027", "w" }, /* 44 z */
{ ASCII, "x", "X", "\030", "x" }, /* 45 x */
{ ASCII, "c", "C", "\003", "c" }, /* 46 c */
{ ASCII, "v", "V", "\026", "v" }, /* 47 v */
{ ASCII, "b", "B", "\002", "b" }, /* 48 b */
{ ASCII, "n", "N", "\016", "n" }, /* 49 n */
{ ASCII, ",", "?", ",", "," }, /* 50 m */
{ ASCII, ";", ".", ";", ";" }, /* 51 , */
{ ASCII, ":", "/", "\037", ":" }, /* 52 . */
{ ASCII, "!", "\266", "!", "!" }, /* 53 / */
{ SHIFT, "", "", "", "" }, /* 54 shift */
{ KP, "*", "*", "*", "*" }, /* 55 kp * */
{ ALT, "", "", "", "" }, /* 56 alt */
{ ASCII, " ", " ", "\000", " " }, /* 57 space */
{ CAPS, "", "", "", "" }, /* 58 caps */
{ FUNC, "\033[M", "\033[Y", "\033[k", "" }, /* 59 f1 */
{ FUNC, "\033[N", "\033[Z", "\033[l", "" }, /* 60 f2 */
{ FUNC, "\033[O", "\033[a", "\033[m", "" }, /* 61 f3 */
{ FUNC, "\033[P", "\033[b", "\033[n", "" }, /* 62 f4 */
{ FUNC, "\033[Q", "\033[c", "\033[o", "" }, /* 63 f5 */
{ FUNC, "\033[R", "\033[d", "\033[p", "" }, /* 64 f6 */
{ FUNC, "\033[S", "\033[e", "\033[q", "" }, /* 65 f7 */
{ FUNC, "\033[T", "\033[f", "\033[r", "" }, /* 66 f8 */
{ FUNC, "\033[U", "\033[g", "\033[s", "" }, /* 67 f9 */
{ FUNC, "\033[V", "\033[h", "\033[t", "" }, /* 68 f10 */
{ NUM, "", "", "", "" }, /* 69 num lock */
{ SCROLL, "", "", "", "" }, /* 70 scroll lock */
{ KP, "7", "\033[H", "7", "" }, /* 71 kp 7 */
{ KP, "8", "\033[A", "8", "" }, /* 72 kp 8 */
{ KP, "9", "\033[I", "9", "" }, /* 73 kp 9 */
{ KP, "-", "-", "-", "" }, /* 74 kp - */
{ KP, "4", "\033[D", "4", "" }, /* 75 kp 4 */
{ KP, "5", "\033[E", "5", "" }, /* 76 kp 5 */
{ KP, "6", "\033[C", "6", "" }, /* 77 kp 6 */
{ KP, "+", "+", "+", "" }, /* 78 kp + */
{ KP, "1", "\033[F", "1", "" }, /* 79 kp 1 */
{ KP, "2", "\033[B", "2", "" }, /* 80 kp 2 */
{ KP, "3", "\033[G", "3", "" }, /* 81 kp 3 */
{ KP, "0", "\033[L", "0", "" }, /* 82 kp 0 */
{ KP, ".", "\177", ".", "" }, /* 83 kp . */
{ NONE, "", "", "", "" }, /* 84 0 */
{ NONE, "100", "", "", "" }, /* 85 0 */
{ ASCII, "<", ">", "<", "<" }, /* 86 < > */
{ FUNC, "\033[W", "\033[i", "\033[u","" }, /* 87 f11 */
{ FUNC, "\033[X", "\033[j", "\033[v","" }, /* 88 f12 */
{ NONE, "102", "", "", "" }, /* 89 0 */
{ NONE, "103", "", "", "" }, /* 90 0 */
{ NONE, "", "", "", "" }, /* 91 0 */
{ NONE, "", "", "", "" }, /* 92 0 */
{ NONE, "", "", "", "" }, /* 93 0 */
{ NONE, "", "", "", "" }, /* 94 0 */
{ NONE, "", "", "", "" }, /* 95 0 */
{ NONE, "", "", "", "" }, /* 96 0 */
{ NONE, "", "", "", "" }, /* 97 0 */
{ NONE, "", "", "", "" }, /* 98 0 */
{ NONE, "", "", "", "" }, /* 99 0 */
{ NONE, "", "", "", "" }, /* 100 */
{ NONE, "", "", "", "" }, /* 101 */
{ NONE, "", "", "", "" }, /* 102 */
{ NONE, "", "", "", "" }, /* 103 */
{ NONE, "", "", "", "" }, /* 104 */
{ NONE, "", "", "", "" }, /* 105 */
{ NONE, "", "", "", "" }, /* 106 */
{ NONE, "", "", "", "" }, /* 107 */
{ NONE, "", "", "", "" }, /* 108 */
{ NONE, "", "", "", "" }, /* 109 */
{ NONE, "", "", "", "" }, /* 110 */
{ NONE, "", "", "", "" }, /* 111 */
{ NONE, "", "", "", "" }, /* 112 */
{ NONE, "", "", "", "" }, /* 113 */
{ NONE, "", "", "", "" }, /* 114 */
{ NONE, "", "", "", "" }, /* 115 */
{ NONE, "", "", "", "" }, /* 116 */
{ NONE, "", "", "", "" }, /* 117 */
{ NONE, "", "", "", "" }, /* 118 */
{ NONE, "", "", "", "" }, /* 119 */
{ NONE, "", "", "", "" }, /* 120 */
{ NONE, "", "", "", "" }, /* 121 */
{ NONE, "", "", "", "" }, /* 122 */
{ NONE, "", "", "", "" }, /* 123 */
{ NONE, "", "", "", "" }, /* 124 */
{ NONE, "", "", "", "" }, /* 125 */
{ NONE, "", "", "", "" }, /* 126 */
{ NONE, "", "", "", "" } /* 127 */
};
#endif /* FRENCH_KBD */
#ifdef GERMAN_KBD
static Scan_def scan_codes[] = {
{ NONE, "", "", "", "" }, /* 0 unused */
{ ASCII, "\033", "\033", "\033", "\033"}, /* 1 ESCape */
{ ASCII, "1", "!", "!", "" }, /* 2 1 */
{ ASCII, "2", "\"", "\"", "\xb2" }, /* 3 2 */
{ ASCII, "3", "\xa7", "\xa7", "\xb3" }, /* 4 3 */
{ ASCII, "4", "$", "$", "" }, /* 5 4 */
{ ASCII, "5", "%", "%", "" }, /* 6 5 */
{ ASCII, "6", "&", "&", "" }, /* 7 6 */
{ ASCII, "7", "/", "/", "{" }, /* 8 7 */
{ ASCII, "8", "(", "(", "[" }, /* 9 8 */
{ ASCII, "9", ")", ")", "]" }, /* 10 9 */
{ ASCII, "0", "=", "=", "}" }, /* 11 0 */
{ ASCII, "\xdf","?", "?", "\\" }, /* 12 - */
{ ASCII, "'", "`", "`", "" }, /* 13 = */
{ ASCII, "\177", "\177", "\010", "\177" }, /* 14 backspace */
{ ASCII, "\t", "\177\t", "\t", "\t" }, /* 15 tab */
{ ASCII, "q", "Q", "\021", "@" }, /* 16 q */
{ ASCII, "w", "W", "\027", "w" }, /* 17 w */
{ ASCII, "e", "E", "\005", "e" }, /* 18 e */
{ ASCII, "r", "R", "\022", "r" }, /* 19 r */
{ ASCII, "t", "T", "\024", "t" }, /* 20 t */
{ ASCII, "z", "Z", "\032", "z" }, /* 21 y */
{ ASCII, "u", "U", "\025", "u" }, /* 22 u */
{ ASCII, "i", "I", "\011", "i" }, /* 23 i */
{ ASCII, "o", "O", "\017", "o" }, /* 24 o */
{ ASCII, "p", "P", "\020", "p" }, /* 25 p */
{ ASCII, "\xfc", "\xdc", "\xfc", "\xdc" }, /* 26 [ */
{ ASCII, "+", "*", "+", "~" }, /* 27 ] */
{ ASCII, "\r", "\r", "\n", "\r" }, /* 28 return */
{ CTL, "", "", "", "" }, /* 29 control */
{ ASCII, "a", "A", "\001", "a" }, /* 30 a */
{ ASCII, "s", "S", "\023", "s" }, /* 31 s */
{ ASCII, "d", "D", "\004", "d" }, /* 32 d */
{ ASCII, "f", "F", "\006", "f" }, /* 33 f */
{ ASCII, "g", "G", "\007", "g" }, /* 34 g */
{ ASCII, "h", "H", "\010", "h" }, /* 35 h */
{ ASCII, "j", "J", "\n", "j" }, /* 36 j */
{ ASCII, "k", "K", "\013", "k" }, /* 37 k */
{ ASCII, "l", "L", "\014", "l" }, /* 38 l */
{ ASCII, "\xf6", "\xd6", "\xf6", "\xd6" }, /* 39 ; */
{ ASCII, "\xe4", "\xc4", "\xe4", "\xc4" }, /* 40 ' */
{ ASCII, "\136", "\370", "\136", "\370" }, /* 41 ` */
{ SHIFT, "", "", "", "" }, /* 42 shift */
{ ASCII, "#", "'", "#", "'" }, /* 43 \ */
{ ASCII, "y", "Y", "\x19", "y" }, /* 44 z */
{ ASCII, "x", "X", "\030", "x" }, /* 45 x */
{ ASCII, "c", "C", "\003", "c" }, /* 46 c */
{ ASCII, "v", "V", "\026", "v" }, /* 47 v */
{ ASCII, "b", "B", "\002", "b" }, /* 48 b */
{ ASCII, "n", "N", "\016", "n" }, /* 49 n */
{ ASCII, "m", "M", "\r", "m" }, /* 50 m */
{ ASCII, ",", ";", ",", ";" }, /* 51 , */
{ ASCII, ".", ":", ".", ":" }, /* 52 . */
{ ASCII, "-", "_", "-", "_" }, /* 53 / */
{ SHIFT, "", "", "", "" }, /* 54 shift */
{ KP, "*", "*", "*", "*" }, /* 55 kp * */
{ ALT, "", "", "", "" }, /* 56 alt */
{ ASCII, " ", " ", "\000", " " }, /* 57 space */
{ CAPS, "", "", "", "" }, /* 58 caps */
{ FUNC, "\033[M", "\033[Y", "\033[k", "" }, /* 59 f1 */
{ FUNC, "\033[N", "\033[Z", "\033[l", "" }, /* 60 f2 */
{ FUNC, "\033[O", "\033[a", "\033[m", "" }, /* 61 f3 */
{ FUNC, "\033[P", "\033[b", "\033[n", "" }, /* 62 f4 */
{ FUNC, "\033[Q", "\033[c", "\033[o", "" }, /* 63 f5 */
{ FUNC, "\033[R", "\033[d", "\033[p", "" }, /* 64 f6 */
{ FUNC, "\033[S", "\033[e", "\033[q", "" }, /* 65 f7 */
{ FUNC, "\033[T", "\033[f", "\033[r", "" }, /* 66 f8 */
{ FUNC, "\033[U", "\033[g", "\033[s", "" }, /* 67 f9 */
{ FUNC, "\033[V", "\033[h", "\033[t", "" }, /* 68 f10 */
{ NUM, "", "", "", "" }, /* 69 num lock */
{ SCROLL, "", "", "", "" }, /* 70 scroll lock */
{ KP, "7", "\033[H", "7", "" }, /* 71 kp 7 */
{ KP, "8", "\033[A", "8", "" }, /* 72 kp 8 */
{ KP, "9", "\033[I", "9", "" }, /* 73 kp 9 */
{ KP, "-", "-", "-", "" }, /* 74 kp - */
{ KP, "4", "\033[D", "4", "" }, /* 75 kp 4 */
{ KP, "5", "\033[E", "5", "" }, /* 76 kp 5 */
{ KP, "6", "\033[C", "6", "" }, /* 77 kp 6 */
{ KP, "+", "+", "+", "" }, /* 78 kp + */
{ KP, "1", "\033[F", "1", "" }, /* 79 kp 1 */
{ KP, "2", "\033[B", "2", "" }, /* 80 kp 2 */
{ KP, "3", "\033[G", "3", "" }, /* 81 kp 3 */
{ KP, "0", "\033[L", "0", "" }, /* 82 kp 0 */
{ KP, ",", "\177", ",", "" }, /* 83 kp . */
{ NONE, "", "", "", "" }, /* 84 0 */
{ NONE, "100", "", "", "" }, /* 85 0 */
{ ASCII, "<", ">", "<", "|" }, /* 86 < > */
{ FUNC, "\033[W", "\033[i", "\033[u","" }, /* 87 f11 */
{ FUNC, "\033[X", "\033[j", "\033[v","" }, /* 88 f12 */
{ NONE, "102", "", "", "" }, /* 89 0 */
{ NONE, "103", "", "", "" }, /* 90 0 */
{ NONE, "", "", "", "" }, /* 91 0 */
{ NONE, "", "", "", "" }, /* 92 0 */
{ NONE, "", "", "", "" }, /* 93 0 */
{ NONE, "", "", "", "" }, /* 94 0 */
{ NONE, "", "", "", "" }, /* 95 0 */
{ NONE, "", "", "", "" }, /* 96 0 */
{ NONE, "", "", "", "" }, /* 97 0 */
{ NONE, "", "", "", "" }, /* 98 0 */
{ NONE, "", "", "", "" }, /* 99 0 */
{ NONE, "", "", "", "" }, /* 100 */
{ NONE, "", "", "", "" }, /* 101 */
{ NONE, "", "", "", "" }, /* 102 */
{ NONE, "", "", "", "" }, /* 103 */
{ NONE, "", "", "", "" }, /* 104 */
{ NONE, "", "", "", "" }, /* 105 */
{ NONE, "", "", "", "" }, /* 106 */
{ NONE, "", "", "", "" }, /* 107 */
{ NONE, "", "", "", "" }, /* 108 */
{ NONE, "", "", "", "" }, /* 109 */
{ NONE, "", "", "", "" }, /* 110 */
{ NONE, "", "", "", "" }, /* 111 */
{ NONE, "", "", "", "" }, /* 112 */
{ NONE, "", "", "", "" }, /* 113 */
{ NONE, "", "", "", "" }, /* 114 */
{ NONE, "", "", "", "" }, /* 115 */
{ NONE, "", "", "", "" }, /* 116 */
{ NONE, "", "", "", "" }, /* 117 */
{ NONE, "", "", "", "" }, /* 118 */
{ NONE, "", "", "", "" }, /* 119 */
{ NONE, "", "", "", "" }, /* 120 */
{ NONE, "", "", "", "" }, /* 121 */
{ NONE, "", "", "", "" }, /* 122 */
{ NONE, "", "", "", "" }, /* 123 */
{ NONE, "", "", "", "" }, /* 124 */
{ NONE, "", "", "", "" }, /* 125 */
{ NONE, "", "", "", "" }, /* 126 */
{ NONE, "", "", "", "" } /* 127 */
};
#endif /* GERMAN_KBD */
#ifdef NORWEGIAN_KBD
static Scan_def scan_codes[] = {
{ NONE, "", "", "", "" }, /* 0 unused */
{ ASCII, "\033", "\033", "\033", "\033" }, /* 1 ESCape */
{ ASCII, "1", "!", "", "\241" }, /* 2 1 */
{ ASCII, "2", "\"", "\000", "@" }, /* 3 2 */
{ ASCII, "3", "#", "", "\243" }, /* 4 3 */
{ ASCII, "4", "$", "", "$" }, /* 5 4 */
{ ASCII, "5", "%", "\034", "\\" }, /* 6 5 */
{ ASCII, "6", "&", "\034", "|" }, /* 7 6 */
{ ASCII, "7", "/", "\033", "{" }, /* 8 7 */
{ ASCII, "8", "(", "\033", "[" }, /* 9 8 */
{ ASCII, "9", ")", "\035", "]" }, /* 10 9 */
{ ASCII, "0", "=", "\035", "}" }, /* 11 0 */
{ ASCII, "+", "?", "\037", "\277" }, /* 12 - */
{ ASCII, "\\", "`", "\034", "'" }, /* 13 = */
{ ASCII, "\177", "\177", "\010", "\177" }, /* 14 backspace */
{ ASCII, "\t", "\177\t", "\t", "\t" }, /* 15 tab */
{ ASCII, "q", "Q", "\021", "q" }, /* 16 q */
{ ASCII, "w", "W", "\027", "w" }, /* 17 w */
{ ASCII, "e", "E", "\005", "\353" }, /* 18 e */
{ ASCII, "r", "R", "\022", "r" }, /* 19 r */
{ ASCII, "t", "T", "\024", "t" }, /* 20 t */
{ ASCII, "y", "Y", "\031", "y" }, /* 21 y */
{ ASCII, "u", "U", "\025", "\374" }, /* 22 u */
{ ASCII, "i", "I", "\011", "i" }, /* 23 i */
{ ASCII, "o", "O", "\017", "\366" }, /* 24 o */
{ ASCII, "p", "P", "\020", "p" }, /* 25 p */
{ ASCII, "\345", "\305", "\334", "\374" }, /* 26 [ */
{ ASCII, "~", "^", "\036", "" }, /* 27 ] */
{ ASCII, "\r", "\r", "\n", "\r" }, /* 28 return */
{ CTL, "", "", "", "" }, /* 29 control */
{ ASCII, "a", "A", "\001", "\344" }, /* 30 a */
{ ASCII, "s", "S", "\023", "\337" }, /* 31 s */
{ ASCII, "d", "D", "\004", "d" }, /* 32 d */
{ ASCII, "f", "F", "\006", "f" }, /* 33 f */
{ ASCII, "g", "G", "\007", "g" }, /* 34 g */
{ ASCII, "h", "H", "\010", "h" }, /* 35 h */
{ ASCII, "j", "J", "\n", "j" }, /* 36 j */
{ ASCII, "k", "K", "\013", "k" }, /* 37 k */
{ ASCII, "l", "L", "\014", "l" }, /* 38 l */
{ ASCII, "\370", "\330", "\326", "\366" }, /* 39 ; */
{ ASCII, "\346", "\306", "\304", "\344" }, /* 40 ' */
{ ASCII, "|", "@", "\034", "\247" }, /* 41 ` */
{ SHIFT, "", "", "", "" }, /* 42 shift */
{ ASCII, "'", "*", "'", "'" }, /* 43 \ */
{ ASCII, "z", "Z", "\032", "z" }, /* 44 z */
{ ASCII, "x", "X", "\030", "x" }, /* 45 x */
{ ASCII, "c", "C", "\003", "c" }, /* 46 c */
{ ASCII, "v", "V", "\026", "v" }, /* 47 v */
{ ASCII, "b", "B", "\002", "b" }, /* 48 b */
{ ASCII, "n", "N", "\016", "n" }, /* 49 n */
{ ASCII, "m", "M", "\015", "m" }, /* 50 m */
{ ASCII, ",", ";", ",", "," }, /* 51 , */
{ ASCII, ".", ":", ".", "." }, /* 52 . */
{ ASCII, "-", "_", "\037", "-" }, /* 53 / */
{ SHIFT, "", "", "", "" }, /* 54 shift */
{ KP, "*", "*", "*", "*" }, /* 55 kp * */
{ ALT, "", "", "", "" }, /* 56 alt */
{ ASCII, " ", " ", "\000", " " }, /* 57 space */
{ CAPS, "", "", "", "" }, /* 58 caps */
{ FUNC, "\033[M", "\033[Y", "\033[k", "" }, /* 59 f1 */
{ FUNC, "\033[N", "\033[Z", "\033[l", "" }, /* 60 f2 */
{ FUNC, "\033[O", "\033[a", "\033[m", "" }, /* 61 f3 */
{ FUNC, "\033[P", "\033[b", "\033[n", "" }, /* 62 f4 */
{ FUNC, "\033[Q", "\033[c", "\033[o", "" }, /* 63 f5 */
{ FUNC, "\033[R", "\033[d", "\033[p", "" }, /* 64 f6 */
{ FUNC, "\033[S", "\033[e", "\033[q", "" }, /* 65 f7 */
{ FUNC, "\033[T", "\033[f", "\033[r", "" }, /* 66 f8 */
{ FUNC, "\033[U", "\033[g", "\033[s", "" }, /* 67 f9 */
{ FUNC, "\033[V", "\033[h", "\033[t", "" }, /* 68 f10 */
{ NUM, "", "", "", "" }, /* 69 num lock */
{ SCROLL, "", "", "", "" }, /* 70 scroll lock */
{ KP, "7", "\033[H", "7", "" }, /* 71 kp 7 */
{ KP, "8", "\033[A", "8", "" }, /* 72 kp 8 */
{ KP, "9", "\033[I", "9", "" }, /* 73 kp 9 */
{ KP, "-", "-", "-", "" }, /* 74 kp - */
{ KP, "4", "\033[D", "4", "" }, /* 75 kp 4 */
{ KP, "5", "\033[E", "5", "" }, /* 76 kp 5 */
{ KP, "6", "\033[C", "6", "" }, /* 77 kp 6 */
{ KP, "+", "+", "+", "" }, /* 78 kp + */
{ KP, "1", "\033[F", "1", "" }, /* 79 kp 1 */
{ KP, "2", "\033[B", "2", "" }, /* 80 kp 2 */
{ KP, "3", "\033[G", "3", "" }, /* 81 kp 3 */
{ KP, "0", "\033[L", "0", "" }, /* 82 kp 0 */
{ KP, ".", "\177", ".", "" }, /* 83 kp . */
{ NONE, "", "", "", "" }, /* 84 0 */
{ NONE, "100", "", "", "" }, /* 85 0 */
{ ASCII, "<", ">", "\273", "\253" }, /* 86 < > */
{ FUNC, "\033[W", "\033[i", "\033[u","" }, /* 87 f11 */
{ FUNC, "\033[X", "\033[j", "\033[v","" }, /* 88 f12 */
{ NONE, "102", "", "", "" }, /* 89 0 */
{ NONE, "103", "", "", "" }, /* 90 0 */
{ NONE, "", "", "", "" }, /* 91 0 */
{ NONE, "", "", "", "" }, /* 92 0 */
{ NONE, "", "", "", "" }, /* 93 0 */
{ NONE, "", "", "", "" }, /* 94 0 */
{ NONE, "", "", "", "" }, /* 95 0 */
{ NONE, "", "", "", "" }, /* 96 0 */
{ NONE, "", "", "", "" }, /* 97 0 */
{ NONE, "", "", "", "" }, /* 98 0 */
{ NONE, "", "", "", "" }, /* 99 0 */
{ NONE, "", "", "", "" }, /* 100 */
{ NONE, "", "", "", "" }, /* 101 */
{ NONE, "", "", "", "" }, /* 102 */
{ NONE, "", "", "", "" }, /* 103 */
{ NONE, "", "", "", "" }, /* 104 */
{ NONE, "", "", "", "" }, /* 105 */
{ NONE, "", "", "", "" }, /* 106 */
{ NONE, "", "", "", "" }, /* 107 */
{ NONE, "", "", "", "" }, /* 108 */
{ NONE, "", "", "", "" }, /* 109 */
{ NONE, "", "", "", "" }, /* 110 */
{ NONE, "", "", "", "" }, /* 111 */
{ NONE, "", "", "", "" }, /* 112 */
{ NONE, "", "", "", "" }, /* 113 */
{ NONE, "", "", "", "" }, /* 114 */
{ NONE, "", "", "", "" }, /* 115 */
{ NONE, "", "", "", "" }, /* 116 */
{ NONE, "", "", "", "" }, /* 117 */
{ NONE, "", "", "", "" }, /* 118 */
{ NONE, "", "", "", "" }, /* 119 */
{ NONE, "", "", "", "" }, /* 120 */
{ NONE, "", "", "", "" }, /* 121 */
{ NONE, "", "", "", "" }, /* 122 */
{ NONE, "", "", "", "" }, /* 123 */
{ NONE, "", "", "", "" }, /* 124 */
{ NONE, "", "", "", "" }, /* 125 */
{ NONE, "", "", "", "" }, /* 126 */
{ NONE, "", "", "", "" } /* 127 */
};
#endif
#ifdef FINNISH_KBD
static Scan_def scan_codes[] = {
{ NONE, "", "", "", "" }, /* 0 unused */
{ ASCII, "\033", "\033", "\033", "\033" }, /* 1 ESCape */
{ ASCII, "1", "!", "", "\241" }, /* 2 1 */
{ ASCII, "2", "\"", "\000", "@" }, /* 3 2 */
{ ASCII, "3", "#", "", "\243" }, /* 4 3 */
{ ASCII, "4", "$", "", "$" }, /* 5 4 */
{ ASCII, "5", "%", "\034", "%" }, /* 6 5 */
{ ASCII, "6", "&", "\034", "&" }, /* 7 6 */
{ ASCII, "7", "/", "\033", "{" }, /* 8 7 */
{ ASCII, "8", "(", "\033", "[" }, /* 9 8 */
{ ASCII, "9", ")", "\035", "]" }, /* 10 9 */
{ ASCII, "0", "=", "\035", "}" }, /* 11 0 */
{ ASCII, "+", "?", "\037", "\\" }, /* 12 - */
{ ASCII, "'", "`", "\034", "'" }, /* 13 = */
{ ASCII, "\177", "\177", "\010", "\177" }, /* 14 backspace */
{ ASCII, "\t", "\177\t", "\t", "\t" }, /* 15 tab */
{ ASCII, "q", "Q", "\021", "q" }, /* 16 q */
{ ASCII, "w", "W", "\027", "w" }, /* 17 w */
{ ASCII, "e", "E", "\005", "\353" }, /* 18 e */
{ ASCII, "r", "R", "\022", "r" }, /* 19 r */
{ ASCII, "t", "T", "\024", "t" }, /* 20 t */
{ ASCII, "y", "Y", "\031", "y" }, /* 21 y */
{ ASCII, "u", "U", "\025", "\374" }, /* 22 u */
{ ASCII, "i", "I", "\011", "i" }, /* 23 i */
{ ASCII, "o", "O", "\017", "\366" }, /* 24 o */
{ ASCII, "p", "P", "\020", "p" }, /* 25 p */
{ ASCII, "\345", "\305", "\035", "}" }, /* 26 [ */
{ ASCII, "~", "^", "\036", "~" }, /* 27 ] */
{ ASCII, "\r", "\r", "\n", "\r" }, /* 28 return */
{ CTL, "", "", "", "" }, /* 29 control */
{ ASCII, "a", "A", "\001", "\344" }, /* 30 a */
{ ASCII, "s", "S", "\023", "\337" }, /* 31 s */
{ ASCII, "d", "D", "\004", "d" }, /* 32 d */
{ ASCII, "f", "F", "\006", "f" }, /* 33 f */
{ ASCII, "g", "G", "\007", "g" }, /* 34 g */
{ ASCII, "h", "H", "\010", "h" }, /* 35 h */
{ ASCII, "j", "J", "\n", "j" }, /* 36 j */
{ ASCII, "k", "K", "\013", "k" }, /* 37 k */
{ ASCII, "l", "L", "\014", "l" }, /* 38 l */
{ ASCII, "\366", "\326", "\034", "|" }, /* 39 ; */
{ ASCII, "\344", "\304", "\033", "{" }, /* 40 ' */
{ ASCII, "\247", "\275", "\000", "@" }, /* 41 ` */
{ SHIFT, "", "", "", "" }, /* 42 shift */
{ ASCII, "'", "*", "'", "'" }, /* 43 \ */
{ ASCII, "z", "Z", "\032", "z" }, /* 44 z */
{ ASCII, "x", "X", "\030", "x" }, /* 45 x */
{ ASCII, "c", "C", "\003", "c" }, /* 46 c */
{ ASCII, "v", "V", "\026", "v" }, /* 47 v */
{ ASCII, "b", "B", "\002", "b" }, /* 48 b */
{ ASCII, "n", "N", "\016", "n" }, /* 49 n */
{ ASCII, "m", "M", "\015", "m" }, /* 50 m */
{ ASCII, ",", ";", ",", "," }, /* 51 , */
{ ASCII, ".", ":", ".", "." }, /* 52 . */
{ ASCII, "-", "_", "\037", "-" }, /* 53 / */
{ SHIFT, "", "", "", "" }, /* 54 shift */
{ KP, "*", "*", "*", "*" }, /* 55 kp * */
{ ALT, "", "", "", "" }, /* 56 alt */
{ ASCII, " ", " ", "\000", " " }, /* 57 space */
{ CAPS, "", "", "", "" }, /* 58 caps */
{ FUNC, "\033[M", "\033[Y", "\033[k", "" }, /* 59 f1 */
{ FUNC, "\033[N", "\033[Z", "\033[l", "" }, /* 60 f2 */
{ FUNC, "\033[O", "\033[a", "\033[m", "" }, /* 61 f3 */
{ FUNC, "\033[P", "\033[b", "\033[n", "" }, /* 62 f4 */
{ FUNC, "\033[Q", "\033[c", "\033[o", "" }, /* 63 f5 */
{ FUNC, "\033[R", "\033[d", "\033[p", "" }, /* 64 f6 */
{ FUNC, "\033[S", "\033[e", "\033[q", "" }, /* 65 f7 */
{ FUNC, "\033[T", "\033[f", "\033[r", "" }, /* 66 f8 */
{ FUNC, "\033[U", "\033[g", "\033[s", "" }, /* 67 f9 */
{ FUNC, "\033[V", "\033[h", "\033[t", "" }, /* 68 f10 */
{ NUM, "", "", "", "" }, /* 69 num lock */
{ SCROLL, "", "", "", "" }, /* 70 scroll lock */
{ KP, "7", "\033[H", "7", "" }, /* 71 kp 7 */
{ KP, "8", "\033[A", "8", "" }, /* 72 kp 8 */
{ KP, "9", "\033[I", "9", "" }, /* 73 kp 9 */
{ KP, "-", "-", "-", "" }, /* 74 kp - */
{ KP, "4", "\033[D", "4", "" }, /* 75 kp 4 */
{ KP, "5", "\033[E", "5", "" }, /* 76 kp 5 */
{ KP, "6", "\033[C", "6", "" }, /* 77 kp 6 */
{ KP, "+", "+", "+", "" }, /* 78 kp + */
{ KP, "1", "\033[F", "1", "" }, /* 79 kp 1 */
{ KP, "2", "\033[B", "2", "" }, /* 80 kp 2 */
{ KP, "3", "\033[G", "3", "" }, /* 81 kp 3 */
{ KP, "0", "\033[L", "0", "" }, /* 82 kp 0 */
{ KP, ".", "\177", ".", "" }, /* 83 kp . */
{ NONE, "", "", "", "" }, /* 84 0 */
{ NONE, "100", "", "", "" }, /* 85 0 */
{ ASCII, "<", ">", "<", "|" }, /* 86 < > */
{ FUNC, "\033[W", "\033[i", "\033[u","" }, /* 87 f11 */
{ FUNC, "\033[X", "\033[j", "\033[v","" }, /* 88 f12 */
{ NONE, "102", "", "", "" }, /* 89 0 */
{ NONE, "103", "", "", "" }, /* 90 0 */
{ NONE, "", "", "", "" }, /* 91 0 */
{ NONE, "", "", "", "" }, /* 92 0 */
{ NONE, "", "", "", "" }, /* 93 0 */
{ NONE, "", "", "", "" }, /* 94 0 */
{ NONE, "", "", "", "" }, /* 95 0 */
{ NONE, "", "", "", "" }, /* 96 0 */
{ NONE, "", "", "", "" }, /* 97 0 */
{ NONE, "", "", "", "" }, /* 98 0 */
{ NONE, "", "", "", "" }, /* 99 0 */
{ NONE, "", "", "", "" }, /* 100 */
{ NONE, "", "", "", "" }, /* 101 */
{ NONE, "", "", "", "" }, /* 102 */
{ NONE, "", "", "", "" }, /* 103 */
{ NONE, "", "", "", "" }, /* 104 */
{ NONE, "", "", "", "" }, /* 105 */
{ NONE, "", "", "", "" }, /* 106 */
{ NONE, "", "", "", "" }, /* 107 */
{ NONE, "", "", "", "" }, /* 108 */
{ NONE, "", "", "", "" }, /* 109 */
{ NONE, "", "", "", "" }, /* 110 */
{ NONE, "", "", "", "" }, /* 111 */
{ NONE, "", "", "", "" }, /* 112 */
{ NONE, "", "", "", "" }, /* 113 */
{ NONE, "", "", "", "" }, /* 114 */
{ NONE, "", "", "", "" }, /* 115 */
{ NONE, "", "", "", "" }, /* 116 */
{ NONE, "", "", "", "" }, /* 117 */
{ NONE, "", "", "", "" }, /* 118 */
{ NONE, "", "", "", "" }, /* 119 */
{ NONE, "", "", "", "" }, /* 120 */
{ NONE, "", "", "", "" }, /* 121 */
{ NONE, "", "", "", "" }, /* 122 */
{ NONE, "", "", "", "" }, /* 123 */
{ NONE, "", "", "", "" }, /* 124 */
{ NONE, "", "", "", "" }, /* 125 */
{ NONE, "", "", "", "" }, /* 126 */
{ NONE, "", "", "", "" }, /* 127 */
};
#endif
/*
* XXXX Add tables for other keyboards here
*/
#endif
#if (NPCCONSKBD == 0)
char *
sget()
{
u_char dt, *capchar;
top:
KBD_DELAY;
dt = inb(IO_KBD + KBDATAP);
switch (dt) {
case KBR_ACK:
ack = 1;
goto loop;
case KBR_RESEND:
nak = 1;
goto loop;
}
capchar = strans(dt);
if (capchar)
return (capchar);
loop:
if ((inb(IO_KBD + KBSTATP) & KBS_DIB) == 0)
return (0);
goto top;
}
#endif
/*
* Get characters from the keyboard. If none are present, return NULL.
*/
char *
strans(dt)
u_char dt;
{
static u_char extended = 0, shift_state = 0;
static u_char capchar[2];
#ifdef XSERVER
if (pc_xmode > 0) {
#if defined(DDB) && defined(XSERVER_DDB)
/* F12 enters the debugger while in X mode */
if ((dt == 88) && !pccons_is_console)
Debugger();
#endif
capchar[0] = dt;
capchar[1] = 0;
/*
* Check for locking keys.
*
* XXX Setting the LEDs this way is a bit bogus. What if the
* keyboard has been remapped in X?
*/
switch (scan_codes[dt & 0x7f].type) {
case NUM:
if (dt & 0x80) {
shift_state &= ~NUM;
break;
}
if (shift_state & NUM)
break;
shift_state |= NUM;
lock_state ^= NUM;
update_leds();
break;
case CAPS:
if (dt & 0x80) {
shift_state &= ~CAPS;
break;
}
if (shift_state & CAPS)
break;
shift_state |= CAPS;
lock_state ^= CAPS;
update_leds();
break;
case SCROLL:
if (dt & 0x80) {
shift_state &= ~SCROLL;
break;
}
if (shift_state & SCROLL)
break;
shift_state |= SCROLL;
lock_state ^= SCROLL;
update_leds();
break;
}
return (capchar);
}
#endif /* XSERVER */
switch (dt) {
case KBR_EXTENDED0:
extended = 1;
return (0);
}
#ifdef DDB
/*
* Check for cntl-alt-esc.
*/
if ((dt == 1) && ((shift_state & (CTL | ALT)) == (CTL | ALT))
&& pccons_is_console) {
Debugger();
dt |= 0x80; /* discard esc (ddb discarded ctl-alt) */
}
#endif
/*
* Check for make/break.
*/
if (dt & 0x80) {
/*
* break
*/
dt &= 0x7f;
switch (scan_codes[dt].type) {
case NUM:
shift_state &= ~NUM;
break;
case CAPS:
shift_state &= ~CAPS;
break;
case SCROLL:
shift_state &= ~SCROLL;
break;
case SHIFT:
shift_state &= ~SHIFT;
break;
case ALT:
#ifdef NONUS_KBD
if (extended)
shift_state &= ~ALTGR;
else
#endif
shift_state &= ~ALT;
break;
case CTL:
shift_state &= ~CTL;
break;
}
} else {
/*
* make
*/
#ifdef NUMERIC_SLASH_FIX
/* fix numeric / on non US keyboard */
if (extended && dt == 53) {
capchar[0] = '/';
extended = 0;
return (capchar);
}
#endif
switch (scan_codes[dt].type) {
/*
* locking keys
*/
case NUM:
if (shift_state & NUM)
break;
shift_state |= NUM;
lock_state ^= NUM;
update_leds();
break;
case CAPS:
if (shift_state & CAPS)
break;
shift_state |= CAPS;
lock_state ^= CAPS;
update_leds();
break;
case SCROLL:
if (shift_state & SCROLL)
break;
shift_state |= SCROLL;
if ((lock_state & SCROLL) == 0)
capchar[0] = 'S' - '@';
else
capchar[0] = 'Q' - '@';
extended = 0;
return (capchar);
/*
* non-locking keys
*/
case SHIFT:
shift_state |= SHIFT;
break;
case ALT:
#ifdef NONUS_KBD
if (extended)
shift_state |= ALTGR;
else
#endif
shift_state |= ALT;
break;
case CTL:
shift_state |= CTL;
break;
case ASCII:
#ifdef NONUS_KBD
if (shift_state & ALTGR) {
capchar[0] = scan_codes[dt].altgr[0];
if (shift_state & CTL)
capchar[0] &= 0x1f;
} else
#endif
/* control has highest priority */
if (shift_state & CTL)
capchar[0] = scan_codes[dt].ctl[0];
else if (shift_state & SHIFT)
capchar[0] = scan_codes[dt].shift[0];
else
capchar[0] = scan_codes[dt].unshift[0];
if ((lock_state & CAPS) && capchar[0] >= 'a' &&
capchar[0] <= 'z') {
capchar[0] -= ('a' - 'A');
}
capchar[0] |= (shift_state & ALT);
extended = 0;
return (capchar);
case NONE:
break;
case FUNC: {
char *more_chars;
if (shift_state & SHIFT)
more_chars = scan_codes[dt].shift;
else if (shift_state & CTL)
more_chars = scan_codes[dt].ctl;
else
more_chars = scan_codes[dt].unshift;
extended = 0;
return (more_chars);
}
case KP: {
char *more_chars;
if (shift_state & (SHIFT | CTL) ||
(lock_state & NUM) == 0 || extended)
more_chars = scan_codes[dt].shift;
else
more_chars = scan_codes[dt].unshift;
extended = 0;
return (more_chars);
}
}
}
extended = 0;
return (0);
}
paddr_t
pcmmap(dev, offset, nprot)
dev_t dev;
off_t offset;
int nprot;
{
if (offset > 0x20000)
return (-1);
return (i386_btop(0xa0000 + offset));
}
#ifdef XSERVER
void
pc_xmode_on()
{
#ifdef COMPAT_10
struct trapframe *fp;
#endif
if (pc_xmode)
return;
pc_xmode = 1;
#ifdef XFREE86_BUG_COMPAT
/* If still unchanged, get current shape. */
if (cursor_shape == 0xffff)
get_cursor_shape();
#endif
#ifdef COMPAT_10
/* This is done by i386_iopl(3) now. */
fp = curproc->p_md.md_regs;
fp->tf_eflags |= PSL_IOPL;
#endif
}
void
pc_xmode_off()
{
struct trapframe *fp;
if (pc_xmode == 0)
return;
pc_xmode = 0;
#ifdef XFREE86_BUG_COMPAT
/* XXX It would be hard to justify why the X server doesn't do this. */
set_cursor_shape();
#endif
async_update();
fp = curproc->p_md.md_regs;
fp->tf_eflags &= ~PSL_IOPL;
}
#endif /* XSERVER */