summaryrefslogtreecommitdiffstats
path: root/sys/isa
diff options
context:
space:
mode:
Diffstat (limited to 'sys/isa')
-rw-r--r--sys/isa/atrtc.c539
-rw-r--r--sys/isa/fd.c1255
-rw-r--r--sys/isa/fdc.h75
-rw-r--r--sys/isa/fdreg.h65
-rw-r--r--sys/isa/ic/nec765.h72
-rw-r--r--sys/isa/ic/ns16550.h51
-rw-r--r--sys/isa/kbdtables.h859
-rw-r--r--sys/isa/rtc.h109
-rw-r--r--sys/isa/sio.c1957
-rw-r--r--sys/isa/sioreg.h114
-rw-r--r--sys/isa/syscons.c2707
-rw-r--r--sys/isa/timerreg.h93
12 files changed, 7896 insertions, 0 deletions
diff --git a/sys/isa/atrtc.c b/sys/isa/atrtc.c
new file mode 100644
index 0000000..e72d6a3
--- /dev/null
+++ b/sys/isa/atrtc.c
@@ -0,0 +1,539 @@
+/*-
+ * 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.
+ *
+ * from: @(#)clock.c 7.2 (Berkeley) 5/12/91
+ * $Id: clock.c,v 1.15 1994/08/18 05:09:21 davidg Exp $
+ */
+
+/*
+ * Primitive clock interrupt routines.
+ */
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/time.h>
+#include <sys/kernel.h>
+#include <machine/segments.h>
+#include <machine/frame.h>
+#include <i386/isa/icu.h>
+#include <i386/isa/isa.h>
+#include <i386/isa/rtc.h>
+#include <i386/isa/timerreg.h>
+#include <machine/cpu.h>
+
+/* X-tals being what they are, it's nice to be able to fudge this one... */
+/* Note, the name changed here from XTALSPEED to TIMER_FREQ rgrimes 4/26/93 */
+#ifndef TIMER_FREQ
+#define TIMER_FREQ 1193182 /* XXX - should be in isa.h */
+#endif
+#define TIMER_DIV(x) ((TIMER_FREQ+(x)/2)/(x))
+
+static int beeping;
+int timer0_divisor = TIMER_DIV(100); /* XXX should be hz */
+u_int timer0_prescale;
+static char timer0_state = 0, timer2_state = 0;
+static char timer0_reprogram = 0;
+static void (*timer_func)() = hardclock;
+static void (*new_function)();
+static u_int new_rate;
+static u_int hardclock_divisor;
+
+#ifdef I586_CPU
+int pentium_mhz = 0;
+#endif
+
+void
+clkintr(frame)
+ struct clockframe frame;
+{
+#ifdef I586_CPU
+ /*
+ * This resets the CPU cycle counter to zero, to make our
+ * job easier in microtime(). Some fancy ifdefs could speed
+ * this up for Pentium-only kernels.
+ * We want this to be done as close as possible to the actual
+ * timer incrementing in hardclock(), because there is a window
+ * between the two where the value is no longer valid. Experimentation
+ * may reveal a good precompensation to apply in microtime().
+ */
+ if(pentium_mhz) {
+ __asm __volatile("movl $0x10,%%ecx\n"
+ "xorl %%eax,%%eax\n"
+ "movl %%eax,%%edx\n"
+ ".byte 0x0f, 0x30\n"
+ "#%0%1"
+ : "=m"(frame) /* no outputs */
+ : "b"(&frame) /* fake input */
+ : "ax", "cx", "dx");
+ }
+#endif
+ hardclock(&frame);
+}
+
+static u_char rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF;
+
+/*
+ * This routine receives statistical clock interrupts from the RTC.
+ * As explained above, these occur at 128 interrupts per second.
+ * When profiling, we receive interrupts at a rate of 1024 Hz.
+ *
+ * This does not actually add as much overhead as it sounds, because
+ * when the statistical clock is active, the hardclock driver no longer
+ * needs to keep (inaccurate) statistics on its own. This decouples
+ * statistics gathering from scheduling interrupts.
+ *
+ * The RTC chip requires that we read status register C (RTC_INTR)
+ * to acknowledge an interrupt, before it will generate the next one.
+ */
+void
+rtcintr(struct clockframe frame)
+{
+ u_char stat;
+ stat = rtcin(RTC_INTR);
+ if(stat & RTCIR_PERIOD) {
+ statclock(&frame);
+ }
+}
+
+#ifdef DEBUG
+void
+printrtc(void)
+{
+ outb(IO_RTC, RTC_STATUSA);
+ printf("RTC status A = %x", inb(IO_RTC+1));
+ outb(IO_RTC, RTC_STATUSB);
+ printf(", B = %x", inb(IO_RTC+1));
+ outb(IO_RTC, RTC_INTR);
+ printf(", C = %x\n", inb(IO_RTC+1));
+}
+#endif
+
+#if 0
+void
+timerintr(struct clockframe frame)
+{
+ timer_func(&frame);
+ switch (timer0_state) {
+ case 0:
+ break;
+ case 1:
+ if ((timer0_prescale+=timer0_divisor) >= hardclock_divisor) {
+ hardclock(&frame);
+ timer0_prescale = 0;
+ }
+ break;
+ case 2:
+ disable_intr();
+ outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
+ outb(TIMER_CNTR0, TIMER_DIV(new_rate)%256);
+ outb(TIMER_CNTR0, TIMER_DIV(new_rate)/256);
+ enable_intr();
+ timer0_divisor = TIMER_DIV(new_rate);
+ timer0_prescale = 0;
+ timer_func = new_function;
+ timer0_state = 1;
+ break;
+ case 3:
+ if ((timer0_prescale+=timer0_divisor) >= hardclock_divisor) {
+ hardclock(&frame);
+ disable_intr();
+ outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
+ outb(TIMER_CNTR0, TIMER_DIV(hz)%256);
+ outb(TIMER_CNTR0, TIMER_DIV(hz)/256);
+ enable_intr();
+ timer0_divisor = TIMER_DIV(hz);
+ timer0_prescale = 0;
+ timer_func = hardclock;;
+ timer0_state = 0;
+ }
+ break;
+ }
+}
+
+#endif
+
+int
+acquire_timer0(int rate, void (*function)() )
+{
+ if (timer0_state || !function)
+ return -1;
+
+ new_function = function;
+ new_rate = rate;
+ timer0_state = 2;
+ return 0;
+}
+
+
+int
+acquire_timer2(int mode)
+{
+ if (timer2_state)
+ return -1;
+ timer2_state = 1;
+ outb(TIMER_MODE, TIMER_SEL2 | (mode &0x3f));
+ return 0;
+}
+
+
+int
+release_timer0()
+{
+ if (!timer0_state)
+ return -1;
+ timer0_state = 3;
+ return 0;
+}
+
+
+int
+release_timer2()
+{
+ if (!timer2_state)
+ return -1;
+ timer2_state = 0;
+ outb(TIMER_MODE, TIMER_SEL2|TIMER_SQWAVE|TIMER_16BIT);
+ return 0;
+}
+
+
+static int
+getit()
+{
+ int high, low;
+
+ disable_intr();
+ /* select timer0 and latch counter value */
+ outb(TIMER_MODE, TIMER_SEL0);
+ low = inb(TIMER_CNTR0);
+ high = inb(TIMER_CNTR0);
+ enable_intr();
+ return ((high << 8) | low);
+}
+
+#ifdef I586_CPU
+static long long cycles_per_sec = 0;
+
+/*
+ * Figure out how fast the cyclecounter runs. This must be run with
+ * clock interrupts disabled, but with the timer/counter programmed
+ * and running.
+ */
+void
+calibrate_cyclecounter(void)
+{
+ volatile long edx, eax, lasteax, lastedx;
+
+ __asm __volatile(".byte 0x0f, 0x31" : "=a"(lasteax), "=d"(lastedx) : );
+ DELAY(1000000);
+ __asm __volatile(".byte 0x0f, 0x31" : "=a"(eax), "=d"(edx) : );
+
+ /*
+ * This assumes that you will never have a clock rate higher
+ * than 4GHz, probably a good assumption.
+ */
+ cycles_per_sec = (long long)edx + eax;
+ cycles_per_sec -= (long long)lastedx + lasteax;
+ pentium_mhz = ((long)cycles_per_sec + 500000) / 1000000; /* round up */
+}
+#endif
+
+/*
+ * Wait "n" microseconds.
+ * Relies on timer 1 counting down from (TIMER_FREQ / hz)
+ * Note: timer had better have been programmed before this is first used!
+ */
+void
+DELAY(int n)
+{
+ int counter_limit, prev_tick, tick, ticks_left, sec, usec;
+
+#ifdef DELAYDEBUG
+ int getit_calls = 1;
+ int n1;
+ static int state = 0;
+
+ if (state == 0) {
+ state = 1;
+ for (n1 = 1; n1 <= 10000000; n1 *= 10)
+ DELAY(n1);
+ state = 2;
+ }
+ if (state == 1)
+ printf("DELAY(%d)...", n);
+#endif
+ /*
+ * Read the counter first, so that the rest of the setup overhead is
+ * counted. Guess the initial overhead is 20 usec (on most systems it
+ * takes about 1.5 usec for each of the i/o's in getit(). The loop
+ * takes about 6 usec on a 486/33 and 13 usec on a 386/20. The
+ * multiplications and divisions to scale the count take a while).
+ */
+ prev_tick = getit(0, 0);
+ n -= 20;
+ /*
+ * Calculate (n * (TIMER_FREQ / 1e6)) without using floating point
+ * and without any avoidable overflows.
+ */
+ sec = n / 1000000;
+ usec = n - sec * 1000000;
+ ticks_left = sec * TIMER_FREQ
+ + usec * (TIMER_FREQ / 1000000)
+ + usec * ((TIMER_FREQ % 1000000) / 1000) / 1000
+ + usec * (TIMER_FREQ % 1000) / 1000000;
+
+ while (ticks_left > 0) {
+ tick = getit(0, 0);
+#ifdef DELAYDEBUG
+ ++getit_calls;
+#endif
+ if (tick > prev_tick)
+ ticks_left -= prev_tick - (tick - timer0_divisor);
+ else
+ ticks_left -= prev_tick - tick;
+ prev_tick = tick;
+ }
+#ifdef DELAYDEBUG
+ if (state == 1)
+ printf(" %d calls to getit() at %d usec each\n",
+ getit_calls, (n + 5) / getit_calls);
+#endif
+}
+
+
+static void
+sysbeepstop()
+{
+ outb(IO_PPI, inb(IO_PPI)&0xFC); /* disable counter2 output to speaker */
+ release_timer2();
+ beeping = 0;
+}
+
+
+int
+sysbeep(int pitch, int period)
+{
+
+ if (acquire_timer2(TIMER_SQWAVE|TIMER_16BIT))
+ return -1;
+ disable_intr();
+ outb(TIMER_CNTR2, pitch);
+ outb(TIMER_CNTR2, (pitch>>8));
+ enable_intr();
+ if (!beeping) {
+ outb(IO_PPI, inb(IO_PPI) | 3); /* enable counter2 output to speaker */
+ beeping = period;
+ timeout(sysbeepstop, 0, period);
+ }
+ return 0;
+}
+
+
+void
+startrtclock()
+{
+ int s;
+
+ /* initialize 8253 clock */
+ outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
+
+ /* Correct rounding will buy us a better precision in timekeeping */
+ outb (IO_TIMER1, TIMER_DIV(hz)%256);
+ outb (IO_TIMER1, TIMER_DIV(hz)/256);
+ timer0_divisor = hardclock_divisor = TIMER_DIV(hz);
+
+ /* initialize brain-dead battery powered clock */
+ outb (IO_RTC, RTC_STATUSA);
+ outb (IO_RTC+1, rtc_statusa);
+ outb (IO_RTC, RTC_STATUSB);
+ outb (IO_RTC+1, RTCSB_24HR);
+
+ outb (IO_RTC, RTC_DIAG);
+ if (s = inb (IO_RTC+1))
+ printf("RTC BIOS diagnostic error %b\n", s, RTCDG_BITS);
+}
+
+
+/* convert 2 digit BCD number */
+int
+bcd(int i)
+{
+ return ((i/16)*10 + (i%16));
+}
+
+
+/* convert years to seconds (from 1970) */
+unsigned long
+ytos(int y)
+{
+ int i;
+ unsigned long ret;
+
+ ret = 0;
+ for(i = 1970; i < y; i++) {
+ if (i % 4) ret += 365*24*60*60;
+ else ret += 366*24*60*60;
+ }
+ return ret;
+}
+
+
+/* convert months to seconds */
+unsigned long
+mtos(int m, int leap)
+{
+ int i;
+ unsigned long ret;
+
+ ret = 0;
+ for(i=1; i<m; i++) {
+ switch(i){
+ case 1: case 3: case 5: case 7: case 8: case 10: case 12:
+ ret += 31*24*60*60; break;
+ case 4: case 6: case 9: case 11:
+ ret += 30*24*60*60; break;
+ case 2:
+ if (leap) ret += 29*24*60*60;
+ else ret += 28*24*60*60;
+ }
+ }
+ return ret;
+}
+
+
+/*
+ * Initialize the time of day register, based on the time base which is, e.g.
+ * from a filesystem.
+ */
+void
+inittodr(time_t base)
+{
+ unsigned long sec;
+ int leap, day_week, t, yd;
+ int sa,s;
+
+ /* do we have a realtime clock present? (otherwise we loop below) */
+ sa = rtcin(RTC_STATUSA);
+ if (sa == 0xff || sa == 0) return;
+
+ /* ready for a read? */
+ while ((sa&RTCSA_TUP) == RTCSA_TUP)
+ sa = rtcin(RTC_STATUSA);
+
+ sec = bcd(rtcin(RTC_YEAR)) + 1900;
+ if (sec < 1970)
+ sec += 100;
+
+ leap = !(sec % 4); sec = ytos(sec); /* year */
+ yd = mtos(bcd(rtcin(RTC_MONTH)),leap); sec+=yd; /* month */
+ t = (bcd(rtcin(RTC_DAY))-1) * 24*60*60; sec+=t; yd+=t; /* date */
+ day_week = rtcin(RTC_WDAY); /* day */
+ sec += bcd(rtcin(RTC_HRS)) * 60*60; /* hour */
+ sec += bcd(rtcin(RTC_MIN)) * 60; /* minutes */
+ sec += bcd(rtcin(RTC_SEC)); /* seconds */
+ sec += tz.tz_minuteswest * 60;
+ time.tv_sec = sec;
+}
+
+
+#ifdef garbage
+/*
+ * Initialze the time of day register, based on the time base which is, e.g.
+ * from a filesystem.
+ */
+test_inittodr(time_t base)
+{
+
+ outb(IO_RTC,9); /* year */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,8); /* month */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,7); /* day */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,4); /* hour */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,2); /* minutes */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,0); /* seconds */
+ printf("%d\n",bcd(inb(IO_RTC+1)));
+
+ time.tv_sec = base;
+}
+#endif
+
+/*
+ * Wire clock interrupt in.
+ */
+void
+enablertclock()
+{
+ register_intr(/* irq */ 0, /* XXX id */ 0, /* flags */ 0, clkintr,
+ HWI_MASK | SWI_MASK, /* unit */ 0);
+ INTREN(IRQ0);
+ register_intr(/* irq */ 8, /* XXX id */ 1, /* flags */ 0, rtcintr,
+ SWI_CLOCK_MASK, /* unit */ 0);
+ INTREN(IRQ8);
+ outb(IO_RTC, RTC_STATUSB);
+ outb(IO_RTC+1, RTCSB_PINTR | RTCSB_24HR);
+}
+
+
+/*
+ * Delay for some number of milliseconds.
+ */
+void
+spinwait(int millisecs)
+{
+ DELAY(1000 * millisecs);
+}
+
+void
+cpu_initclocks()
+{
+ stathz = RTC_NOPROFRATE;
+ profhz = RTC_PROFRATE;
+ enablertclock();
+}
+
+void
+setstatclockrate(int newhz)
+{
+ if(newhz == RTC_PROFRATE) {
+ rtc_statusa = RTCSA_DIVIDER | RTCSA_PROF;
+ } else {
+ rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF;
+ }
+ outb(IO_RTC, RTC_STATUSA);
+ outb(IO_RTC+1, rtc_statusa);
+}
diff --git a/sys/isa/fd.c b/sys/isa/fd.c
new file mode 100644
index 0000000..61e385f9
--- /dev/null
+++ b/sys/isa/fd.c
@@ -0,0 +1,1255 @@
+/*#define DEBUG 1*/
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * 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.
+ *
+ * from: @(#)fd.c 7.4 (Berkeley) 5/25/91
+ * $Id: fd.c,v 1.27 1994/08/13 03:49:57 wollman Exp $
+ *
+ */
+
+#include "ft.h"
+#if NFT < 1
+#undef NFDC
+#endif
+#include "fd.h"
+
+#if NFDC > 0
+
+#include <sys/param.h>
+#include <sys/dkbad.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/conf.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <machine/ioctl_fd.h>
+#include <sys/disklabel.h>
+#include <sys/buf.h>
+#include <sys/uio.h>
+#include <sys/malloc.h>
+#include <sys/syslog.h>
+#include <i386/isa/isa.h>
+#include <i386/isa/isa_device.h>
+#include <i386/isa/fdreg.h>
+#include <i386/isa/fdc.h>
+#include <i386/isa/icu.h>
+#include <i386/isa/rtc.h>
+
+#if NFT > 0
+extern int ftopen(), ftintr(), ftattach(), ftclose(), ftioctl();
+#endif
+
+#define b_cylin b_resid
+#define FDBLK 512
+
+/* misuse a flag to identify format operation */
+#define B_FORMAT B_XXX
+
+#define NUMTYPES 14
+#define NUMDENS (NUMTYPES - 6)
+
+/* This defines (-1) must match index for fd_types */
+#define F_TAPE_TYPE 0x020 /* bit for fd_types to indicate tape */
+#define NO_TYPE 0 /* must match NO_TYPE in ft.c */
+#define FD_1720 1
+#define FD_1480 2
+#define FD_1440 3
+#define FD_1200 4
+#define FD_820 5
+#define FD_800 6
+#define FD_720 7
+#define FD_360 8
+
+#define FD_1480in5_25 9
+#define FD_1440in5_25 10
+#define FD_820in5_25 11
+#define FD_800in5_25 12
+#define FD_720in5_25 13
+#define FD_360in5_25 14
+
+
+struct fd_type fd_types[NUMTYPES] =
+{
+{ 21,2,0xFF,0x04,82,3444,1,FDC_500KBPS,2,0x0C,2 }, /* 1.72M in HD 3.5in */
+{ 18,2,0xFF,0x1B,82,2952,1,FDC_500KBPS,2,0x6C,1 }, /* 1.48M in HD 3.5in */
+{ 18,2,0xFF,0x1B,80,2880,1,FDC_500KBPS,2,0x6C,1 }, /* 1.44M in HD 3.5in */
+{ 15,2,0xFF,0x1B,80,2400,1,FDC_500KBPS,2,0x54,1 }, /* 1.2M in HD 5.25/3.5 */
+{ 10,2,0xFF,0x10,82,1640,1,FDC_250KBPS,2,0x2E,1 }, /* 820K in HD 3.5in */
+{ 10,2,0xFF,0x10,80,1600,1,FDC_250KBPS,2,0x2E,1 }, /* 800K in HD 3.5in */
+{ 9,2,0xFF,0x20,80,1440,1,FDC_250KBPS,2,0x50,1 }, /* 720K in HD 3.5in */
+{ 9,2,0xFF,0x2A,40, 720,1,FDC_250KBPS,2,0x50,1 }, /* 360K in DD 5.25in */
+
+{ 18,2,0xFF,0x02,82,2952,1,FDC_500KBPS,2,0x02,2 }, /* 1.48M in HD 5.25in */
+{ 18,2,0xFF,0x02,80,2880,1,FDC_500KBPS,2,0x02,2 }, /* 1.44M in HD 5.25in */
+{ 10,2,0xFF,0x10,82,1640,1,FDC_300KBPS,2,0x2E,1 }, /* 820K in HD 5.25in */
+{ 10,2,0xFF,0x10,80,1600,1,FDC_300KBPS,2,0x2E,1 }, /* 800K in HD 5.25in */
+{ 9,2,0xFF,0x20,80,1440,1,FDC_300KBPS,2,0x50,1 }, /* 720K in HD 5.25in */
+{ 9,2,0xFF,0x23,40, 720,2,FDC_300KBPS,2,0x50,1 }, /* 360K in HD 5.25in */
+};
+
+#define DRVS_PER_CTLR 2 /* 2 floppies */
+/***********************************************************************\
+* Per controller structure. *
+\***********************************************************************/
+struct fdc_data fdc_data[NFDC];
+
+/***********************************************************************\
+* Per drive structure. *
+* N per controller (DRVS_PER_CTLR) *
+\***********************************************************************/
+struct fd_data {
+ struct fdc_data *fdc; /* pointer to controller structure */
+ int fdsu; /* this units number on this controller */
+ int type; /* Drive type (HD, DD */
+ struct fd_type *ft; /* pointer to the type descriptor */
+ int flags;
+#define FD_OPEN 0x01 /* it's open */
+#define FD_ACTIVE 0x02 /* it's active */
+#define FD_MOTOR 0x04 /* motor should be on */
+#define FD_MOTOR_WAIT 0x08 /* motor coming up */
+ int skip;
+ int hddrv;
+ int track; /* where we think the head is */
+} fd_data[NFD];
+
+/***********************************************************************\
+* Throughout this file the following conventions will be used: *
+* fd is a pointer to the fd_data struct for the drive in question *
+* fdc is a pointer to the fdc_data struct for the controller *
+* fdu is the floppy drive unit number *
+* fdcu is the floppy controller unit number *
+* fdsu is the floppy drive unit number on that controller. (sub-unit) *
+\***********************************************************************/
+
+#define id_physid id_scsiid /* this biotab field doubles as a field */
+ /* for the physical unit number on the controller */
+
+static int retrier(fdcu_t);
+
+#define DEVIDLE 0
+#define FINDWORK 1
+#define DOSEEK 2
+#define SEEKCOMPLETE 3
+#define IOCOMPLETE 4
+#define RECALCOMPLETE 5
+#define STARTRECAL 6
+#define RESETCTLR 7
+#define SEEKWAIT 8
+#define RECALWAIT 9
+#define MOTORWAIT 10
+#define IOTIMEDOUT 11
+
+#ifdef DEBUG
+char *fdstates[] =
+{
+"DEVIDLE",
+"FINDWORK",
+"DOSEEK",
+"SEEKCOMPLETE",
+"IOCOMPLETE",
+"RECALCOMPLETE",
+"STARTRECAL",
+"RESETCTLR",
+"SEEKWAIT",
+"RECALWAIT",
+"MOTORWAIT",
+"IOTIMEDOUT"
+};
+
+
+int fd_debug = 1;
+#define TRACE0(arg) if(fd_debug) printf(arg)
+#define TRACE1(arg1,arg2) if(fd_debug) printf(arg1,arg2)
+#else /* DEBUG */
+#define TRACE0(arg)
+#define TRACE1(arg1,arg2)
+#endif /* DEBUG */
+
+static void fdstart(fdcu_t);
+void fdintr(fdcu_t);
+static timeout_t fd_turnoff;
+
+/****************************************************************************/
+/* autoconfiguration stuff */
+/****************************************************************************/
+static int fdprobe(struct isa_device *);
+static int fdattach(struct isa_device *);
+
+struct isa_driver fdcdriver = {
+ fdprobe, fdattach, "fdc",
+};
+
+/*
+ * probe for existance of controller
+ */
+int
+fdprobe(dev)
+ struct isa_device *dev;
+{
+ fdcu_t fdcu = dev->id_unit;
+ if(fdc_data[fdcu].flags & FDC_ATTACHED)
+ {
+ printf("fdc: same unit (%d) used multiple times\n",fdcu);
+ return 0;
+ }
+
+ fdc_data[fdcu].baseport = dev->id_iobase;
+
+ /* First - lets reset the floppy controller */
+
+ outb(dev->id_iobase+fdout,0);
+ DELAY(100);
+ outb(dev->id_iobase+fdout,FDO_FRST);
+
+ /* see if it can handle a command */
+ if (out_fdc(fdcu,NE7CMD_SPECIFY) < 0)
+ {
+ return(0);
+ }
+ out_fdc(fdcu,0xDF);
+ out_fdc(fdcu,2);
+ return (IO_FDCSIZE);
+}
+
+/*
+ * wire controller into system, look for floppy units
+ */
+int
+fdattach(dev)
+ struct isa_device *dev;
+{
+ unsigned fdt,st0, cyl;
+ int hdr;
+ fdu_t fdu;
+ fdcu_t fdcu = dev->id_unit;
+ fdc_p fdc = fdc_data + fdcu;
+ fd_p fd;
+ int fdsu;
+ struct isa_device *fdup;
+
+ fdc->fdcu = fdcu;
+ fdc->flags |= FDC_ATTACHED;
+ fdc->dmachan = dev->id_drq;
+ fdc->state = DEVIDLE;
+ hdr = 0;
+ printf("fdc%d:", fdcu);
+
+ /* check for each floppy drive */
+ for (fdup = isa_biotab_fdc; fdup->id_driver != 0; fdup++) {
+ if (fdup->id_iobase != dev->id_iobase)
+ continue;
+ fdu = fdup->id_unit;
+ fd = &fd_data[fdu];
+ if (fdu >= (NFD+NFT))
+ continue;
+ fdsu = fdup->id_physid;
+ /* look up what bios thinks we have */
+ switch (fdu) {
+ case 0: fdt = (rtcin(RTC_FDISKETTE) & 0xf0);
+ break;
+ case 1: fdt = ((rtcin(RTC_FDISKETTE) << 4) & 0xf0);
+ break;
+ default: fdt = RTCFDT_NONE;
+ break;
+ }
+ /* is there a unit? */
+ if ((fdt == RTCFDT_NONE)
+#if NFT > 0
+ || (fdsu >= DRVS_PER_CTLR)) {
+#else
+ ) {
+ fd->type = NO_TYPE;
+#endif
+#if NFT > 0
+ /* If BIOS says no floppy, or > 2nd device */
+ /* Probe for and attach a floppy tape. */
+ if (ftattach(dev, fdup))
+ continue;
+ if (fdsu < DRVS_PER_CTLR)
+ fd->type = NO_TYPE;
+#endif
+ continue;
+ }
+
+#ifdef notyet
+ /* select it */
+ fd_turnon1(fdu);
+ spinwait(1000); /* 1 sec */
+ out_fdc(fdcu,NE7CMD_RECAL); /* Recalibrate Function */
+ out_fdc(fdcu,fdsu);
+ spinwait(1000); /* 1 sec */
+
+ /* anything responding */
+ out_fdc(fdcu,NE7CMD_SENSEI);
+ st0 = in_fdc(fdcu);
+ cyl = in_fdc(fdcu);
+ if (st0 & 0xd0)
+ continue;
+
+#endif
+ fd->track = -2;
+ fd->fdc = fdc;
+ fd->fdsu = fdsu;
+ printf(" [%d: fd%d: ", fdsu, fdu);
+
+ switch (fdt) {
+ case RTCFDT_12M:
+ printf("1.2MB 5.25in]");
+ fd->type = FD_1200;
+ break;
+ case RTCFDT_144M:
+ printf("1.44MB 3.5in]");
+ fd->type = FD_1440;
+ break;
+ case RTCFDT_360K:
+ printf("360KB 5.25in]");
+ fd->type = FD_360;
+ break;
+ case RTCFDT_720K:
+ printf("720KB 3.5in]");
+ fd->type = FD_720;
+ break;
+ default:
+ printf("unknown]");
+ fd->type = NO_TYPE;
+ break;
+ }
+
+ fd_turnoff((caddr_t)fdu);
+ hdr = 1;
+ }
+ printf("\n");
+
+ /* Set transfer to 500kbps */
+ outb(fdc->baseport+fdctl,0); /*XXX*/
+ return 1;
+}
+
+int
+fdsize(dev)
+ dev_t dev;
+{
+ return(0);
+}
+
+/****************************************************************************/
+/* fdstrategy */
+/****************************************************************************/
+void fdstrategy(struct buf *bp)
+{
+ register struct buf *dp,*dp0,*dp1;
+ long nblocks,blknum;
+ int s;
+ fdcu_t fdcu;
+ fdu_t fdu;
+ fdc_p fdc;
+ fd_p fd;
+
+ fdu = FDUNIT(minor(bp->b_dev));
+ fd = &fd_data[fdu];
+ fdc = fd->fdc;
+ fdcu = fdc->fdcu;
+
+#if NFT > 0
+ /* check for controller already busy with tape */
+ if (fdc->flags & FDC_TAPE_BUSY) {
+ bp->b_error = EBUSY;
+ bp->b_flags |= B_ERROR;
+ return;
+ }
+#endif
+ if ((fdu >= NFD) || (bp->b_blkno < 0)) {
+ printf("fdstrat: fdu = %d, blkno = %d, bcount = %d\n",
+ fdu, bp->b_blkno, bp->b_bcount);
+ pg("fd:error in fdstrategy");
+ bp->b_error = EINVAL;
+ bp->b_flags |= B_ERROR;
+ goto bad;
+ }
+ /*
+ * Set up block calculations.
+ */
+ blknum = (unsigned long) bp->b_blkno * DEV_BSIZE/FDBLK;
+ nblocks = fd->ft->size;
+ if (blknum + (bp->b_bcount / FDBLK) > nblocks) {
+ if (blknum == nblocks) {
+ bp->b_resid = bp->b_bcount;
+ } else {
+ bp->b_error = ENOSPC;
+ bp->b_flags |= B_ERROR;
+ }
+ goto bad;
+ }
+ bp->b_cylin = blknum / (fd->ft->sectrac * fd->ft->heads);
+ bp->b_pblkno = bp->b_blkno;
+ dp = &(fdc->head);
+ s = splbio();
+ disksort(dp, bp);
+ untimeout(fd_turnoff, (caddr_t)fdu); /* a good idea */
+ fdstart(fdcu);
+ splx(s);
+ return;
+
+bad:
+ biodone(bp);
+ return;
+}
+
+/****************************************************************************/
+/* motor control stuff */
+/* remember to not deselect the drive we're working on */
+/****************************************************************************/
+void
+set_motor(fdcu, fdu, reset)
+ fdcu_t fdcu;
+ fdu_t fdu;
+ int reset;
+{
+ int m0,m1;
+ int selunit;
+ fd_p fd;
+ if(fd = fdc_data[fdcu].fd)/* yes an assign! */
+ {
+ selunit = fd->fdsu;
+ }
+ else
+ {
+ selunit = 0;
+ }
+ m0 = fd_data[fdcu * DRVS_PER_CTLR + 0].flags & FD_MOTOR;
+ m1 = fd_data[fdcu * DRVS_PER_CTLR + 1].flags & FD_MOTOR;
+ outb(fdc_data[fdcu].baseport+fdout,
+ selunit
+ | (reset ? 0 : (FDO_FRST|FDO_FDMAEN))
+ | (m0 ? FDO_MOEN0 : 0)
+ | (m1 ? FDO_MOEN1 : 0));
+ TRACE1("[0x%x->fdout]",(
+ selunit
+ | (reset ? 0 : (FDO_FRST|FDO_FDMAEN))
+ | (m0 ? FDO_MOEN0 : 0)
+ | (m1 ? FDO_MOEN1 : 0)));
+}
+
+static void
+fd_turnoff(void *arg1)
+{
+ fdu_t fdu = (fdu_t)arg1;
+ int s;
+
+ fd_p fd = fd_data + fdu;
+ s = splbio();
+ fd->flags &= ~FD_MOTOR;
+ set_motor(fd->fdc->fdcu,fd->fdsu,0);
+ splx(s);
+}
+
+void
+fd_motor_on(void *arg1)
+{
+ fdu_t fdu = (fdu_t)arg1;
+ int s;
+
+ fd_p fd = fd_data + fdu;
+ s = splbio();
+ fd->flags &= ~FD_MOTOR_WAIT;
+ if((fd->fdc->fd == fd) && (fd->fdc->state == MOTORWAIT))
+ {
+ fdintr(fd->fdc->fdcu);
+ }
+ splx(s);
+}
+
+static void fd_turnon1(fdu_t);
+
+void
+fd_turnon(fdu)
+ fdu_t fdu;
+{
+ fd_p fd = fd_data + fdu;
+ if(!(fd->flags & FD_MOTOR))
+ {
+ fd_turnon1(fdu);
+ fd->flags |= FD_MOTOR_WAIT;
+ timeout(fd_motor_on, (caddr_t)fdu, hz); /* in 1 sec its ok */
+ }
+}
+
+static void
+fd_turnon1(fdu_t fdu)
+{
+ fd_p fd = fd_data + fdu;
+ fd->flags |= FD_MOTOR;
+ set_motor(fd->fdc->fdcu,fd->fdsu,0);
+}
+
+/****************************************************************************/
+/* fdc in/out */
+/****************************************************************************/
+int
+in_fdc(fdcu)
+ fdcu_t fdcu;
+{
+ int baseport = fdc_data[fdcu].baseport;
+ int i, j = 100000;
+ while ((i = inb(baseport+fdsts) & (NE7_DIO|NE7_RQM))
+ != (NE7_DIO|NE7_RQM) && j-- > 0)
+ if (i == NE7_RQM) return -1;
+ if (j <= 0)
+ return(-1);
+#ifdef DEBUG
+ i = inb(baseport+fddata);
+ TRACE1("[fddata->0x%x]",(unsigned char)i);
+ return(i);
+#else
+ return inb(baseport+fddata);
+#endif
+}
+
+int
+out_fdc(fdcu, x)
+ fdcu_t fdcu;
+ int x;
+{
+ int baseport = fdc_data[fdcu].baseport;
+ int i;
+
+ /* Check that the direction bit is set */
+ i = 100000;
+ while ((inb(baseport+fdsts) & NE7_DIO) && i-- > 0);
+ if (i <= 0) return (-1); /* Floppy timed out */
+
+ /* Check that the floppy controller is ready for a command */
+ i = 100000;
+ while ((inb(baseport+fdsts) & NE7_RQM) == 0 && i-- > 0);
+ if (i <= 0) return (-1); /* Floppy timed out */
+
+ /* Send the command and return */
+ outb(baseport+fddata,x);
+ TRACE1("[0x%x->fddata]",x);
+ return (0);
+}
+
+/****************************************************************************/
+/* fdopen/fdclose */
+/****************************************************************************/
+int
+Fdopen(dev, flags)
+ dev_t dev;
+ int flags;
+{
+ fdu_t fdu = FDUNIT(minor(dev));
+ int type = FDTYPE(minor(dev));
+ fdc_p fdc;
+
+#if NFT > 0
+ /* check for a tape open */
+ if (type & F_TAPE_TYPE)
+ return(ftopen(dev, flags));
+#endif
+ /* check bounds */
+ if (fdu >= NFD)
+ return(ENXIO);
+ fdc = fd_data[fdu].fdc;
+ if ((fdc == NULL) || (fd_data[fdu].type == NO_TYPE))
+ return(ENXIO);
+ if (type > NUMDENS)
+ return(ENXIO);
+ if (type == 0)
+ type = fd_data[fdu].type;
+ else {
+ if (type != fd_data[fdu].type) {
+ switch (fd_data[fdu].type) {
+ case FD_360:
+ return(ENXIO);
+ case FD_720:
+ if ( type != FD_820
+ && type != FD_800
+ )
+ return(ENXIO);
+ break;
+ case FD_1200:
+ switch (type) {
+ case FD_1480:
+ type = FD_1480in5_25;
+ break;
+ case FD_1440:
+ type = FD_1440in5_25;
+ break;
+ case FD_820:
+ type = FD_820in5_25;
+ break;
+ case FD_800:
+ type = FD_800in5_25;
+ break;
+ case FD_720:
+ type = FD_720in5_25;
+ break;
+ case FD_360:
+ type = FD_360in5_25;
+ break;
+ default:
+ return(ENXIO);
+ }
+ break;
+ case FD_1440:
+ if ( type != FD_1720
+ && type != FD_1480
+ && type != FD_1200
+ && type != FD_820
+ && type != FD_800
+ && type != FD_720
+ )
+ return(ENXIO);
+ break;
+ }
+ }
+ }
+ fd_data[fdu].ft = fd_types + type - 1;
+ fd_data[fdu].flags |= FD_OPEN;
+
+ return 0;
+}
+
+int
+fdclose(dev, flags)
+ dev_t dev;
+ int flags;
+{
+ fdu_t fdu = FDUNIT(minor(dev));
+ int type = FDTYPE(minor(dev));
+
+#if NFT > 0
+ if (type & F_TAPE_TYPE)
+ return ftclose(0);
+#endif
+ fd_data[fdu].flags &= ~FD_OPEN;
+ return(0);
+}
+
+
+/***************************************************************\
+* fdstart *
+* We have just queued something.. if the controller is not busy *
+* then simulate the case where it has just finished a command *
+* So that it (the interrupt routine) looks on the queue for more*
+* work to do and picks up what we just added. *
+* If the controller is already busy, we need do nothing, as it *
+* will pick up our work when the present work completes *
+\***************************************************************/
+static void
+fdstart(fdcu)
+ fdcu_t fdcu;
+{
+ register struct buf *dp,*bp;
+ int s;
+ fdu_t fdu;
+
+ s = splbio();
+ if(fdc_data[fdcu].state == DEVIDLE)
+ {
+ fdintr(fdcu);
+ }
+ splx(s);
+}
+
+static void
+fd_timeout(void *arg1)
+{
+ fdcu_t fdcu = (fdcu_t)arg1;
+ fdu_t fdu = fdc_data[fdcu].fdu;
+ int st0, st3, cyl;
+ struct buf *dp,*bp;
+ int s;
+
+ dp = &fdc_data[fdcu].head;
+ s = splbio();
+ bp = dp->b_actf;
+
+ out_fdc(fdcu,NE7CMD_SENSED);
+ out_fdc(fdcu,fd_data[fdu].hddrv);
+ st3 = in_fdc(fdcu);
+
+ out_fdc(fdcu,NE7CMD_SENSEI);
+ st0 = in_fdc(fdcu);
+ cyl = in_fdc(fdcu);
+ printf("fd%d: Operation timeout ST0 %b cyl %d ST3 %b\n",
+ fdu,
+ st0,
+ NE7_ST0BITS,
+ cyl,
+ st3,
+ NE7_ST3BITS);
+
+ if (bp)
+ {
+ retrier(fdcu);
+ fdc_data[fdcu].status[0] = 0xc0;
+ fdc_data[fdcu].state = IOTIMEDOUT;
+ if( fdc_data[fdcu].retry < 6)
+ fdc_data[fdcu].retry = 6;
+ }
+ else
+ {
+ fdc_data[fdcu].fd = (fd_p) 0;
+ fdc_data[fdcu].fdu = -1;
+ fdc_data[fdcu].state = DEVIDLE;
+ }
+ fdintr(fdcu);
+ splx(s);
+}
+
+/* just ensure it has the right spl */
+static void
+fd_pseudointr(void *arg1)
+{
+ fdcu_t fdcu = (fdcu_t)arg1;
+ int s;
+ s = splbio();
+ fdintr(fdcu);
+ splx(s);
+}
+
+/***********************************************************************\
+* fdintr *
+* keep calling the state machine until it returns a 0 *
+* ALWAYS called at SPLBIO *
+\***********************************************************************/
+void
+fdintr(fdcu_t fdcu)
+{
+ fdc_p fdc = fdc_data + fdcu;
+#if NFT > 0
+ fdu_t fdu = fdc->fdu;
+
+ if (fdc->flags & FDC_TAPE_BUSY)
+ (ftintr(fdu));
+ else
+#endif
+ while(fdstate(fdcu, fdc))
+ ;
+}
+
+/***********************************************************************\
+* The controller state machine. *
+* if it returns a non zero value, it should be called again immediatly *
+\***********************************************************************/
+int
+fdstate(fdcu, fdc)
+ fdcu_t fdcu;
+ fdc_p fdc;
+{
+ int read, format, head, trac, sec = 0, i = 0, s, sectrac, cyl, st0;
+ unsigned long blknum;
+ fdu_t fdu = fdc->fdu;
+ fd_p fd;
+ register struct buf *dp,*bp;
+ struct fd_formb *finfo = NULL;
+
+ dp = &(fdc->head);
+ bp = dp->b_actf;
+ if(!bp)
+ {
+ /***********************************************\
+ * nothing left for this controller to do *
+ * Force into the IDLE state, *
+ \***********************************************/
+ fdc->state = DEVIDLE;
+ if(fdc->fd)
+ {
+ printf("unexpected valid fd pointer (fdu = %d)\n"
+ ,fdc->fdu);
+ fdc->fd = (fd_p) 0;
+ fdc->fdu = -1;
+ }
+ TRACE1("[fdc%d IDLE]",fdcu);
+ return(0);
+ }
+ fdu = FDUNIT(minor(bp->b_dev));
+ fd = fd_data + fdu;
+ if (fdc->fd && (fd != fdc->fd))
+ {
+ printf("confused fd pointers\n");
+ }
+ read = bp->b_flags & B_READ;
+ format = bp->b_flags & B_FORMAT;
+ if(format)
+ finfo = (struct fd_formb *)bp->b_un.b_addr;
+ TRACE1("fd%d",fdu);
+ TRACE1("[%s]",fdstates[fdc->state]);
+ TRACE1("(0x%x)",fd->flags);
+ untimeout(fd_turnoff, (caddr_t)fdu);
+ timeout(fd_turnoff, (caddr_t)fdu, 4 * hz);
+ switch (fdc->state)
+ {
+ case DEVIDLE:
+ case FINDWORK: /* we have found new work */
+ fdc->retry = 0;
+ fd->skip = 0;
+ fdc->fd = fd;
+ fdc->fdu = fdu;
+ outb(fdc->baseport+fdctl, fd->ft->trans);
+ /*******************************************************\
+ * If the next drive has a motor startup pending, then *
+ * it will start up in it's own good time *
+ \*******************************************************/
+ if(fd->flags & FD_MOTOR_WAIT)
+ {
+ fdc->state = MOTORWAIT;
+ return(0); /* come back later */
+ }
+ /*******************************************************\
+ * Maybe if it's not starting, it SHOULD be starting *
+ \*******************************************************/
+ if (!(fd->flags & FD_MOTOR))
+ {
+ fdc->state = MOTORWAIT;
+ fd_turnon(fdu);
+ return(0);
+ }
+ else /* at least make sure we are selected */
+ {
+ set_motor(fdcu,fd->fdsu,0);
+ }
+ fdc->state = DOSEEK;
+ break;
+ case DOSEEK:
+ if (bp->b_cylin == fd->track)
+ {
+ fdc->state = SEEKCOMPLETE;
+ break;
+ }
+ out_fdc(fdcu,NE7CMD_SEEK); /* Seek function */
+ out_fdc(fdcu,fd->fdsu); /* Drive number */
+ out_fdc(fdcu,bp->b_cylin * fd->ft->steptrac);
+ fd->track = -2;
+ fdc->state = SEEKWAIT;
+ timeout(fd_timeout, (caddr_t)fdcu, 2 * hz);
+ return(0); /* will return later */
+ case SEEKWAIT:
+ untimeout(fd_timeout, (caddr_t)fdcu);
+ /* allow heads to settle */
+ timeout(fd_pseudointr, (caddr_t)fdcu, hz / 50);
+ fdc->state = SEEKCOMPLETE;
+ return(0); /* will return later */
+ break;
+
+ case SEEKCOMPLETE : /* SEEK DONE, START DMA */
+ /* Make sure seek really happened*/
+ if(fd->track == -2)
+ {
+ int descyl = bp->b_cylin * fd->ft->steptrac;
+ out_fdc(fdcu,NE7CMD_SENSEI);
+ i = in_fdc(fdcu);
+ cyl = in_fdc(fdcu);
+ if (cyl != descyl)
+ {
+ printf("fd%d: Seek to cyl %d failed; am at cyl %d (ST0 = 0x%x)\n",
+ fdu, descyl, cyl, i, NE7_ST0BITS);
+ return(retrier(fdcu));
+ }
+ }
+
+ fd->track = bp->b_cylin;
+ if(format)
+ fd->skip = (char *)&(finfo->fd_formb_cylno(0))
+ - (char *)finfo;
+ isa_dmastart(bp->b_flags, bp->b_un.b_addr+fd->skip,
+ format ? bp->b_bcount : FDBLK, fdc->dmachan);
+ blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK
+ + fd->skip/FDBLK;
+ sectrac = fd->ft->sectrac;
+ sec = blknum % (sectrac * fd->ft->heads);
+ head = sec / sectrac;
+ sec = sec % sectrac + 1;
+/*XXX*/ fd->hddrv = ((head&1)<<2)+fdu;
+
+ if(format)
+ {
+ /* formatting */
+ out_fdc(fdcu,/* NE7CMD_FORMAT */ 0x4d);
+ out_fdc(fdcu,head << 2 | fdu);
+ out_fdc(fdcu,finfo->fd_formb_secshift);
+ out_fdc(fdcu,finfo->fd_formb_nsecs);
+ out_fdc(fdcu,finfo->fd_formb_gaplen);
+ out_fdc(fdcu,finfo->fd_formb_fillbyte);
+ }
+ else
+ {
+ if (read)
+ {
+ out_fdc(fdcu,NE7CMD_READ); /* READ */
+ }
+ else
+ {
+ out_fdc(fdcu,NE7CMD_WRITE); /* WRITE */
+ }
+ out_fdc(fdcu,head << 2 | fdu); /* head & unit */
+ out_fdc(fdcu,fd->track); /* track */
+ out_fdc(fdcu,head);
+ out_fdc(fdcu,sec); /* sector XXX +1? */
+ out_fdc(fdcu,fd->ft->secsize); /* sector size */
+ out_fdc(fdcu,sectrac); /* sectors/track */
+ out_fdc(fdcu,fd->ft->gap); /* gap size */
+ out_fdc(fdcu,fd->ft->datalen); /* data length */
+ }
+ fdc->state = IOCOMPLETE;
+ timeout(fd_timeout, (caddr_t)fdcu, 2 * hz);
+ return(0); /* will return later */
+ case IOCOMPLETE: /* IO DONE, post-analyze */
+ untimeout(fd_timeout, (caddr_t)fdcu);
+ for(i=0;i<7;i++)
+ {
+ fdc->status[i] = in_fdc(fdcu);
+ }
+ case IOTIMEDOUT: /*XXX*/
+ isa_dmadone(bp->b_flags, bp->b_un.b_addr+fd->skip,
+ format ? bp->b_bcount : FDBLK, fdc->dmachan);
+ if (fdc->status[0]&0xF8)
+ {
+ if (fdc->status[1] & 0x10) {
+ /*
+ * Operation not completed in reasonable time.
+ * Just restart it, don't increment retry count.
+ * (vak)
+ */
+ fdc->state = SEEKCOMPLETE;
+ return (1);
+ }
+ return(retrier(fdcu));
+ }
+ /* All OK */
+ fd->skip += FDBLK;
+ if (!format && fd->skip < bp->b_bcount)
+ {
+ /* set up next transfer */
+ blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK
+ + fd->skip/FDBLK;
+ bp->b_cylin = (blknum / (fd->ft->sectrac * fd->ft->heads));
+ fdc->state = DOSEEK;
+ }
+ else
+ {
+ /* ALL DONE */
+ fd->skip = 0;
+ bp->b_resid = 0;
+ dp->b_actf = bp->b_actf;
+ biodone(bp);
+ fdc->fd = (fd_p) 0;
+ fdc->fdu = -1;
+ fdc->state = FINDWORK;
+ }
+ return(1);
+ case RESETCTLR:
+ /* Try a reset, keep motor on */
+ set_motor(fdcu,fd->fdsu,1);
+ DELAY(100);
+ set_motor(fdcu,fd->fdsu,0);
+ outb(fdc->baseport+fdctl,fd->ft->trans);
+ TRACE1("[0x%x->fdctl]",fd->ft->trans);
+ fdc->retry++;
+ fdc->state = STARTRECAL;
+ break;
+ case STARTRECAL:
+ out_fdc(fdcu,NE7CMD_SPECIFY); /* specify command */
+ out_fdc(fdcu,0xDF);
+ out_fdc(fdcu,2);
+ out_fdc(fdcu,NE7CMD_RECAL); /* Recalibrate Function */
+ out_fdc(fdcu,fdu);
+ fdc->state = RECALWAIT;
+ return(0); /* will return later */
+ case RECALWAIT:
+ /* allow heads to settle */
+ timeout(fd_pseudointr, (caddr_t)fdcu, hz / 30);
+ fdc->state = RECALCOMPLETE;
+ return(0); /* will return later */
+ case RECALCOMPLETE:
+ out_fdc(fdcu,NE7CMD_SENSEI);
+ st0 = in_fdc(fdcu);
+ cyl = in_fdc(fdcu);
+ if (cyl != 0)
+ {
+ printf("fd%d: recal failed ST0 %b cyl %d\n", fdu,
+ st0, NE7_ST0BITS, cyl);
+ return(retrier(fdcu));
+ }
+ fd->track = 0;
+ /* Seek (probably) necessary */
+ fdc->state = DOSEEK;
+ return(1); /* will return immediatly */
+ case MOTORWAIT:
+ if(fd->flags & FD_MOTOR_WAIT)
+ {
+ return(0); /* time's not up yet */
+ }
+ fdc->state = DOSEEK;
+ return(1); /* will return immediatly */
+ default:
+ printf("Unexpected FD int->");
+ out_fdc(fdcu,NE7CMD_SENSEI);
+ st0 = in_fdc(fdcu);
+ cyl = in_fdc(fdcu);
+ printf("ST0 = %lx, PCN = %lx\n",i,sec);
+ out_fdc(fdcu,0x4A);
+ out_fdc(fdcu,fd->fdsu);
+ for(i=0;i<7;i++) {
+ fdc->status[i] = in_fdc(fdcu);
+ }
+ printf("intr status :%lx %lx %lx %lx %lx %lx %lx ",
+ fdc->status[0],
+ fdc->status[1],
+ fdc->status[2],
+ fdc->status[3],
+ fdc->status[4],
+ fdc->status[5],
+ fdc->status[6] );
+ return(0);
+ }
+ return(1); /* Come back immediatly to new state */
+}
+
+static int
+retrier(fdcu)
+ fdcu_t fdcu;
+{
+ fdc_p fdc = fdc_data + fdcu;
+ register struct buf *dp,*bp;
+
+ dp = &(fdc->head);
+ bp = dp->b_actf;
+
+ switch(fdc->retry)
+ {
+ case 0: case 1: case 2:
+ fdc->state = SEEKCOMPLETE;
+ break;
+ case 3: case 4: case 5:
+ fdc->state = STARTRECAL;
+ break;
+ case 6:
+ fdc->state = RESETCTLR;
+ break;
+ case 7:
+ break;
+ default:
+ {
+ dev_t sav_b_dev = bp->b_dev;
+ /* Trick diskerr */
+ bp->b_dev = makedev(major(bp->b_dev), (FDUNIT(minor(bp->b_dev))<<3)|3);
+ diskerr(bp, "fd", "hard error", LOG_PRINTF,
+ fdc->fd->skip, (struct disklabel *)NULL);
+ bp->b_dev = sav_b_dev;
+ printf(" (ST0 %b ", fdc->status[0], NE7_ST0BITS);
+ printf(" ST1 %b ", fdc->status[1], NE7_ST1BITS);
+ printf(" ST2 %b ", fdc->status[2], NE7_ST2BITS);
+ printf("cyl %d hd %d sec %d)\n",
+ fdc->status[3], fdc->status[4], fdc->status[5]);
+ }
+ bp->b_flags |= B_ERROR;
+ bp->b_error = EIO;
+ bp->b_resid = bp->b_bcount - fdc->fd->skip;
+ dp->b_actf = bp->b_actf;
+ fdc->fd->skip = 0;
+ biodone(bp);
+ fdc->state = FINDWORK;
+ fdc->fd = (fd_p) 0;
+ fdc->fdu = -1;
+ /* XXX abort current command, if any. */
+ return(1);
+ }
+ fdc->retry++;
+ return(1);
+}
+
+static int
+fdformat(dev, finfo, p)
+ dev_t dev;
+ struct fd_formb *finfo;
+ struct proc *p;
+{
+ fdu_t fdu;
+ fd_p fd;
+
+ struct buf *bp;
+ int rv = 0, s;
+
+ fdu = FDUNIT(minor(dev));
+ fd = &fd_data[fdu];
+
+ /* set up a buffer header for fdstrategy() */
+ bp = (struct buf *)malloc(sizeof(struct buf), M_TEMP, M_NOWAIT);
+ if(bp == 0)
+ return ENOBUFS;
+ bzero((void *)bp, sizeof(struct buf));
+ bp->b_flags = B_BUSY | B_PHYS | B_FORMAT;
+ bp->b_proc = p;
+ bp->b_dev = dev;
+
+ /*
+ * calculate a fake blkno, so fdstrategy() would initiate a
+ * seek to the requested cylinder
+ */
+ bp->b_blkno = (finfo->cyl * (fd->ft->sectrac * fd->ft->heads)
+ + finfo->head * fd->ft->sectrac) * FDBLK / DEV_BSIZE;
+
+ bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs;
+ bp->b_un.b_addr = (caddr_t)finfo;
+
+ /* now do the format */
+ fdstrategy(bp);
+
+ /* ...and wait for it to complete */
+ s = splbio();
+ while(!(bp->b_flags & B_DONE))
+ {
+ rv = tsleep((caddr_t)bp, PRIBIO, "fdform", 20 * hz);
+ if(rv == EWOULDBLOCK)
+ break;
+ }
+ splx(s);
+
+ if(rv == EWOULDBLOCK)
+ {
+ /* timed out */
+ biodone(bp);
+ rv = EIO;
+ }
+ free(bp, M_TEMP);
+ return rv;
+}
+
+/*
+ * fdioctl() from jc@irbs.UUCP (John Capo)
+ * i386/i386/conf.c needs to have fdioctl() declared and remove the line that
+ * defines fdioctl to be enxio.
+ *
+ * TODO: Reformat.
+ * Think about allocating buffer off stack.
+ * Don't pass uncast 0's and NULL's to read/write/setdisklabel().
+ * Watch out for NetBSD's different *disklabel() interface.
+ *
+ * Added functionality for floppy formatting
+ * joerg_wunsch@uriah.sax.de (Joerg Wunsch)
+ */
+
+int
+fdioctl (dev, cmd, addr, flag, p)
+ dev_t dev;
+ int cmd;
+ caddr_t addr;
+ int flag;
+ struct proc *p;
+{
+ struct fd_type *fdt;
+ struct disklabel *dl;
+ char buffer[DEV_BSIZE];
+ int error;
+
+#if NFT > 0
+ int type = FDTYPE(minor(dev));
+
+ /* check for a tape ioctl */
+ if (type & F_TAPE_TYPE)
+ return ftioctl(dev, cmd, addr, flag, p);
+#endif
+
+ error = 0;
+
+ switch (cmd)
+ {
+ case DIOCGDINFO:
+ bzero(buffer, sizeof (buffer));
+ dl = (struct disklabel *)buffer;
+ dl->d_secsize = FDBLK;
+ fdt = fd_data[FDUNIT(minor(dev))].ft;
+ dl->d_secpercyl = fdt->size / fdt->tracks;
+ dl->d_type = DTYPE_FLOPPY;
+
+ if (readdisklabel(dev, fdstrategy, dl, NULL, 0, 0) == NULL)
+ error = 0;
+ else
+ error = EINVAL;
+
+ *(struct disklabel *)addr = *dl;
+ break;
+
+ case DIOCSDINFO:
+ if ((flag & FWRITE) == 0)
+ error = EBADF;
+ break;
+
+ case DIOCWLABEL:
+ if ((flag & FWRITE) == 0)
+ error = EBADF;
+ break;
+
+ case DIOCWDINFO:
+ if ((flag & FWRITE) == 0)
+ {
+ error = EBADF;
+ break;
+ }
+
+ dl = (struct disklabel *)addr;
+
+ if (error = setdisklabel ((struct disklabel *)buffer,
+ dl, 0, NULL))
+ break;
+
+ error = writedisklabel(dev, fdstrategy,
+ (struct disklabel *)buffer, NULL);
+ break;
+
+ case FD_FORM:
+ if((flag & FWRITE) == 0)
+ error = EBADF; /* must be opened for writing */
+ else if(((struct fd_formb *)addr)->format_version !=
+ FD_FORMAT_VERSION)
+ error = EINVAL; /* wrong version of formatting prog */
+ else
+ error = fdformat(dev, (struct fd_formb *)addr, p);
+ break;
+
+ case FD_GTYPE: /* get drive type */
+ *(struct fd_type *)addr = *fd_data[FDUNIT(minor(dev))].ft;
+ break;
+
+ default:
+ error = EINVAL;
+ break;
+ }
+ return (error);
+}
+
+#endif
diff --git a/sys/isa/fdc.h b/sys/isa/fdc.h
new file mode 100644
index 0000000..1542f0e
--- /dev/null
+++ b/sys/isa/fdc.h
@@ -0,0 +1,75 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 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.
+ *
+ * from: @(#)fd.c 7.4 (Berkeley) 5/25/91
+ * $Id:$
+ *
+ */
+
+
+/***********************************************************************\
+* Per controller structure. *
+\***********************************************************************/
+struct fdc_data
+{
+ int fdcu; /* our unit number */
+ int baseport;
+ int dmachan;
+ int flags;
+#define FDC_ATTACHED 0x01
+#define FDC_HASFTAPE 0x02
+#define FDC_TAPE_BUSY 0x04
+ struct fd_data *fd;
+ int fdu; /* the active drive */
+ struct buf head; /* Head of buf chain */
+ struct buf rhead; /* Raw head of buf chain */
+ int state;
+ int retry;
+ int status[7]; /* copy of the registers */
+};
+
+/***********************************************************************\
+* Throughout this file the following conventions will be used: *
+* fd is a pointer to the fd_data struct for the drive in question *
+* fdc is a pointer to the fdc_data struct for the controller *
+* fdu is the floppy drive unit number *
+* fdcu is the floppy controller unit number *
+* fdsu is the floppy drive unit number on that controller. (sub-unit) *
+\***********************************************************************/
+typedef int fdu_t;
+typedef int fdcu_t;
+typedef int fdsu_t;
+typedef struct fd_data *fd_p;
+typedef struct fdc_data *fdc_p;
+
+#define FDUNIT(s) (((s)>>6)&03)
+#define FDTYPE(s) ((s)&077)
diff --git a/sys/isa/fdreg.h b/sys/isa/fdreg.h
new file mode 100644
index 0000000..d0d69e2
--- /dev/null
+++ b/sys/isa/fdreg.h
@@ -0,0 +1,65 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 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.
+ *
+ * from: @(#)fdreg.h 7.1 (Berkeley) 5/9/91
+ * $Id: fdreg.h,v 1.4 1994/02/07 22:12:42 alm Exp $
+ */
+
+/*
+ * AT floppy controller registers and bitfields
+ */
+
+/* uses NEC765 controller */
+#include <i386/isa/ic/nec765.h>
+
+/* registers */
+#define fdout 2 /* Digital Output Register (W) */
+#define FDO_FDSEL 0x03 /* floppy device select */
+#define FDO_FRST 0x04 /* floppy controller reset */
+#define FDO_FDMAEN 0x08 /* enable floppy DMA and Interrupt */
+#define FDO_MOEN0 0x10 /* motor enable drive 0 */
+#define FDO_MOEN1 0x20 /* motor enable drive 1 */
+#define FDO_MOEN2 0x30 /* motor enable drive 2 */
+#define FDO_MOEN3 0x40 /* motor enable drive 3 */
+
+#define fdsts 4 /* NEC 765 Main Status Register (R) */
+#define fddata 5 /* NEC 765 Data Register (R/W) */
+
+#define fdctl 7 /* Control Register (W) */
+#define FDC_500KBPS 0x00 /* 500KBPS MFM drive transfer rate */
+#define FDC_300KBPS 0x01 /* 300KBPS MFM drive transfer rate */
+#define FDC_250KBPS 0x02 /* 250KBPS MFM drive transfer rate */
+#define FDC_125KBPS 0x03 /* 125KBPS FM drive transfer rate */
+
+#define fdin 7 /* Digital Input Register (R) */
+#define FDI_DCHG 0x80 /* diskette has been changed */
+
diff --git a/sys/isa/ic/nec765.h b/sys/isa/ic/nec765.h
new file mode 100644
index 0000000..1895db7
--- /dev/null
+++ b/sys/isa/ic/nec765.h
@@ -0,0 +1,72 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 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.
+ *
+ * from: @(#)nec765.h 7.1 (Berkeley) 5/9/91
+ * $Id$
+ */
+
+/*
+ * Nec 765 floppy disc controller definitions
+ */
+
+/* Main status register */
+#define NE7_DAB 0x01 /* Diskette drive A is seeking, thus busy */
+#define NE7_DBB 0x02 /* Diskette drive B is seeking, thus busy */
+#define NE7_CB 0x10 /* Diskette Controller Busy */
+#define NE7_NDM 0x20 /* Diskette Controller in Non Dma Mode */
+#define NE7_DIO 0x40 /* Diskette Controller Data register I/O */
+#define NE7_RQM 0x80 /* Diskette Controller ReQuest for Master */
+
+/* Status register ST0 */
+#define NE7_ST0BITS "\020\010invld\007abnrml\006seek_cmplt\005drv_chck\004drive_rdy\003top_head"
+
+/* Status register ST1 */
+#define NE7_ST1BITS "\020\010end_of_cyl\006bad_crc\005data_overrun\003sec_not_fnd\002write_protect\001no_am"
+
+/* Status register ST2 */
+#define NE7_ST2BITS "\020\007ctrl_mrk\006bad_crc\005wrong_cyl\004scn_eq\003scn_not_fnd\002bad_cyl\001no_dam"
+
+/* Status register ST3 */
+#define NE7_ST3BITS "\020\010fault\007write_protect\006drdy\005tk0\004two_side\003side_sel\002"
+
+/* Commands */
+#define NE7CMD_SPECIFY 3 /* specify drive parameters - requires unit
+ parameters byte */
+#define NE7CMD_SENSED 4 /* sense drive - requires unit select byte */
+#define NE7CMD_WRITE 0xc5 /* write - requires eight additional bytes */
+#define NE7CMD_READ 0xe6 /* read - requires eight additional bytes */
+#define NE7CMD_FORMAT 0x4c /* format - requires five additional bytes */
+#define NE7CMD_RECAL 7 /* recalibrate drive - requires
+ unit select byte */
+#define NE7CMD_SENSEI 8 /* sense controller interrupt status */
+#define NE7CMD_SEEK 15 /* seek drive - requires unit select byte
+ and new cyl byte */
diff --git a/sys/isa/ic/ns16550.h b/sys/isa/ic/ns16550.h
new file mode 100644
index 0000000..ff59757
--- /dev/null
+++ b/sys/isa/ic/ns16550.h
@@ -0,0 +1,51 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 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.
+ *
+ * from: @(#)ns16550.h 7.1 (Berkeley) 5/9/91
+ * $Id$
+ */
+
+/*
+ * NS16550 UART registers
+ */
+
+#define com_data 0 /* data register (R/W) */
+#define com_dlbl 0 /* divisor latch low (W) */
+#define com_dlbh 1 /* divisor latch high (W) */
+#define com_ier 1 /* interrupt enable (W) */
+#define com_iir 2 /* interrupt identification (R) */
+#define com_fifo 2 /* FIFO control (W) */
+#define com_lctl 3 /* line control register (R/W) */
+#define com_cfcr 3 /* line control register (R/W) */
+#define com_mcr 4 /* modem control register (R/W) */
+#define com_lsr 5 /* line status register (R/W) */
+#define com_msr 6 /* modem status register (R/W) */
diff --git a/sys/isa/kbdtables.h b/sys/isa/kbdtables.h
new file mode 100644
index 0000000..a923c45
--- /dev/null
+++ b/sys/isa/kbdtables.h
@@ -0,0 +1,859 @@
+/*
+ * Copyright (C) 1992, 1993, 1994 Søren Schmidt
+ *
+ * This program is free software; you may redistribute it and/or
+ * modify it, provided that it retain the above copyright notice
+ * and the following disclaimer.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Søren Schmidt Email: sos@login.dkuug.dk
+ * Tritonvej 36 UUCP: ...uunet!dkuug!login!sos
+ * DK9210 Aalborg SO Phone: +45 9814 8076
+ *
+ * @(#)kbdtables.h 1.3 940123
+ * $Id: kbdtables.h,v 1.11 1994/02/01 09:27:43 ache Exp $
+ */
+
+#define SET8 0x80 /* eight bit for emacs SET8-key */
+
+#ifdef DKKEYMAP
+keymap_t key_map = { 0x69, /* DK iso8859 keymap */
+/* alt
+ * scan cntrl alt alt cntrl
+ * code base shift cntrl shift alt shift cntrl shift spcl flgs
+ * ---------------------------------------------------------------------------
+ */
+/* sc=00 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=01 */ 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, DBG, 0x1B, 0x02, 0x00,
+/* sc=02 */ '1', '!', NOP, NOP, '1', '!', NOP, NOP, 0x33, 0x00,
+/* sc=03 */ '2', '"', 0x00, 0x00, '@', '"', 0x00, 0x00, 0x00, 0x00,
+/* sc=04 */ '3', '#', NOP, NOP, 0x9E, '#', NOP, NOP, 0x33, 0x00,
+/* sc=05 */ '4', 0xA4, NOP, NOP, '$', 0xA4, NOP, NOP, 0x33, 0x00,
+/* sc=06 */ '5', '%', NOP, NOP, '5', '%', NOP, NOP, 0x33, 0x00,
+/* sc=07 */ '6', '&', NOP, NOP, '6', '&', NOP, NOP, 0x33, 0x00,
+/* sc=08 */ '7', '/', NOP, NOP, '{', '/', NOP, NOP, 0x33, 0x00,
+/* sc=09 */ '8', '(', 0x1B, 0x1B, '[', '(', 0x1B, 0x1B, 0x00, 0x00,
+/* sc=0a */ '9', ')', 0x1D, 0x1D, ']', ')', 0x1D, 0x1D, 0x00, 0x00,
+/* sc=0b */ '0', '=', NOP, NOP, '}', '=', NOP, NOP, 0x33, 0x00,
+/* sc=0c */ '+', '?', NOP, NOP, '+', '?', NOP, NOP, 0x33, 0x00,
+/* sc=0d */ '\'', '`', NOP, NOP, '|', '`', NOP, NOP, 0x33, 0x00,
+/* sc=0e */ 0x7F, 0x7F, 0x08, 0x08, 0x7F, 0x7F, 0x08, 0x08, 0x00, 0x00,
+/* sc=0f */ 0x09, 0x08, NOP, NOP, 0x09, 0x08, NOP, NOP, 0x33, 0x00,
+/* sc=10 */ 'q', 'Q', 0x11, 0x11, 'q', 'Q', 0x11, 0x11, 0x00, 0x01,
+/* sc=11 */ 'w', 'W', 0x17, 0x17, 'w', 'W', 0x17, 0x17, 0x00, 0x01,
+/* sc=12 */ 'e', 'E', 0x05, 0x05, 'e', 'E', 0x05, 0x05, 0x00, 0x01,
+/* sc=13 */ 'r', 'R', 0x12, 0x12, 'r', 'R', 0x12, 0x12, 0x00, 0x01,
+/* sc=14 */ 't', 'T', 0x14, 0x14, 't', 'T', 0x14, 0x14, 0x00, 0x01,
+/* sc=15 */ 'y', 'Y', 0x19, 0x19, 'y', 'Y', 0x19, 0x19, 0x00, 0x01,
+/* sc=16 */ 'u', 'U', 0x15, 0x15, 'u', 'U', 0x15, 0x15, 0x00, 0x01,
+/* sc=17 */ 'i', 'I', 0x09, 0x09, 'i', 'I', 0x09, 0x09, 0x00, 0x01,
+/* sc=18 */ 'o', 'O', 0x0F, 0x0F, 'o', 'O', 0x0F, 0x0F, 0x00, 0x01,
+/* sc=19 */ 'p', 'P', 0x10, 0x10, 'p', 'P', 0x10, 0x10, 0x00, 0x01,
+/* sc=1a */ 0xE5, 0xC5, NOP, NOP, 0x86, 0x8F, NOP, NOP, 0x33, 0x01,
+/* sc=1b */ '"', '^', 0x1E, 0x1E, '~', '^', 0x1E, 0x1E, 0x00, 0x00,
+/* sc=1c */ 0x0D, 0x0D, 0x0A, 0x0A, 0x0D, 0x0D, 0x0A, 0x0A, 0x00, 0x00,
+/* sc=1d */ LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, 0xFF, 0x00,
+/* sc=1e */ 'a', 'A', 0x01, 0x01, 'a', 'A', 0x01, 0x01, 0x00, 0x01,
+/* sc=1f */ 's', 'S', 0x13, 0x13, 's', 'S', 0x13, 0x13, 0x00, 0x01,
+/* sc=20 */ 'd', 'D', 0x04, 0x04, 'd', 'D', 0x04, 0x04, 0x00, 0x01,
+/* sc=21 */ 'f', 'F', 0x06, 0x06, 'f', 'F', 0x06, 0x06, 0x00, 0x01,
+/* sc=22 */ 'g', 'G', 0x07, 0x07, 'g', 'G', 0x07, 0x07, 0x00, 0x01,
+/* sc=23 */ 'h', 'H', 0x08, 0x08, 'h', 'H', 0x08, 0x08, 0x00, 0x01,
+/* sc=24 */ 'j', 'J', 0x0A, 0x0A, 'j', 'J', 0x0A, 0x0A, 0x00, 0x01,
+/* sc=25 */ 'k', 'K', 0x0B, 0x0B, 'k', 'K', 0x0B, 0x0B, 0x00, 0x01,
+/* sc=26 */ 'l', 'L', 0x0C, 0x0C, 'l', 'L', 0x0C, 0x0C, 0x00, 0x01,
+/* sc=27 */ 0xE6, 0xC6, NOP, NOP, 0x91, 0x92, NOP, NOP, 0x33, 0x01,
+/* sc=28 */ 0xF8, 0xD8, NOP, NOP, 0x9B, 0x9D, NOP, NOP, 0x33, 0x01,
+/* sc=29 */ 0xBD, 0xA7, NOP, NOP, 0xBD, 0xA7, NOP, NOP, 0x33, 0x00,
+/* sc=2a */ LSH, LSH, LSH, LSH, LSH, LSH, LSH, LSH, 0xFF, 0x00,
+/* sc=2b */ '\'', '*', NOP, NOP, '\'', '*', NOP, NOP, 0x33, 0x00,
+/* sc=2c */ 'z', 'Z', 0x1A, 0x1A, 'z', 'Z', 0x1A, 0x1A, 0x00, 0x01,
+/* sc=2d */ 'x', 'X', 0x18, 0x18, 'x', 'X', 0x18, 0x18, 0x00, 0x01,
+/* sc=2e */ 'c', 'C', 0x03, 0x03, 'c', 'C', 0x03, 0x03, 0x00, 0x01,
+/* sc=2f */ 'v', 'V', 0x16, 0x16, 'v', 'V', 0x16, 0x16, 0x00, 0x01,
+/* sc=30 */ 'b', 'B', 0x02, 0x02, 'b', 'B', 0x02, 0x02, 0x00, 0x01,
+/* sc=31 */ 'n', 'N', 0x0E, 0x0E, 'n', 'N', 0x0E, 0x0E, 0x00, 0x01,
+/* sc=32 */ 'm', 'M', 0x0D, 0x0D, 'm', 'M', 0x0D, 0x0D, 0x00, 0x01,
+/* sc=33 */ ',', ';', NOP, NOP, ',', ';', NOP, NOP, 0x33, 0x00,
+/* sc=34 */ '.', ':', NOP, NOP, '.', ':', NOP, NOP, 0x33, 0x00,
+/* sc=35 */ '-', '_', 0x1F, 0x1F, '-', '_', 0x1F, 0x1F, 0x00, 0x00,
+/* sc=36 */ RSH, RSH, RSH, RSH, RSH, RSH, RSH, RSH, 0xFF, 0x00,
+/* sc=37 */ '*', '*', '*', '*', '*', '*', '*', '*', 0x00, 0x00,
+/* sc=38 */ LALT, LALT, LALT, LALT, LALT, LALT, LALT, LALT, 0xFF, 0x00,
+/* sc=39 */ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 0x00, 0x00,
+/* sc=3a */ CLK, CLK, CLK, CLK, CLK, CLK, CLK, CLK, 0xFF, 0x00,
+/* sc=3b */ F( 1), F(13), F(25), F(37), S( 1), S(11), S( 1), S(11), 0xFF, 0x00,
+/* sc=3c */ F( 2), F(14), F(26), F(38), S( 2), S(12), S( 2), S(12), 0xFF, 0x00,
+/* sc=3d */ F( 3), F(15), F(27), F(39), S( 3), S(13), S( 3), S(13), 0xFF, 0x00,
+/* sc=3e */ F( 4), F(16), F(28), F(40), S( 4), S(14), S( 4), S(14), 0xFF, 0x00,
+/* sc=3f */ F( 5), F(17), F(29), F(41), S( 5), S(15), S( 5), S(15), 0xFF, 0x00,
+/* sc=40 */ F( 6), F(18), F(30), F(42), S( 6), S(16), S( 6), S(16), 0xFF, 0x00,
+/* sc=41 */ F( 7), F(19), F(31), F(43), S( 7), S( 7), S( 7), S( 7), 0xFF, 0x00,
+/* sc=42 */ F( 8), F(20), F(32), F(44), S( 8), S( 8), S( 8), S( 8), 0xFF, 0x00,
+/* sc=43 */ F( 9), F(21), F(33), F(45), S( 9), S( 9), S( 9), S( 9), 0xFF, 0x00,
+/* sc=44 */ F(10), F(22), F(34), F(46), S(10), S(10), S(10), S(10), 0xFF, 0x00,
+/* sc=45 */ NLK, NLK, NLK, NLK, NLK, NLK, NLK, NLK, 0xFF, 0x00,
+/* sc=46 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+/* sc=47 */ F(49), '7', '7', '7', '7', '7', '7', '7', 0x80, 0x02,
+/* sc=48 */ F(50), '8', '8', '8', '8', '8', '8', '8', 0x80, 0x02,
+/* sc=49 */ F(51), '9', '9', '9', '9', '9', '9', '9', 0x80, 0x02,
+/* sc=4a */ F(52), '-', '-', '-', '-', '-', '-', '-', 0x80, 0x02,
+/* sc=4b */ F(53), '4', '4', '4', '4', '4', '4', '4', 0x80, 0x02,
+/* sc=4c */ NOP, '5', '5', '5', '5', '5', '5', '5', 0x80, 0x02,
+/* sc=4d */ F(55), '6', '6', '6', '6', '6', '6', '6', 0x80, 0x02,
+/* sc=4e */ F(56), '+', '+', '+', '+', '+', '+', '+', 0x80, 0x02,
+/* sc=4f */ F(57), '1', '1', '1', '1', '1', '1', '1', 0x80, 0x02,
+/* sc=50 */ F(58), '2', '2', '2', '2', '2', '2', '2', 0x80, 0x02,
+/* sc=51 */ F(59), '3', '3', '3', '3', '3', '3', '3', 0x80, 0x02,
+/* sc=52 */ F(60), '0', '0', '0', '0', '0', '0', '0', 0x80, 0x02,
+/* sc=53 */ 0x7F, '.', 0x7F, 0x7F, 0x7F, 0x7F, RBT, 0x7F, 0x02, 0x02,
+/* sc=54 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=55 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=56 */ '<', '>', 0x1C, 0x1C, '\\', '>', 0x1C, 0x1C, 0x00, 0x00,
+/* sc=57 */ F(11), F(23), F(35), F(47), S(11), S(11), S(11), S(11), 0xFF, 0x00,
+/* sc=58 */ F(12), F(24), F(36), F(48), S(12), S(12), S(12), S(12), 0xFF, 0x00,
+/* sc=59 */ 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x00, 0x02,
+/* sc=5a */ RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, 0xFF, 0x00,
+/* sc=5b */ '/', '/', '/', '/', '/', '/', '/', '/', 0x00, 0x00,
+/* sc=5c */ NEXT, NOP, DBG, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=5d */ RALT, RALT, RALT, RALT, RALT, RALT, RALT, RALT, 0xFF, 0x00,
+/* sc=5e */ F(49), F(49), F(49), F(49), F(49), F(49), F(49), F(49), 0xFF, 0x00,
+/* sc=5f */ F(50), F(50), F(50), F(50), F(50), F(50), F(50), F(50), 0xFF, 0x00,
+/* sc=60 */ F(51), F(51), F(51), F(51), F(51), F(51), F(51), F(51), 0xFF, 0x00,
+/* sc=61 */ F(53), F(53), F(53), F(53), F(53), F(53), F(53), F(53), 0xFF, 0x00,
+/* sc=62 */ F(55), F(55), F(55), F(55), F(55), F(55), F(55), F(55), 0xFF, 0x00,
+/* sc=63 */ F(57), F(57), F(57), F(57), F(57), F(57), F(57), F(57), 0xFF, 0x00,
+/* sc=64 */ F(58), F(58), F(58), F(58), F(58), F(58), F(58), F(58), 0xFF, 0x00,
+/* sc=65 */ F(59), F(59), F(59), F(59), F(59), F(59), F(59), F(59), 0xFF, 0x00,
+/* sc=66 */ F(60), F(60), F(60), F(60), F(60), F(60), F(60), F(60), 0xFF, 0x00,
+/* sc=67 */ F(54), F(54), F(54), F(54), F(54), F(54), RBT, F(54), 0xFF, 0x00,
+/* sc=68 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+};
+#endif
+
+#ifdef UKKEYMAP
+keymap_t key_map = { 0x69, /* uk iso8859 keymap */
+/* alt
+ * scan cntrl alt alt cntrl
+ * code base shift cntrl shift alt shift cntrl shift spcl flgs
+ * ---------------------------------------------------------------------------
+ */
+/* sc=00 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=01 */ 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, DBG, 0x1B, 0x02, 0x00,
+/* sc=02 */ '1', '!', NOP, NOP, '`', '`', NOP, NOP, 0x33, 0x00,
+/* sc=03 */ '2', '"', 0x00, 0x00, '@', '@', 0x00, 0x00, 0x00, 0x00,
+/* sc=04 */ '3', 0xA3, NOP, NOP, '#', '#', NOP, NOP, 0x33, 0x00,
+/* sc=05 */ '4', '$', NOP, NOP, '4', '$', NOP, NOP, 0x33, 0x00,
+/* sc=06 */ '5', '%', NOP, NOP, '5', '%', NOP, NOP, 0x33, 0x00,
+/* sc=07 */ '6', '^', 0x1E, 0x1E, '^', '^', 0x1E, 0x1E, 0x00, 0x00,
+/* sc=08 */ '7', '&', NOP, NOP, '[', '[', 0x1B, 0x1B, 0x30, 0x00,
+/* sc=09 */ '8', '*', NOP, NOP, '8', '*', NOP, NOP, 0x33, 0x00,
+/* sc=0a */ '9', '(', NOP, NOP, ']', ']', 0x1D, 0x1D, 0x30, 0x00,
+/* sc=0b */ '0', ')', NOP, NOP, '{', '{', NOP, NOP, 0x33, 0x00,
+/* sc=0c */ '-', '_', 0x1F, 0x1F, '|', '|', 0x1F, 0x1F, 0x00, 0x00,
+/* sc=0d */ '=', '+', NOP, NOP, '}', '}', NOP, NOP, 0x33, 0x00,
+/* sc=0e */ 0x08, 0x08, 0x7F, 0x7F, 0x08, 0x08, 0x7F, 0x7F, 0x00, 0x00,
+/* sc=0f */ 0x09, 0x08, NOP, NOP, 0x09, 0x08, NOP, NOP, 0x77, 0x00,
+/* sc=10 */ 'q', 'Q', 0x11, 0x11, 'q', 'Q', 0x11, 0x11, 0x00, 0x01,
+/* sc=11 */ 'w', 'W', 0x17, 0x17, 'w', 'W', 0x17, 0x17, 0x00, 0x01,
+/* sc=12 */ 'e', 'E', 0x05, 0x05, 'e', 'E', 0x05, 0x05, 0x00, 0x01,
+/* sc=13 */ 'r', 'R', 0x12, 0x12, 'r', 'R', 0x12, 0x12, 0x00, 0x01,
+/* sc=14 */ 't', 'T', 0x14, 0x14, 't', 'T', 0x14, 0x14, 0x00, 0x01,
+/* sc=15 */ 'y', 'Y', 0x19, 0x19, 'y', 'Y', 0x19, 0x19, 0x00, 0x01,
+/* sc=16 */ 'u', 'U', 0x15, 0x15, 'u', 'U', 0x15, 0x15, 0x00, 0x01,
+/* sc=17 */ 'i', 'I', 0x09, 0x09, 'i', 'I', 0x09, 0x09, 0x00, 0x01,
+/* sc=18 */ 'o', 'O', 0x0F, 0x0F, 'o', 'O', 0x0F, 0x0F, 0x00, 0x01,
+/* sc=19 */ 'p', 'P', 0x10, 0x10, 'p', 'P', 0x10, 0x10, 0x00, 0x01,
+/* sc=1a */ '[', '{', 0x1B, 0x1B, '[', '{', 0x1B, 0x1B, 0x00, 0x00,
+/* sc=1b */ ']', '}', 0x1D, 0x1D, ']', '}', 0x1D, 0x1D, 0x00, 0x00,
+/* sc=1c */ 0x0D, 0x0D, 0x0A, 0x0A, 0x0D, 0x0D, 0x0A, 0x0A, 0x00, 0x00,
+/* sc=1d */ LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, 0xFF, 0x00,
+/* sc=1e */ 'a', 'A', 0x01, 0x01, 'a', 'A', 0x01, 0x01, 0x00, 0x01,
+/* sc=1f */ 's', 'S', 0x13, 0x13, 's', 'S', 0x13, 0x13, 0x00, 0x01,
+/* sc=20 */ 'd', 'D', 0x04, 0x04, 'd', 'D', 0x04, 0x04, 0x00, 0x01,
+/* sc=21 */ 'f', 'F', 0x06, 0x06, 'f', 'F', 0x06, 0x06, 0x00, 0x01,
+/* sc=22 */ 'g', 'G', 0x07, 0x07, 'g', 'G', 0x07, 0x07, 0x00, 0x01,
+/* sc=23 */ 'h', 'H', 0x08, 0x08, 'h', 'H', 0x08, 0x08, 0x00, 0x01,
+/* sc=24 */ 'j', 'J', 0x0A, 0x0A, 'j', 'J', 0x0A, 0x0A, 0x00, 0x01,
+/* sc=25 */ 'k', 'K', 0x0B, 0x0B, 'k', 'K', 0x0B, 0x0B, 0x00, 0x01,
+/* sc=26 */ 'l', 'L', 0x0C, 0x0C, 'l', 'L', 0x0C, 0x0C, 0x00, 0x01,
+/* sc=27 */ ';', ':', NOP, NOP, ';', ':', NOP, NOP, 0x33, 0x00,
+/* sc=28 */ '\'', '@', 0x00, 0x00, '\'', '@', 0x00, 0x00, 0x00, 0x00,
+/* sc=29 */ '\\', '|', 0x1C, 0x1C, '\\', '\\', 0x1C, 0x1C, 0x00, 0x00,
+/* sc=2a */ LSH, LSH, LSH, LSH, LSH, LSH, LSH, LSH, 0xFF, 0x00,
+/* sc=2b */ '#', '~', NOP, NOP, '~', '~', NOP, NOP, 0x33, 0x00,
+/* sc=2c */ 'z', 'Z', 0x1A, 0x1A, 'z', 'Z', 0x1A, 0x1A, 0x00, 0x01,
+/* sc=2d */ 'x', 'X', 0x18, 0x18, 'x', 'X', 0x18, 0x18, 0x00, 0x01,
+/* sc=2e */ 'c', 'C', 0x03, 0x03, 'c', 'C', 0x03, 0x03, 0x00, 0x01,
+/* sc=2f */ 'v', 'V', 0x16, 0x16, 'v', 'V', 0x16, 0x16, 0x00, 0x01,
+/* sc=30 */ 'b', 'B', 0x02, 0x02, 'b', 'B', 0x02, 0x02, 0x00, 0x01,
+/* sc=31 */ 'n', 'N', 0x0E, 0x0E, 'n', 'N', 0x0E, 0x0E, 0x00, 0x01,
+/* sc=32 */ 'm', 'M', 0x0D, 0x0D, 'm', 'M', 0x0D, 0x0D, 0x00, 0x01,
+/* sc=33 */ ',', '<', NOP, NOP, ',', '<', NOP, NOP, 0x33, 0x00,
+/* sc=34 */ '.', '>', NOP, NOP, '.', '>', NOP, NOP, 0x33, 0x00,
+/* sc=35 */ '/', '?', NOP, NOP, '/', '?', NOP, NOP, 0x33, 0x00,
+/* sc=36 */ RSH, RSH, RSH, RSH, RSH, RSH, RSH, RSH, 0xFF, 0x00,
+/* sc=37 */ '*', '*', 0x0A, 0x0A, '*', '*', 0x0A, 0x0A, 0x33, 0x00,
+/* sc=38 */ LALT, LALT, LALT, LALT, LALT, LALT, LALT, LALT, 0xFF, 0x00,
+/* sc=39 */ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 0x00, 0x00,
+/* sc=3a */ CLK, CLK, CLK, CLK, CLK, CLK, CLK, CLK, 0xFF, 0x00,
+/* sc=3b */ F( 1), F(13), F(25), F(37), S( 1), S(11), S( 1), S(11), 0xFF, 0x00,
+/* sc=3c */ F( 2), F(14), F(26), F(38), S( 2), S(12), S( 2), S(12), 0xFF, 0x00,
+/* sc=3d */ F( 3), F(15), F(27), F(39), S( 3), S(13), S( 3), S(13), 0xFF, 0x00,
+/* sc=3e */ F( 4), F(16), F(28), F(40), S( 4), S(14), S( 4), S(14), 0xFF, 0x00,
+/* sc=3f */ F( 5), F(17), F(29), F(41), S( 5), S(15), S( 5), S(15), 0xFF, 0x00,
+/* sc=40 */ F( 6), F(18), F(30), F(42), S( 6), S(16), S( 6), S(16), 0xFF, 0x00,
+/* sc=41 */ F( 7), F(19), F(31), F(43), S( 7), S( 7), S( 7), S( 7), 0xFF, 0x00,
+/* sc=42 */ F( 8), F(20), F(32), F(44), S( 8), S( 8), S( 8), S( 8), 0xFF, 0x00,
+/* sc=43 */ F( 9), F(21), F(33), F(45), S( 9), S( 9), S( 9), S( 9), 0xFF, 0x00,
+/* sc=44 */ F(10), F(22), F(34), F(46), S(10), S(10), S(10), S(10), 0xFF, 0x00,
+/* sc=45 */ NLK, NLK, 0x13, 0x13, NLK, NLK, 0x13, 0x13, 0xCC, 0x00,
+/* sc=46 */ SLK, SLK, 0x7F, 0x7F, SLK, SLK, 0x7F, 0x7F, 0xCC, 0x00,
+/* sc=47 */ F(49), '7', '7', '7', '7', '7', '7', '7', 0x80, 0x02,
+/* sc=48 */ F(50), '8', '8', '8', '8', '8', '8', '8', 0x80, 0x02,
+/* sc=49 */ F(51), '9', '9', '9', '9', '9', '9', '9', 0x80, 0x02,
+/* sc=4a */ F(52), '-', 0x1F, 0x1F, '-', '-', '-', '-', 0x80, 0x02,
+/* sc=4b */ F(53), '4', '4', '4', '4', '4', '4', '4', 0x80, 0x02,
+/* sc=4c */ F(54), '5', '5', '5', '5', '5', '5', '5', 0x80, 0x02,
+/* sc=4d */ F(55), '6', 0x1E, 0x1E, '6', '6', '6', '6', 0x80, 0x02,
+/* sc=4e */ F(56), '+', '+', '+', '+', '+', '+', '+', 0x80, 0x02,
+/* sc=4f */ F(57), '1', '1', '1', '1', '1', '1', '1', 0x80, 0x02,
+/* sc=50 */ F(58), '2', '2', '2', '2', '2', '2', '2', 0x80, 0x02,
+/* sc=51 */ F(59), '3', '3', '3', '3', '3', '3', '3', 0x80, 0x02,
+/* sc=52 */ F(60), '0', '0', '0', '0', '0', '0', '0', 0x80, 0x02,
+/* sc=53 */ 0x7F, '.', 0x7F, 0x7F, 0x7F, 0x7F, RBT, 0x7F, 0x02, 0x02,
+/* sc=54 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=55 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=56 */ '\\', '|', 0x1C, 0x1C, '\\', '|', 0x1C, 0x1C, 0x00, 0x00,
+/* sc=57 */ F(11), F(23), F(35), F(47), S(11), S(11), S(11), S(11), 0xFF, 0x00,
+/* sc=58 */ F(12), F(24), F(36), F(48), S(12), S(12), S(12), S(12), 0xFF, 0x00,
+/* sc=59 */ 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0xFF, 0x02,
+/* sc=5a */ RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, 0xFF, 0x00,
+/* sc=5b */ '/', '/', '/', '/', '/', '/', '/', '/', 0x00, 0x02,
+/* sc=5c */ NEXT, NOP, DBG, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=5d */ RALT, RALT, RALT, RALT, RALT, RALT, RALT, RALT, 0xFF, 0x00,
+/* sc=5e */ F(49), F(49), F(49), F(49), F(49), F(49), F(49), F(49), 0xFF, 0x00,
+/* sc=5f */ F(50), F(50), F(50), F(50), F(50), F(50), F(50), F(50), 0xFF, 0x00,
+/* sc=60 */ F(51), F(51), F(51), F(51), F(51), F(51), F(51), F(51), 0xFF, 0x00,
+/* sc=61 */ F(53), F(53), F(53), F(53), F(53), F(53), F(53), F(53), 0xFF, 0x00,
+/* sc=62 */ F(55), F(55), F(55), F(55), F(55), F(55), F(55), F(55), 0xFF, 0x00,
+/* sc=63 */ F(57), F(57), F(57), F(57), F(57), F(57), F(57), F(57), 0xFF, 0x00,
+/* sc=64 */ F(58), F(58), F(58), F(58), F(58), F(58), F(58), F(58), 0xFF, 0x00,
+/* sc=65 */ F(59), F(59), F(59), F(59), F(59), F(59), F(59), F(59), 0xFF, 0x00,
+/* sc=66 */ F(60), F(60), F(60), F(60), F(60), F(60), F(60), F(60), 0xFF, 0x00,
+/* sc=67 */ F(54), F(54), F(54), F(54), F(54), F(54), RBT, F(54), 0xFF, 0x00,
+/* sc=68 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+};
+#endif
+
+#ifdef GRKEYMAP
+keymap_t key_map = { 0x69, /* german iso8859 keymap */
+/* alt
+ * scan cntrl alt alt cntrl
+ * code base shift cntrl shift alt shift cntrl shift spcl flgs
+ * ---------------------------------------------------------------------------
+ */
+/* sc=00 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=01 */ 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, DBG, 0x1B, 0x02, 0x00,
+/* sc=02 */ '1', '!', NOP, NOP, '`', '`', NOP, NOP, 0x33, 0x00,
+/* sc=03 */ '2', '"', 0x00, 0x00, '@', '@', 0x00, 0x00, 0x00, 0x00,
+/* sc=04 */ '3', 0xA7, NOP, NOP, '#', '#', NOP, NOP, 0x33, 0x00,
+/* sc=05 */ '4', '$', NOP, NOP, '4', '$', NOP, NOP, 0x33, 0x00,
+/* sc=06 */ '5', '%', NOP, NOP, '5', '%', NOP, NOP, 0x33, 0x00,
+/* sc=07 */ '6', '&', 0x1E, 0x1E, '^', '^', 0x1E, 0x1E, 0x00, 0x00,
+/* sc=08 */ '7', '/', 0x1B, 0x1B, '[', '[', 0x1B, 0x1B, 0x00, 0x00,
+/* sc=09 */ '8', '(', NOP, NOP, '8', '(', NOP, NOP, 0x33, 0x00,
+/* sc=0a */ '9', ')', 0x1D, 0x1D, ']', ']', 0x1D, 0x1D, 0x00, 0x00,
+/* sc=0b */ '0', '=', NOP, NOP, '{', '{', NOP, NOP, 0x33, 0x00,
+/* sc=0c */ 0xDF, '?', NOP, NOP, '|', '|', NOP, NOP, 0x33, 0x00,
+/* sc=0d */ 0x92, 0x93, NOP, NOP, '\'', '`', NOP, NOP, 0x33, 0x00,
+/* sc=0e */ 0x08, 0x08, 0x7F, 0x7F, 0x08, 0x08, 0x7F, 0x7F, 0x00, 0x00,
+/* sc=0f */ 0x09, 0x08, NOP, NOP, 0x09, 0x08, NOP, NOP, 0x77, 0x00,
+/* sc=10 */ 'q', 'Q', 0x11, 0x11, 'q', 'Q', 0x11, 0x11, 0x00, 0x01,
+/* sc=11 */ 'w', 'W', 0x17, 0x17, 'w', 'W', 0x17, 0x17, 0x00, 0x01,
+/* sc=12 */ 'e', 'E', 0x05, 0x05, 'e', 'E', 0x05, 0x05, 0x00, 0x01,
+/* sc=13 */ 'r', 'R', 0x12, 0x12, 'r', 'R', 0x12, 0x12, 0x00, 0x01,
+/* sc=14 */ 't', 'T', 0x14, 0x14, 't', 'T', 0x14, 0x14, 0x00, 0x01,
+/* sc=15 */ 'z', 'Z', 0x1A, 0x1A, 'z', 'Z', 0x1A, 0x1A, 0x00, 0x01,
+/* sc=16 */ 'u', 'U', 0x15, 0x15, 'u', 'U', 0x15, 0x15, 0x00, 0x01,
+/* sc=17 */ 'i', 'I', 0x09, 0x09, 'i', 'I', 0x09, 0x09, 0x00, 0x01,
+/* sc=18 */ 'o', 'O', 0x0F, 0x0F, 'o', 'O', 0x0F, 0x0F, 0x00, 0x01,
+/* sc=19 */ 'p', 'P', 0x10, 0x10, 'p', 'P', 0x10, 0x10, 0x00, 0x01,
+/* sc=1a */ 0xFC, 0xDC, 0x1B, 0x1B, '[', '{', 0x1B, 0x1B, 0x00, 0x01,
+/* sc=1b */ '+', '*', 0x1D, 0x1D, ']', '}', 0x1D, 0x1D, 0x00, 0x00,
+/* sc=1c */ 0x0D, 0x0D, 0x0A, 0x0A, 0x0D, 0x0D, 0x0A, 0x0A, 0x00, 0x00,
+/* sc=1d */ LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, 0xFF, 0x00,
+/* sc=1e */ 'a', 'A', 0x01, 0x01, 'a', 'A', 0x01, 0x01, 0x00, 0x01,
+/* sc=1f */ 's', 'S', 0x13, 0x13, 's', 'S', 0x13, 0x13, 0x00, 0x01,
+/* sc=20 */ 'd', 'D', 0x04, 0x04, 'd', 'D', 0x04, 0x04, 0x00, 0x01,
+/* sc=21 */ 'f', 'F', 0x06, 0x06, 'f', 'F', 0x06, 0x06, 0x00, 0x01,
+/* sc=22 */ 'g', 'G', 0x07, 0x07, 'g', 'G', 0x07, 0x07, 0x00, 0x01,
+/* sc=23 */ 'h', 'H', 0x08, 0x08, 'h', 'H', 0x08, 0x08, 0x00, 0x01,
+/* sc=24 */ 'j', 'J', 0x0A, 0x0A, 'j', 'J', 0x0A, 0x0A, 0x00, 0x01,
+/* sc=25 */ 'k', 'K', 0x0B, 0x0B, 'k', 'K', 0x0B, 0x0B, 0x00, 0x01,
+/* sc=26 */ 'l', 'L', 0x0C, 0x0C, 'l', 'L', 0x0C, 0x0C, 0x00, 0x01,
+/* sc=27 */ 0xF6, 0xD6, NOP, NOP, 0xF6, 0xD6, NOP, NOP, 0x33, 0x01,
+/* sc=28 */ 0xE4, 0xC4, NOP, NOP, 0xE4, 0xC4, NOP, NOP, 0x33, 0x01,
+/* sc=29 */ '<', '>', 0x1C, 0x1C, '\\', '|', 0x1C, 0x1C, 0x00, 0x00,
+/* sc=2a */ LSH, LSH, LSH, LSH, LSH, LSH, LSH, LSH, 0xFF, 0x00,
+/* sc=2b */ '#', '^', 0x1E, 0x1E, '`', '~', 0x1E, 0x1E, 0x00, 0x00,
+/* sc=2c */ 'y', 'Y', 0x19, 0x19, 'y', 'Y', 0x19, 0x19, 0x00, 0x01,
+/* sc=2d */ 'x', 'X', 0x18, 0x18, 'x', 'X', 0x18, 0x18, 0x00, 0x01,
+/* sc=2e */ 'c', 'C', 0x03, 0x03, 'c', 'C', 0x03, 0x03, 0x00, 0x01,
+/* sc=2f */ 'v', 'V', 0x16, 0x16, 'v', 'V', 0x16, 0x16, 0x00, 0x01,
+/* sc=30 */ 'b', 'B', 0x02, 0x02, 'b', 'B', 0x02, 0x02, 0x00, 0x01,
+/* sc=31 */ 'n', 'N', 0x0E, 0x0E, 'n', 'N', 0x0E, 0x0E, 0x00, 0x01,
+/* sc=32 */ 'm', 'M', 0x0D, 0x0D, 'm', 'M', 0x0D, 0x0D, 0x00, 0x01,
+/* sc=33 */ ',', ';', NOP, NOP, ',', ';', NOP, NOP, 0x33, 0x00,
+/* sc=34 */ '.', ':', NOP, NOP, '.', ':', NOP, NOP, 0x33, 0x00,
+/* sc=35 */ '-', '_', 0x1F, 0x1F, '-', '_', 0x1F, 0x1F, 0x00, 0x00,
+/* sc=36 */ RSH, RSH, RSH, RSH, RSH, RSH, RSH, RSH, 0xFF, 0x00,
+/* sc=37 */ '*', '*', 0x0A, 0x0A, '*', '*', 0x0A, 0x0A, 0x33, 0x00,
+/* sc=38 */ LALT, LALT, LALT, LALT, LALT, LALT, LALT, LALT, 0xFF, 0x00,
+/* sc=39 */ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 0x00, 0x00,
+/* sc=3a */ CLK, CLK, CLK, CLK, CLK, CLK, CLK, CLK, 0xFF, 0x00,
+/* sc=3b */ F( 1), F(13), F(25), F(37), S( 1), S(11), S( 1), S(11), 0xFF, 0x00,
+/* sc=3c */ F( 2), F(14), F(26), F(38), S( 2), S(12), S( 2), S(12), 0xFF, 0x00,
+/* sc=3d */ F( 3), F(15), F(27), F(39), S( 3), S(13), S( 3), S(13), 0xFF, 0x00,
+/* sc=3e */ F( 4), F(16), F(28), F(40), S( 4), S(14), S( 4), S(14), 0xFF, 0x00,
+/* sc=3f */ F( 5), F(17), F(29), F(41), S( 5), S(15), S( 5), S(15), 0xFF, 0x00,
+/* sc=40 */ F( 6), F(18), F(30), F(42), S( 6), S(16), S( 6), S(16), 0xFF, 0x00,
+/* sc=41 */ F( 7), F(19), F(31), F(43), S( 7), S( 7), S( 7), S( 7), 0xFF, 0x00,
+/* sc=42 */ F( 8), F(20), F(32), F(44), S( 8), S( 8), S( 8), S( 8), 0xFF, 0x00,
+/* sc=43 */ F( 9), F(21), F(33), F(45), S( 9), S( 9), S( 9), S( 9), 0xFF, 0x00,
+/* sc=44 */ F(10), F(22), F(34), F(46), S(10), S(10), S(10), S(10), 0xFF, 0x00,
+/* sc=45 */ NLK, NLK, 0x13, 0x13, NLK, NLK, 0x13, 0x13, 0xCC, 0x00,
+/* sc=46 */ SLK, SLK, 0x7F, 0x7F, SLK, SLK, 0x7F, 0x7F, 0xCC, 0x00,
+/* sc=47 */ F(49), '7', '7', '7', '7', '7', '7', '7', 0x80, 0x02,
+/* sc=48 */ F(50), '8', '8', '8', '8', '8', '8', '8', 0x80, 0x02,
+/* sc=49 */ F(51), '9', '9', '9', '9', '9', '9', '9', 0x80, 0x02,
+/* sc=4a */ F(52), '-', 0x1F, 0x1F, '-', '-', '-', '-', 0x80, 0x02,
+/* sc=4b */ F(53), '4', '4', '4', '4', '4', '4', '4', 0x80, 0x02,
+/* sc=4c */ F(54), '5', '5', '5', '5', '5', '5', '5', 0x80, 0x02,
+/* sc=4d */ F(55), '6', 0x1E, 0x1E, '6', '6', '6', '6', 0x80, 0x02,
+/* sc=4e */ F(56), '+', '+', '+', '+', '+', '+', '+', 0x80, 0x02,
+/* sc=4f */ F(57), '1', '1', '1', '1', '1', '1', '1', 0x80, 0x02,
+/* sc=50 */ F(58), '2', '2', '2', '2', '2', '2', '2', 0x80, 0x02,
+/* sc=51 */ F(59), '3', '3', '3', '3', '3', '3', '3', 0x80, 0x02,
+/* sc=52 */ F(60), '0', '0', '0', '0', '0', '0', '0', 0x80, 0x02,
+/* sc=53 */ 0x7F, '.', 0x7F, 0x7F, 0x7F, 0x7F, RBT, 0x7F, 0x02, 0x02,
+/* sc=54 */ 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x00, 0x00,
+/* sc=55 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=56 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=57 */ F(11), F(23), F(35), F(47), S(11), S(11), S(11), S(11), 0xFF, 0x00,
+/* sc=58 */ F(12), F(24), F(36), F(48), S(12), S(12), S(12), S(12), 0xFF, 0x00,
+/* sc=59 */ 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0xFF, 0x02,
+/* sc=5a */ RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, 0xFF, 0x00,
+/* sc=5b */ '/', '/', '/', '/', '/', '/', '/', '/', 0x00, 0x02,
+/* sc=5c */ NEXT, NOP, DBG, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=5d */ RALT, RALT, RALT, RALT, RALT, RALT, RALT, RALT, 0xFF, 0x00,
+/* sc=5e */ F(49), F(49), F(49), F(49), F(49), F(49), F(49), F(49), 0xFF, 0x00,
+/* sc=5f */ F(50), F(50), F(50), F(50), F(50), F(50), F(50), F(50), 0xFF, 0x00,
+/* sc=60 */ F(51), F(51), F(51), F(51), F(51), F(51), F(51), F(51), 0xFF, 0x00,
+/* sc=61 */ F(53), F(53), F(53), F(53), F(53), F(53), F(53), F(53), 0xFF, 0x00,
+/* sc=62 */ F(55), F(55), F(55), F(55), F(55), F(55), F(55), F(55), 0xFF, 0x00,
+/* sc=63 */ F(57), F(57), F(57), F(57), F(57), F(57), F(57), F(57), 0xFF, 0x00,
+/* sc=64 */ F(58), F(58), F(58), F(58), F(58), F(58), F(58), F(58), 0xFF, 0x00,
+/* sc=65 */ F(59), F(59), F(59), F(59), F(59), F(59), F(59), F(59), 0xFF, 0x00,
+/* sc=66 */ F(60), F(60), F(60), F(60), F(60), F(60), F(60), F(60), 0xFF, 0x00,
+/* sc=67 */ F(54), F(54), F(54), F(54), F(54), F(54), RBT, F(54), 0xFF, 0x00,
+/* sc=68 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+};
+#endif
+
+#ifdef SWKEYMAP
+keymap_t key_map = { 0x69, /* swedish iso8859 keymap */
+/* alt
+ * scan cntrl alt alt cntrl
+ * code base shift cntrl shift alt shift cntrl shift spcl flgs
+ * ---------------------------------------------------------------------------
+ */
+/* sc=00 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=01 */ 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, DBG, 0x1B, 0x02, 0x00,
+/* sc=02 */ '1', '!', NOP, NOP, NOP, NOP, NOP, NOP, 0x3F, 0x00,
+/* sc=03 */ '2', '"', NOP, NOP, '@', NOP, NOP, NOP, 0x37, 0x00,
+/* sc=04 */ '3', '#', NOP, NOP, 0xA3, NOP, NOP, NOP, 0x37, 0x00,
+/* sc=05 */ '4', '$', NOP, NOP, 0xA4, NOP, NOP, NOP, 0x37, 0x00,
+/* sc=06 */ '5', '%', NOP, NOP, NOP, NOP, NOP, NOP, 0x3F, 0x00,
+/* sc=07 */ '6', '&', NOP, NOP, NOP, NOP, NOP, NOP, 0x3F, 0x00,
+/* sc=08 */ '7', '/', NOP, NOP, '{', NOP, NOP, NOP, 0x37, 0x00,
+/* sc=09 */ '8', '(', NOP, NOP, '[', NOP, NOP, NOP, 0x37, 0x00,
+/* sc=0a */ '9', ')', NOP, NOP, ']', NOP, NOP, NOP, 0x37, 0x00,
+/* sc=0b */ '0', '=', NOP, NOP, '}', NOP, NOP, NOP, 0x37, 0x00,
+/* sc=0c */ '+', '?', NOP, NOP, '\\', NOP, 0x1C, NOP, 0x35, 0x00,
+/* sc=0d */ 0x180, '`', NOP, NOP, NOP, NOP, NOP, NOP, 0x3F, 0x00,
+/* sc=0e */ 0x08, 0x08, 0x7F, 0x7F, 0x08, 0x08, 0x7F, 0x7F, 0x00, 0x00,
+/* sc=0f */ 0x09, 0x08, NOP, NOP, 0x09, 0x08, NOP, NOP, 0x77, 0x00,
+/* sc=10 */ 'q', 'Q', 0x11, 0x11, 'q', 'Q', 0x11, 0x11, 0x00, 0x01,
+/* sc=11 */ 'w', 'W', 0x17, 0x17, 'w', 'W', 0x17, 0x17, 0x00, 0x01,
+/* sc=12 */ 'e', 'E', 0x05, 0x05, 'e', 'E', 0x05, 0x05, 0x00, 0x01,
+/* sc=13 */ 'r', 'R', 0x12, 0x12, 'r', 'R', 0x12, 0x12, 0x00, 0x01,
+/* sc=14 */ 't', 'T', 0x14, 0x14, 't', 'T', 0x14, 0x14, 0x00, 0x01,
+/* sc=15 */ 'y', 'Y', 0x19, 0x19, 'y', 'Y', 0x19, 0x19, 0x00, 0x01,
+/* sc=16 */ 'u', 'U', 0x15, 0x15, 'u', 'U', 0x15, 0x15, 0x00, 0x01,
+/* sc=17 */ 'i', 'I', 0x09, 0x09, 'i', 'I', 0x09, 0x09, 0x00, 0x01,
+/* sc=18 */ 'o', 'O', 0x0F, 0x0F, 'o', 'O', 0x0F, 0x0F, 0x00, 0x01,
+/* sc=19 */ 'p', 'P', 0x10, 0x10, 'p', 'P', 0x10, 0x10, 0x00, 0x01,
+/* sc=1a */ 0xE5, 0xC5, NOP, NOP, '}', ']', NOP, NOP, 0x33, 0x01,
+/* sc=1b */ 0xA8, '^', NOP, NOP, '~', NOP, NOP, NOP, 0x37, 0x00,
+/* sc=1c */ 0x0D, 0x0D, 0x0A, 0x0A, 0x0D, 0x0D, 0x0A, 0x0A, 0x00, 0x00,
+/* sc=1d */ LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, 0xFF, 0x00,
+/* sc=1e */ 'a', 'A', 0x01, 0x01, 'a', 'A', 0x01, 0x01, 0x00, 0x01,
+/* sc=1f */ 's', 'S', 0x13, 0x13, 's', 'S', 0x13, 0x13, 0x00, 0x01,
+/* sc=20 */ 'd', 'D', 0x04, 0x04, 'd', 'D', 0x04, 0x04, 0x00, 0x01,
+/* sc=21 */ 'f', 'F', 0x06, 0x06, 'f', 'F', 0x06, 0x06, 0x00, 0x01,
+/* sc=22 */ 'g', 'G', 0x07, 0x07, 'g', 'G', 0x07, 0x07, 0x00, 0x01,
+/* sc=23 */ 'h', 'H', 0x08, 0x08, 'h', 'H', 0x08, 0x08, 0x00, 0x01,
+/* sc=24 */ 'j', 'J', 0x0A, 0x0A, 'j', 'J', 0x0A, 0x0A, 0x00, 0x01,
+/* sc=25 */ 'k', 'K', 0x0B, 0x0B, 'k', 'K', 0x0B, 0x0B, 0x00, 0x01,
+/* sc=26 */ 'l', 'L', 0x0C, 0x0C, 'l', 'L', 0x0C, 0x0C, 0x00, 0x01,
+/* sc=27 */ 0xF6, 0xD6, NOP, NOP, '|', '\\', NOP, NOP, 0x33, 0x01,
+/* sc=28 */ 0xE4, 0xC4, NOP, NOP, '{', '[', NOP, NOP, 0x33, 0x01,
+/* sc=29 */ 0xA7, 0xBD, NOP, NOP, '\\', '|', NOP, NOP, 0x33, 0x00,
+/* sc=2a */ LSH, LSH, LSH, LSH, LSH, LSH, LSH, LSH, 0xFF, 0x00,
+/* sc=2b */ '\'', '*', NOP, NOP, NOP, NOP, NOP, NOP, 0x3F, 0x00,
+/* sc=2c */ 'z', 'Z', 0x1A, 0x1A, 'z', 'Z', 0x1A, 0x1A, 0x00, 0x01,
+/* sc=2d */ 'x', 'X', 0x18, 0x18, 'x', 'X', 0x18, 0x18, 0x00, 0x01,
+/* sc=2e */ 'c', 'C', 0x03, 0x03, 'c', 'C', 0x03, 0x03, 0x00, 0x01,
+/* sc=2f */ 'v', 'V', 0x16, 0x16, 'v', 'V', 0x16, 0x16, 0x00, 0x01,
+/* sc=30 */ 'b', 'B', 0x02, 0x02, 'b', 'B', 0x02, 0x02, 0x00, 0x01,
+/* sc=31 */ 'n', 'N', 0x0E, 0x0E, 'n', 'N', 0x0E, 0x0E, 0x00, 0x01,
+/* sc=32 */ 'm', 'M', 0x0D, 0x0D, 'm', 'M', 0x0D, 0x0D, 0x00, 0x01,
+/* sc=33 */ ',', ';', NOP, NOP, NOP, '<', NOP, NOP, 0x3B, 0x00,
+/* sc=34 */ '.', ':', NOP, NOP, NOP, '>', NOP, NOP, 0x3B, 0x00,
+/* sc=35 */ '-', '_', 0x1F, NOP, '/', '?', NOP, NOP, 0x13, 0x00,
+/* sc=36 */ RSH, RSH, RSH, RSH, RSH, RSH, RSH, RSH, 0xFF, 0x00,
+/* sc=37 */ '*', '*', 0x0A, 0x0A, '*', '*', 0x0A, 0x0A, 0x33, 0x00,
+/* sc=38 */ LALT, LALT, LALT, LALT, LALT, LALT, LALT, LALT, 0xFF, 0x00,
+/* sc=39 */ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 0x00, 0x00,
+/* sc=3a */ CLK, CLK, CLK, CLK, CLK, CLK, CLK, CLK, 0xFF, 0x00,
+/* sc=3b */ F( 1), F(13), F(25), F(37), S( 1), S(11), S( 1), S(11), 0xFF, 0x00,
+/* sc=3c */ F( 2), F(14), F(26), F(38), S( 2), S(12), S( 2), S(12), 0xFF, 0x00,
+/* sc=3d */ F( 3), F(15), F(27), F(39), S( 3), S(13), S( 3), S(13), 0xFF, 0x00,
+/* sc=3e */ F( 4), F(16), F(28), F(40), S( 4), S(14), S( 4), S(14), 0xFF, 0x00,
+/* sc=3f */ F( 5), F(17), F(29), F(41), S( 5), S(15), S( 5), S(15), 0xFF, 0x00,
+/* sc=40 */ F( 6), F(18), F(30), F(42), S( 6), S(16), S( 6), S(16), 0xFF, 0x00,
+/* sc=41 */ F( 7), F(19), F(31), F(43), S( 7), S( 7), S( 7), S( 7), 0xFF, 0x00,
+/* sc=42 */ F( 8), F(20), F(32), F(44), S( 8), S( 8), S( 8), S( 8), 0xFF, 0x00,
+/* sc=43 */ F( 9), F(21), F(33), F(45), S( 9), S( 9), S( 9), S( 9), 0xFF, 0x00,
+/* sc=44 */ F(10), F(22), F(34), F(46), S(10), S(10), S(10), S(10), 0xFF, 0x00,
+/* sc=45 */ NLK, NLK, 0x13, 0x13, NLK, NLK, 0x13, 0x13, 0xCC, 0x00,
+/* sc=46 */ SLK, SLK, 0x7F, 0x7F, SLK, SLK, 0x7F, 0x7F, 0xCC, 0x00,
+/* sc=47 */ F(49), '7', '7', '7', '7', '7', '7', '7', 0x80, 0x02,
+/* sc=48 */ F(50), '8', '8', '8', '8', '8', '8', '8', 0x80, 0x02,
+/* sc=49 */ F(51), '9', '9', '9', '9', '9', '9', '9', 0x80, 0x02,
+/* sc=4a */ F(52), '-', 0x1F, 0x1F, '-', '-', '-', '-', 0x80, 0x02,
+/* sc=4b */ F(53), '4', '4', '4', '4', '4', '4', '4', 0x80, 0x02,
+/* sc=4c */ F(54), '5', '5', '5', '5', '5', '5', '5', 0x80, 0x02,
+/* sc=4d */ F(55), '6', 0x1E, 0x1E, '6', '6', '6', '6', 0x80, 0x02,
+/* sc=4e */ F(56), '+', '+', '+', '+', '+', '+', '+', 0x80, 0x02,
+/* sc=4f */ F(57), '1', '1', '1', '1', '1', '1', '1', 0x80, 0x02,
+/* sc=50 */ F(58), '2', '2', '2', '2', '2', '2', '2', 0x80, 0x02,
+/* sc=51 */ F(59), '3', '3', '3', '3', '3', '3', '3', 0x80, 0x02,
+/* sc=52 */ F(60), '0', '0', '0', '0', '0', '0', '0', 0x80, 0x02,
+/* sc=53 */ 0x7F, '.', 0x7F, 0x7F, 0x7F, 0x7F, RBT, 0x7F, 0x02, 0x02,
+/* sc=54 */ 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x00, 0x00,
+/* sc=55 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=56 */ '<', '>', NOP, NOP, '|', NOP, NOP, NOP, 0x37, 0x00,
+/* sc=57 */ F(11), F(23), F(35), F(47), S(11), S(11), S(11), S(11), 0xFF, 0x00,
+/* sc=58 */ F(12), F(24), F(36), F(48), S(12), S(12), S(12), S(12), 0xFF, 0x00,
+/* sc=59 */ 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0xFF, 0x02,
+/* sc=5a */ RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, 0xFF, 0x00,
+/* sc=5b */ '/', '/', '/', '/', '/', '/', '/', '/', 0x00, 0x02,
+/* sc=5c */ NEXT, NOP, DBG, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=5d */ RALT, RALT, RALT, RALT, RALT, RALT, RALT, RALT, 0xFF, 0x00,
+/* sc=5e */ F(49), F(49), F(49), F(49), F(49), F(49), F(49), F(49), 0xFF, 0x00,
+/* sc=5f */ F(50), F(50), F(50), F(50), F(50), F(50), F(50), F(50), 0xFF, 0x00,
+/* sc=60 */ F(51), F(51), F(51), F(51), F(51), F(51), F(51), F(51), 0xFF, 0x00,
+/* sc=61 */ F(53), F(53), F(53), F(53), F(53), F(53), F(53), F(53), 0xFF, 0x00,
+/* sc=62 */ F(55), F(55), F(55), F(55), F(55), F(55), F(55), F(55), 0xFF, 0x00,
+/* sc=63 */ F(57), F(57), F(57), F(57), F(57), F(57), F(57), F(57), 0xFF, 0x00,
+/* sc=64 */ F(58), F(58), F(58), F(58), F(58), F(58), F(58), F(58), 0xFF, 0x00,
+/* sc=65 */ F(59), F(59), F(59), F(59), F(59), F(59), F(59), F(59), 0xFF, 0x00,
+/* sc=66 */ F(60), F(60), F(60), F(60), F(60), F(60), F(60), F(60), 0xFF, 0x00,
+/* sc=67 */ F(54), F(54), F(54), F(54), F(54), F(54), RBT, F(54), 0xFF, 0x00,
+/* sc=68 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+};
+#endif
+
+#ifdef RUKEYMAP
+keymap_t key_map = { 0xe9, /* keys number */
+/* alt
+ * scan cntrl alt alt cntrl
+ * code base shift cntrl shift alt shift cntrl shift spcl flgs
+ * -------------------------------------------------------------------------------------------
+ */
+/* sc=00 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=01 */ 0x1B, 0x1B, NOP, NOP, SET8|0x1B, SET8|0x1B, DBG, NOP, 0x33, 0x00,
+/* sc=02 */ '1', '!', NOP, NOP, SET8|'1', SET8|'!', NOP, NOP, 0x33, 0x00,
+/* sc=03 */ '2', '@', 0x00, 0x00, SET8|'2', SET8|'@', SET8|0x00, SET8|0x00, 0x00, 0x00,
+/* sc=04 */ '3', '#', NOP, NOP, SET8|'3', SET8|'#', NOP, NOP, 0x33, 0x00,
+/* sc=05 */ '4', '$', NOP, NOP, SET8|'4', SET8|'$', NOP, NOP, 0x33, 0x00,
+/* sc=06 */ '5', '%', NOP, NOP, SET8|'5', SET8|'%', NOP, NOP, 0x33, 0x00,
+/* sc=07 */ '6', '^', 0x1E, 0x1E, SET8|'6', SET8|'^', SET8|0x1E, SET8|0x1E, 0x00, 0x00,
+/* sc=08 */ '7', '&', NOP, NOP, SET8|'7', SET8|'&', NOP, NOP, 0x33, 0x00,
+/* sc=09 */ '8', '*', NOP, NOP, SET8|'8', SET8|'*', NOP, NOP, 0x33, 0x00,
+/* sc=0a */ '9', '(', NOP, NOP, SET8|'9', SET8|'(', NOP, NOP, 0x33, 0x00,
+/* sc=0b */ '0', ')', NOP, NOP, SET8|'0', SET8|')', NOP, NOP, 0x33, 0x00,
+/* sc=0c */ '-', '_', 0x1F, 0x1F, SET8|'-', SET8|'_', SET8|0x1F, SET8|0x1F, 0x00, 0x00,
+/* sc=0d */ '=', '+', NOP, NOP, SET8|'=', SET8|'+', NOP, NOP, 0x33, 0x00,
+/* sc=0e */ 0x08, 0x08, 0x7F, 0x7F, SET8|0x08, SET8|0x08, SET8|0x7F, SET8|0x7F, 0x00, 0x00,
+/* sc=0f */ 0x09, F(16), NOP, NOP, SET8|0x09, F(16), NOP, NOP, 0x77, 0x00,
+/* sc=10 */ 'q', 'Q', 0x11, 0x11, SET8|'q', SET8|'Q', SET8|0x11, SET8|0x11, 0x00, 0x01,
+/* sc=11 */ 'w', 'W', 0x17, 0x17, SET8|'w', SET8|'W', SET8|0x17, SET8|0x17, 0x00, 0x01,
+/* sc=12 */ 'e', 'E', 0x05, 0x05, SET8|'e', SET8|'E', SET8|0x05, SET8|0x05, 0x00, 0x01,
+/* sc=13 */ 'r', 'R', 0x12, 0x12, SET8|'r', SET8|'R', SET8|0x12, SET8|0x12, 0x00, 0x01,
+/* sc=14 */ 't', 'T', 0x14, 0x14, SET8|'t', SET8|'T', SET8|0x14, SET8|0x14, 0x00, 0x01,
+/* sc=15 */ 'y', 'Y', 0x19, 0x19, SET8|'y', SET8|'Y', SET8|0x19, SET8|0x19, 0x00, 0x01,
+/* sc=16 */ 'u', 'U', 0x15, 0x15, SET8|'u', SET8|'U', SET8|0x15, SET8|0x15, 0x00, 0x01,
+/* sc=17 */ 'i', 'I', 0x09, 0x09, SET8|'i', SET8|'I', SET8|0x09, SET8|0x09, 0x00, 0x01,
+/* sc=18 */ 'o', 'O', 0x0F, 0x0F, SET8|'o', SET8|'O', SET8|0x0F, SET8|0x0F, 0x00, 0x01,
+/* sc=19 */ 'p', 'P', 0x10, 0x10, SET8|'p', SET8|'P', SET8|0x10, SET8|0x10, 0x00, 0x01,
+/* sc=1a */ '[', '{', 0x1B, 0x1B, SET8|'[', SET8|'{', SET8|0x1B, SET8|0x1B, 0x00, 0x00,
+/* sc=1b */ ']', '}', 0x1D, 0x1D, SET8|']', SET8|'}', SET8|0x1D, SET8|0x1D, 0x00, 0x00,
+/* sc=1c */ 0x0D, 0x0D, 0x0A, 0x0A, SET8|0x0D, SET8|0x0D, SET8|0x0A, SET8|0x0A, 0x00, 0x00,
+/* sc=1d */ LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, 0xFF, 0x00,
+/* sc=1e */ 'a', 'A', 0x01, 0x01, SET8|'a', SET8|'A', SET8|0x01, SET8|0x01, 0x00, 0x01,
+/* sc=1f */ 's', 'S', 0x13, 0x13, SET8|'s', SET8|'S', SET8|0x13, SET8|0x13, 0x00, 0x01,
+/* sc=20 */ 'd', 'D', 0x04, 0x04, SET8|'d', SET8|'D', SET8|0x04, SET8|0x04, 0x00, 0x01,
+/* sc=21 */ 'f', 'F', 0x06, 0x06, SET8|'f', SET8|'F', SET8|0x06, SET8|0x06, 0x00, 0x01,
+/* sc=22 */ 'g', 'G', 0x07, 0x07, SET8|'g', SET8|'G', SET8|0x07, SET8|0x07, 0x00, 0x01,
+/* sc=23 */ 'h', 'H', 0x08, 0x08, SET8|'h', SET8|'H', SET8|0x08, SET8|0x08, 0x00, 0x01,
+/* sc=24 */ 'j', 'J', 0x0A, 0x0A, SET8|'j', SET8|'J', SET8|0x0A, SET8|0x0A, 0x00, 0x01,
+/* sc=25 */ 'k', 'K', 0x0B, 0x0B, SET8|'k', SET8|'K', SET8|0x0B, SET8|0x0B, 0x00, 0x01,
+/* sc=26 */ 'l', 'L', 0x0C, 0x0C, SET8|'l', SET8|'L', SET8|0x0C, SET8|0x0C, 0x00, 0x01,
+/* sc=27 */ ';', ':', NOP, NOP, SET8|';', SET8|':', NOP, NOP, 0x33, 0x00,
+/* sc=28 */ '\'', '"', NOP, NOP, SET8|'\'', SET8|'"', NOP, NOP, 0x33, 0x00,
+/* sc=29 */ '`', '~', NOP, NOP, SET8|'`', SET8|'~', NOP, NOP, 0x33, 0x00,
+/* sc=2a */ LSH, LSH, LSH, LSH, LSH, LSH, LSH, LSH, 0xFF, 0x00,
+/* sc=2b */ '\\', '|', 0x1C, 0x1C, SET8|'\\', SET8|'|', SET8|0x1C, SET8|0x1C, 0x00, 0x00,
+/* sc=2c */ 'z', 'Z', 0x1A, 0x1A, SET8|'z', SET8|'Z', SET8|0x1A, SET8|0x1A, 0x00, 0x01,
+/* sc=2d */ 'x', 'X', 0x18, 0x18, SET8|'x', SET8|'X', SET8|0x18, SET8|0x18, 0x00, 0x01,
+/* sc=2e */ 'c', 'C', 0x03, 0x03, SET8|'c', SET8|'C', SET8|0x03, SET8|0x03, 0x00, 0x01,
+/* sc=2f */ 'v', 'V', 0x16, 0x16, SET8|'v', SET8|'V', SET8|0x16, SET8|0x16, 0x00, 0x01,
+/* sc=30 */ 'b', 'B', 0x02, 0x02, SET8|'b', SET8|'B', SET8|0x02, SET8|0x02, 0x00, 0x01,
+/* sc=31 */ 'n', 'N', 0x0E, 0x0E, SET8|'n', SET8|'N', SET8|0x0E, SET8|0x0E, 0x00, 0x01,
+/* sc=32 */ 'm', 'M', 0x0D, 0x0D, SET8|'m', SET8|'M', SET8|0x0D, SET8|0x0D, 0x00, 0x01,
+/* sc=33 */ ',', '<', NOP, NOP, SET8|',', SET8|'<', NOP, NOP, 0x33, 0x00,
+/* sc=34 */ '.', '>', NOP, NOP, SET8|'.', SET8|'>', NOP, NOP, 0x33, 0x00,
+/* sc=35 */ '/', '?', NOP, NOP, SET8|'/', SET8|'?', NOP, NOP, 0x33, 0x00,
+/* sc=36 */ RSH, RSH, RSH, RSH, RSH, RSH, RSH, RSH, 0xFF, 0x00,
+/* sc=37 */ '*', '*', 0x0A, 0x0A, SET8|'*', SET8|'*', SET8|0x0A, SET8|0x0A, 0x00, 0x00,
+/* sc=38 */ LALT, LALT, LALT, LALT, LALT, LALT, LALT, LALT, 0xFF, 0x00,
+/* sc=39 */ ' ', ' ', ' ', ' ', SET8|' ', SET8|' ', SET8|' ', SET8|' ', 0x00, 0x00,
+/* sc=3a */ ALK, CLK, CLK, CLK, CLK, CLK, CLK, CLK, 0xFF, 0x00,
+/* sc=3b */ F( 1), F(13), F(25), F(37), S( 1), S(11), S( 1), S(11), 0xFF, 0x00,
+/* sc=3c */ F( 2), F(14), F(26), F(38), S( 2), S(12), S( 2), S(12), 0xFF, 0x00,
+/* sc=3d */ F( 3), F(15), F(27), F(39), S( 3), S(13), S( 3), S(13), 0xFF, 0x00,
+/* sc=3e */ F( 4), F(16), F(28), F(40), S( 4), S(14), S( 4), S(14), 0xFF, 0x00,
+/* sc=3f */ F( 5), F(17), F(29), F(41), S( 5), S(15), S( 5), S(15), 0xFF, 0x00,
+/* sc=40 */ F( 6), F(18), F(30), F(42), S( 6), S(16), S( 6), S(16), 0xFF, 0x00,
+/* sc=41 */ F( 7), F(19), F(31), F(43), S( 7), S( 7), S( 7), S( 7), 0xFF, 0x00,
+/* sc=42 */ F( 8), F(20), F(32), F(44), S( 8), S( 8), S( 8), S( 8), 0xFF, 0x00,
+/* sc=43 */ F( 9), F(21), F(33), F(45), S( 9), S( 9), S( 9), S( 9), 0xFF, 0x00,
+/* sc=44 */ F(10), F(22), F(34), F(46), S(10), S(10), S(10), S(10), 0xFF, 0x00,
+/* sc=45 */ NLK, NLK, NLK, NLK, NLK, NLK, NLK, NLK, 0xFF, 0x00,
+/* sc=46 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+/* sc=47 */ F(49), '7', '7', '7', SET8|'7', SET8|'7', SET8|'7', SET8|'7', 0x80, 0x02,
+/* sc=48 */ F(50), '8', '8', '8', SET8|'8', SET8|'8', SET8|'8', SET8|'8', 0x80, 0x02,
+/* sc=49 */ F(51), '9', '9', '9', SET8|'9', SET8|'9', SET8|'9', SET8|'9', 0x80, 0x02,
+/* sc=4a */ F(52), '-', '-', '-', SET8|'-', SET8|'-', SET8|'-', SET8|'-', 0x80, 0x02,
+/* sc=4b */ F(53), '4', '4', '4', SET8|'4', SET8|'4', SET8|'4', SET8|'4', 0x80, 0x02,
+/* sc=4c */ F(48), '5', '5', '5', SET8|'5', SET8|'5', SET8|'5', SET8|'5', 0x80, 0x02,
+/* sc=4d */ F(55), '6', '6', '6', SET8|'6', SET8|'6', SET8|'6', SET8|'6', 0x80, 0x02,
+/* sc=4e */ F(56), '+', '+', '+', SET8|'+', SET8|'+', SET8|'+', SET8|'+', 0x80, 0x02,
+/* sc=4f */ F(57), '1', '1', '1', SET8|'1', SET8|'1', SET8|'1', SET8|'1', 0x80, 0x02,
+/* sc=50 */ F(58), '2', '2', '2', SET8|'2', SET8|'2', SET8|'2', SET8|'2', 0x80, 0x02,
+/* sc=51 */ F(59), '3', '3', '3', SET8|'3', SET8|'3', SET8|'3', SET8|'3', 0x80, 0x02,
+/* sc=52 */ F(60), '0', '0', '0', SET8|'0', SET8|'0', SET8|'0', SET8|'0', 0x80, 0x02,
+/* sc=53 */ F(54), '.', 0x7F, 0x7F, SET8|0x7F, SET8|0x7F, RBT, SET8|0x7F, 0x82, 0x02,
+/* sc=54 */ ALK, ALK, ALK, ALK, ALK, ALK, ALK, ALK, 0xFF, 0x00,
+/* sc=55 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=56 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=57 */ F(11), F(23), F(35), F(47), S(11), S(11), S(11), S(11), 0xFF, 0x00,
+/* sc=58 */ F(12), F(24), F(36), F(48), S(12), S(12), S(12), S(12), 0xFF, 0x00,
+/* sc=59 */ 0x0D, 0x0D, 0x0A, 0x0A, SET8|0x0D, SET8|0x0D, SET8|0x0A, SET8|0x0A, 0x00, 0x00,
+/* sc=5a */ RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, 0xFF, 0x00,
+/* sc=5b */ '/', '/', NOP, NOP, SET8|'/', SET8|'/', NOP, NOP, 0x33, 0x00,
+/* sc=5c */ NEXT, NOP, DBG, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=5d */ RALT, RALT, RALT, RALT, RALT, RALT, RALT, RALT, 0xFF, 0x00,
+/* sc=5e */ F(49), F(49), F(49), F(49), F(49), F(49), F(49), F(49), 0xFF, 0x00,
+/* sc=5f */ F(50), F(50), F(50), F(50), F(50), F(50), F(50), F(50), 0xFF, 0x00,
+/* sc=60 */ F(51), F(51), F(51), F(51), F(51), F(51), F(51), F(51), 0xFF, 0x00,
+/* sc=61 */ F(53), F(53), F(53), F(53), F(53), F(53), F(53), F(53), 0xFF, 0x00,
+/* sc=62 */ F(55), F(55), F(55), F(55), F(55), F(55), F(55), F(55), 0xFF, 0x00,
+/* sc=63 */ F(57), F(57), F(57), F(57), F(57), F(57), F(57), F(57), 0xFF, 0x00,
+/* sc=64 */ F(58), F(58), F(58), F(58), F(58), F(58), F(58), F(58), 0xFF, 0x00,
+/* sc=65 */ F(59), F(59), F(59), F(59), F(59), F(59), F(59), F(59), 0xFF, 0x00,
+/* sc=66 */ F(60), F(60), F(60), F(60), F(60), F(60), F(60), F(60), 0xFF, 0x00,
+/* sc=67 */ F(54), F(54), 0x7F, 0x7F, SET8|0x7F, SET8|0x7F, RBT, SET8|0x7F, 0xC2, 0x00,
+/* sc=68 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+/* sc=69 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=6a */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=6b */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=6c */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=6d */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=6e */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=6f */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=70 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=71 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=72 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=73 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=74 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=75 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=76 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=77 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=78 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=79 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=7a */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=7b */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=7c */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=7d */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=7e */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=7f */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* extended (ALTGR LOCK keys) */
+/* sc=00 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=01 */ 0x1B, 0x1B, NOP, NOP, SET8|0x1B, SET8|0x1B, DBG, NOP, 0x33, 0x00,
+/* sc=02 */ '!', '1', NOP, NOP, SET8|'1', SET8|'!', NOP, NOP, 0x33, 0x00,
+/* sc=03 */ '"', '2', 0x00, 0x00, SET8|'2', SET8|'@', SET8|0x00, SET8|0x00, 0x00, 0x00,
+/* sc=04 */ '\'', '3', NOP, NOP, SET8|'3', SET8|'#', NOP, NOP, 0x33, 0x00,
+/* sc=05 */ ';', '4', NOP, NOP, SET8|'4', SET8|'$', NOP, NOP, 0x33, 0x00,
+/* sc=06 */ ':', '5', NOP, NOP, SET8|'5', SET8|'%', NOP, NOP, 0x33, 0x00,
+/* sc=07 */ ',', '6', 0x1E, 0x1E, SET8|'6', SET8|'^', SET8|0x1E, SET8|0x1E, 0x00, 0x00,
+/* sc=08 */ '.', '7', NOP, NOP, SET8|'7', SET8|'&', NOP, NOP, 0x33, 0x00,
+/* sc=09 */ '*', '8', NOP, NOP, SET8|'8', SET8|'*', NOP, NOP, 0x33, 0x00,
+/* sc=0a */ '(', '9', NOP, NOP, SET8|'9', SET8|'(', NOP, NOP, 0x33, 0x00,
+/* sc=0b */ ')', '0', NOP, NOP, SET8|'0', SET8|')', NOP, NOP, 0x33, 0x00,
+/* sc=0c */ '-', '_', 0x1F, 0x1F, SET8|'-', SET8|'_', SET8|0x1F, SET8|0x1F, 0x00, 0x00,
+/* sc=0d */ '=', '+', NOP, NOP, SET8|'=', SET8|'+', NOP, NOP, 0x33, 0x00,
+/* sc=0e */ 0x08, 0x08, 0x7F, 0x7F, SET8|0x08, SET8|0x08, SET8|0x7F, SET8|0x7F, 0x00, 0x00,
+/* sc=0f */ 0x09, F(16), NOP, NOP, SET8|0x09, F(16), NOP, NOP, 0x77, 0x00,
+/* sc=10 */ 0xca, 0xea, 0x11, 0x11, SET8|'q', SET8|'Q', SET8|0x11, SET8|0x11, 0x00, 0x01,
+/* sc=11 */ 0xc3, 0xe3, 0x17, 0x17, SET8|'w', SET8|'W', SET8|0x17, SET8|0x17, 0x00, 0x01,
+/* sc=12 */ 0xd5, 0xf5, 0x05, 0x05, SET8|'e', SET8|'E', SET8|0x05, SET8|0x05, 0x00, 0x01,
+/* sc=13 */ 0xcb, 0xeb, 0x12, 0x12, SET8|'r', SET8|'R', SET8|0x12, SET8|0x12, 0x00, 0x01,
+/* sc=14 */ 0xc5, 0xe5, 0x14, 0x14, SET8|'t', SET8|'T', SET8|0x14, SET8|0x14, 0x00, 0x01,
+/* sc=15 */ 0xce, 0xee, 0x19, 0x19, SET8|'y', SET8|'Y', SET8|0x19, SET8|0x19, 0x00, 0x01,
+/* sc=16 */ 0xc7, 0xe7, 0x15, 0x15, SET8|'u', SET8|'U', SET8|0x15, SET8|0x15, 0x00, 0x01,
+/* sc=17 */ 0xdb, 0xfb, 0x09, 0x09, SET8|'i', SET8|'I', SET8|0x09, SET8|0x09, 0x00, 0x01,
+/* sc=18 */ 0xdd, 0xfd, 0x0F, 0x0F, SET8|'o', SET8|'O', SET8|0x0F, SET8|0x0F, 0x00, 0x01,
+/* sc=19 */ 0xda, 0xfa, 0x10, 0x10, SET8|'p', SET8|'P', SET8|0x10, SET8|0x10, 0x00, 0x01,
+/* sc=1a */ 0xc8, 0xe8, 0x1B, 0x1B, SET8|'[', SET8|'{', SET8|0x1B, SET8|0x1B, 0x00, 0x01,
+/* sc=1b */ 0xdf, 0xff, 0x1D, 0x1D, SET8|']', SET8|'}', SET8|0x1D, SET8|0x1D, 0x00, 0x01,
+/* sc=1c */ 0x0D, 0x0D, 0x0A, 0x0A, SET8|0x0D, SET8|0x0D, SET8|0x0A, SET8|0x0A, 0x00, 0x00,
+/* sc=1d */ LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, 0xFF, 0x00,
+/* sc=1e */ 0xc6, 0xe6, 0x01, 0x01, SET8|'a', SET8|'A', SET8|0x01, SET8|0x01, 0x00, 0x01,
+/* sc=1f */ 0xd9, 0xf9, 0x13, 0x13, SET8|'s', SET8|'S', SET8|0x13, SET8|0x13, 0x00, 0x01,
+/* sc=20 */ 0xd7, 0xf7, 0x04, 0x04, SET8|'d', SET8|'D', SET8|0x04, SET8|0x04, 0x00, 0x01,
+/* sc=21 */ 0xc1, 0xe1, 0x06, 0x06, SET8|'f', SET8|'F', SET8|0x06, SET8|0x06, 0x00, 0x01,
+/* sc=22 */ 0xd0, 0xf0, 0x07, 0x07, SET8|'g', SET8|'G', SET8|0x07, SET8|0x07, 0x00, 0x01,
+/* sc=23 */ 0xd2, 0xf2, 0x08, 0x08, SET8|'h', SET8|'H', SET8|0x08, SET8|0x08, 0x00, 0x01,
+/* sc=24 */ 0xcf, 0xef, 0x0A, 0x0A, SET8|'j', SET8|'J', SET8|0x0A, SET8|0x0A, 0x00, 0x01,
+/* sc=25 */ 0xcc, 0xec, 0x0B, 0x0B, SET8|'k', SET8|'K', SET8|0x0B, SET8|0x0B, 0x00, 0x01,
+/* sc=26 */ 0xc4, 0xe4, 0x0C, 0x0C, SET8|'l', SET8|'L', SET8|0x0C, SET8|0x0C, 0x00, 0x01,
+/* sc=27 */ 0xd6, 0xf6, NOP, NOP, SET8|';', SET8|':', NOP, NOP, 0x33, 0x01,
+/* sc=28 */ 0xdc, 0xfc, NOP, NOP, SET8|'\'', SET8|'"', NOP, NOP, 0x33, 0x01,
+/* sc=29 */ 0xa3, 0xb3, NOP, NOP, SET8|'`', SET8|'~', NOP, NOP, 0x33, 0x01,
+/* sc=2a */ LSH, LSH, LSH, LSH, LSH, LSH, LSH, LSH, 0xFF, 0x00,
+/* sc=2b */ '\\', '|', 0x1C, 0x1C, SET8|'\\', SET8|'|', SET8|0x1C, SET8|0x1C, 0x00, 0x00,
+/* sc=2c */ 0xd1, 0xf1, 0x1A, 0x1A, SET8|'z', SET8|'Z', SET8|0x1A, SET8|0x1A, 0x00, 0x01,
+/* sc=2d */ 0xde, 0xfe, 0x18, 0x18, SET8|'x', SET8|'X', SET8|0x18, SET8|0x18, 0x00, 0x01,
+/* sc=2e */ 0xd3, 0xf3, 0x03, 0x03, SET8|'c', SET8|'C', SET8|0x03, SET8|0x03, 0x00, 0x01,
+/* sc=2f */ 0xcd, 0xed, 0x16, 0x16, SET8|'v', SET8|'V', SET8|0x16, SET8|0x16, 0x00, 0x01,
+/* sc=30 */ 0xc9, 0xe9, 0x02, 0x02, SET8|'b', SET8|'B', SET8|0x02, SET8|0x02, 0x00, 0x01,
+/* sc=31 */ 0xd4, 0xf4, 0x0E, 0x0E, SET8|'n', SET8|'N', SET8|0x0E, SET8|0x0E, 0x00, 0x01,
+/* sc=32 */ 0xd8, 0xf8, 0x0D, 0x0D, SET8|'m', SET8|'M', SET8|0x0D, SET8|0x0D, 0x00, 0x01,
+/* sc=33 */ 0xc2, 0xe2, NOP, NOP, SET8|',', SET8|'<', NOP, NOP, 0x33, 0x01,
+/* sc=34 */ 0xc0, 0xe0, NOP, NOP, SET8|'.', SET8|'>', NOP, NOP, 0x33, 0x01,
+/* sc=35 */ '/', '?', NOP, NOP, SET8|'/', SET8|'?', NOP, NOP, 0x33, 0x00,
+/* sc=36 */ RSH, RSH, RSH, RSH, RSH, RSH, RSH, RSH, 0xFF, 0x00,
+/* sc=37 */ '*', '*', 0x0A, 0x0A, SET8|'*', SET8|'*', SET8|0x0A, SET8|0x0A, 0x00, 0x00,
+/* sc=38 */ LALT, LALT, LALT, LALT, LALT, LALT, LALT, LALT, 0xFF, 0x00,
+/* sc=39 */ ' ', ' ', ' ', ' ', SET8|' ', SET8|' ', SET8|' ', SET8|' ', 0x00, 0x00,
+/* sc=3a */ ALK, CLK, CLK, CLK, CLK, CLK, CLK, CLK, 0xFF, 0x00,
+/* sc=3b */ F( 1), F(13), F(25), F(37), S( 1), S(11), S( 1), S(11), 0xFF, 0x00,
+/* sc=3c */ F( 2), F(14), F(26), F(38), S( 2), S(12), S( 2), S(12), 0xFF, 0x00,
+/* sc=3d */ F( 3), F(15), F(27), F(39), S( 3), S(13), S( 3), S(13), 0xFF, 0x00,
+/* sc=3e */ F( 4), F(16), F(28), F(40), S( 4), S(14), S( 4), S(14), 0xFF, 0x00,
+/* sc=3f */ F( 5), F(17), F(29), F(41), S( 5), S(15), S( 5), S(15), 0xFF, 0x00,
+/* sc=40 */ F( 6), F(18), F(30), F(42), S( 6), S(16), S( 6), S(16), 0xFF, 0x00,
+/* sc=41 */ F( 7), F(19), F(31), F(43), S( 7), S( 7), S( 7), S( 7), 0xFF, 0x00,
+/* sc=42 */ F( 8), F(20), F(32), F(44), S( 8), S( 8), S( 8), S( 8), 0xFF, 0x00,
+/* sc=43 */ F( 9), F(21), F(33), F(45), S( 9), S( 9), S( 9), S( 9), 0xFF, 0x00,
+/* sc=44 */ F(10), F(22), F(34), F(46), S(10), S(10), S(10), S(10), 0xFF, 0x00,
+/* sc=45 */ NLK, NLK, NLK, NLK, NLK, NLK, NLK, NLK, 0xFF, 0x00,
+/* sc=46 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+/* sc=47 */ F(49), '7', '7', '7', SET8|'7', SET8|'7', SET8|'7', SET8|'7', 0x80, 0x02,
+/* sc=48 */ F(50), '8', '8', '8', SET8|'8', SET8|'8', SET8|'8', SET8|'8', 0x80, 0x02,
+/* sc=49 */ F(51), '9', '9', '9', SET8|'9', SET8|'9', SET8|'9', SET8|'9', 0x80, 0x02,
+/* sc=4a */ F(52), '-', '-', '-', SET8|'-', SET8|'-', SET8|'-', SET8|'-', 0x80, 0x02,
+/* sc=4b */ F(53), '4', '4', '4', SET8|'4', SET8|'4', SET8|'4', SET8|'4', 0x80, 0x02,
+/* sc=4c */ F(48), '5', '5', '5', SET8|'5', SET8|'5', SET8|'5', SET8|'5', 0x80, 0x02,
+/* sc=4d */ F(55), '6', '6', '6', SET8|'6', SET8|'6', SET8|'6', SET8|'6', 0x80, 0x02,
+/* sc=4e */ F(56), '+', '+', '+', SET8|'+', SET8|'+', SET8|'+', SET8|'+', 0x80, 0x02,
+/* sc=4f */ F(57), '1', '1', '1', SET8|'1', SET8|'1', SET8|'1', SET8|'1', 0x80, 0x02,
+/* sc=50 */ F(58), '2', '2', '2', SET8|'2', SET8|'2', SET8|'2', SET8|'2', 0x80, 0x02,
+/* sc=51 */ F(59), '3', '3', '3', SET8|'3', SET8|'3', SET8|'3', SET8|'3', 0x80, 0x02,
+/* sc=52 */ F(60), '0', '0', '0', SET8|'0', SET8|'0', SET8|'0', SET8|'0', 0x80, 0x02,
+/* sc=53 */ F(54), '.', 0x7F, 0x7F, SET8|0x7F, SET8|0x7F, RBT, SET8|0x7F, 0x82, 0x02,
+/* sc=54 */ ALK, ALK, ALK, ALK, ALK, ALK, ALK, ALK, 0xFF, 0x00,
+/* sc=55 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=56 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=57 */ F(11), F(23), F(35), F(47), S(11), S(11), S(11), S(11), 0xFF, 0x00,
+/* sc=58 */ F(12), F(24), F(36), F(48), S(12), S(12), S(12), S(12), 0xFF, 0x00,
+/* sc=59 */ 0x0D, 0x0D, 0x0A, 0x0A, SET8|0x0D, SET8|0x0D, SET8|0x0A, SET8|0x0A, 0x00, 0x00,
+/* sc=5a */ RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, 0xFF, 0x00,
+/* sc=5b */ '/', '/', NOP, NOP, SET8|'/', SET8|'/', NOP, NOP, 0x33, 0x00,
+/* sc=5c */ NEXT, NOP, DBG, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=5d */ RALT, RALT, RALT, RALT, RALT, RALT, RALT, RALT, 0xFF, 0x00,
+/* sc=5e */ F(49), F(49), F(49), F(49), F(49), F(49), F(49), F(49), 0xFF, 0x00,
+/* sc=5f */ F(50), F(50), F(50), F(50), F(50), F(50), F(50), F(50), 0xFF, 0x00,
+/* sc=60 */ F(51), F(51), F(51), F(51), F(51), F(51), F(51), F(51), 0xFF, 0x00,
+/* sc=61 */ F(53), F(53), F(53), F(53), F(53), F(53), F(53), F(53), 0xFF, 0x00,
+/* sc=62 */ F(55), F(55), F(55), F(55), F(55), F(55), F(55), F(55), 0xFF, 0x00,
+/* sc=63 */ F(57), F(57), F(57), F(57), F(57), F(57), F(57), F(57), 0xFF, 0x00,
+/* sc=64 */ F(58), F(58), F(58), F(58), F(58), F(58), F(58), F(58), 0xFF, 0x00,
+/* sc=65 */ F(59), F(59), F(59), F(59), F(59), F(59), F(59), F(59), 0xFF, 0x00,
+/* sc=66 */ F(60), F(60), F(60), F(60), F(60), F(60), F(60), F(60), 0xFF, 0x00,
+/* sc=67 */ F(54), F(54), 0x7F, 0x7F, SET8|0x7F, SET8|0x7F, RBT, SET8|0x7F, 0xC2, 0x00,
+/* sc=68 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+};
+
+#endif
+
+#if !defined(DKKEYMAP) && !defined(UKKEYMAP) && !defined(GRKEYMAP) && !defined(SWKEYMAP) && !defined(RUKEYMAP)
+keymap_t key_map = { 0x69, /* US iso8859 keymap */
+/* alt
+ * scan cntrl alt alt cntrl
+ * code base shift cntrl shift alt shift cntrl shift spcl flgs
+ * ---------------------------------------------------------------------------
+ */
+/* sc=00 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=01 */ 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, DBG, 0x1B, 0x02, 0x00,
+/* sc=02 */ '1', '!', NOP, NOP, '1', '!', NOP, NOP, 0x33, 0x00,
+/* sc=03 */ '2', '@', 0x00, 0x00, '2', '@', 0x00, 0x00, 0x00, 0x00,
+/* sc=04 */ '3', '#', NOP, NOP, '3', '#', NOP, NOP, 0x33, 0x00,
+/* sc=05 */ '4', '$', NOP, NOP, '4', '$', NOP, NOP, 0x33, 0x00,
+/* sc=06 */ '5', '%', NOP, NOP, '5', '%', NOP, NOP, 0x33, 0x00,
+/* sc=07 */ '6', '^', 0x1E, 0x1E, '6', '^', 0x1E, 0x1E, 0x00, 0x00,
+/* sc=08 */ '7', '&', NOP, NOP, '7', '&', NOP, NOP, 0x33, 0x00,
+/* sc=09 */ '8', '*', NOP, NOP, '8', '*', NOP, NOP, 0x33, 0x00,
+/* sc=0a */ '9', '(', NOP, NOP, '9', '(', NOP, NOP, 0x33, 0x00,
+/* sc=0b */ '0', ')', NOP, NOP, '0', ')', NOP, NOP, 0x33, 0x00,
+/* sc=0c */ '-', '_', 0x1F, 0x1F, '-', '_', 0x1F, 0x1F, 0x00, 0x00,
+/* sc=0d */ '=', '+', NOP, NOP, '=', '+', NOP, NOP, 0x33, 0x00,
+/* sc=0e */ 0x08, 0x08, 0x7F, 0x7F, 0x08, 0x08, 0x7F, 0x7F, 0x00, 0x00,
+/* sc=0f */ 0x09, 0x08, NOP, NOP, 0x09, 0x08, NOP, NOP, 0x33, 0x00,
+/* sc=10 */ 'q', 'Q', 0x11, 0x11, 'q', 'Q', 0x11, 0x11, 0x00, 0x01,
+/* sc=11 */ 'w', 'W', 0x17, 0x17, 'w', 'W', 0x17, 0x17, 0x00, 0x01,
+/* sc=12 */ 'e', 'E', 0x05, 0x05, 'e', 'E', 0x05, 0x05, 0x00, 0x01,
+/* sc=13 */ 'r', 'R', 0x12, 0x12, 'r', 'R', 0x12, 0x12, 0x00, 0x01,
+/* sc=14 */ 't', 'T', 0x14, 0x14, 't', 'T', 0x14, 0x14, 0x00, 0x01,
+/* sc=15 */ 'y', 'Y', 0x19, 0x19, 'y', 'Y', 0x19, 0x19, 0x00, 0x01,
+/* sc=16 */ 'u', 'U', 0x15, 0x15, 'u', 'U', 0x15, 0x15, 0x00, 0x01,
+/* sc=17 */ 'i', 'I', 0x09, 0x09, 'i', 'I', 0x09, 0x09, 0x00, 0x01,
+/* sc=18 */ 'o', 'O', 0x0F, 0x0F, 'o', 'O', 0x0F, 0x0F, 0x00, 0x01,
+/* sc=19 */ 'p', 'P', 0x10, 0x10, 'p', 'P', 0x10, 0x10, 0x00, 0x01,
+/* sc=1a */ '[', '{', 0x1B, 0x1B, '[', '{', 0x1B, 0x1B, 0x00, 0x00,
+/* sc=1b */ ']', '}', 0x1D, 0x1D, ']', '}', 0x1D, 0x1D, 0x00, 0x00,
+/* sc=1c */ 0x0D, 0x0D, 0x0A, 0x0A, 0x0D, 0x0D, 0x0A, 0x0A, 0x00, 0x00,
+/* sc=1d */ LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, 0xFF, 0x00,
+/* sc=1e */ 'a', 'A', 0x01, 0x01, 'a', 'A', 0x01, 0x01, 0x00, 0x01,
+/* sc=1f */ 's', 'S', 0x13, 0x13, 's', 'S', 0x13, 0x13, 0x00, 0x01,
+/* sc=20 */ 'd', 'D', 0x04, 0x04, 'd', 'D', 0x04, 0x04, 0x00, 0x01,
+/* sc=21 */ 'f', 'F', 0x06, 0x06, 'f', 'F', 0x06, 0x06, 0x00, 0x01,
+/* sc=22 */ 'g', 'G', 0x07, 0x07, 'g', 'G', 0x07, 0x07, 0x00, 0x01,
+/* sc=23 */ 'h', 'H', 0x08, 0x08, 'h', 'H', 0x08, 0x08, 0x00, 0x01,
+/* sc=24 */ 'j', 'J', 0x0A, 0x0A, 'j', 'J', 0x0A, 0x0A, 0x00, 0x01,
+/* sc=25 */ 'k', 'K', 0x0B, 0x0B, 'k', 'K', 0x0B, 0x0B, 0x00, 0x01,
+/* sc=26 */ 'l', 'L', 0x0C, 0x0C, 'l', 'L', 0x0C, 0x0C, 0x00, 0x01,
+/* sc=27 */ ';', ':', NOP, NOP, ';', ':', NOP, NOP, 0x33, 0x00,
+/* sc=28 */ '\'', '"', NOP, NOP, '\'', '"', NOP, NOP, 0x33, 0x00,
+/* sc=29 */ '`', '~', NOP, NOP, '`', '~', NOP, NOP, 0x33, 0x00,
+/* sc=2a */ LSH, LSH, LSH, LSH, LSH, LSH, LSH, LSH, 0xFF, 0x00,
+/* sc=2b */ '\\', '|', 0x1C, 0x1C, '\\', '|', 0x1C, 0x1C, 0x00, 0x00,
+/* sc=2c */ 'z', 'Z', 0x1A, 0x1A, 'z', 'Z', 0x1A, 0x1A, 0x00, 0x01,
+/* sc=2d */ 'x', 'X', 0x18, 0x18, 'x', 'X', 0x18, 0x18, 0x00, 0x01,
+/* sc=2e */ 'c', 'C', 0x03, 0x03, 'c', 'C', 0x03, 0x03, 0x00, 0x01,
+/* sc=2f */ 'v', 'V', 0x16, 0x16, 'v', 'V', 0x16, 0x16, 0x00, 0x01,
+/* sc=30 */ 'b', 'B', 0x02, 0x02, 'b', 'B', 0x02, 0x02, 0x00, 0x01,
+/* sc=31 */ 'n', 'N', 0x0E, 0x0E, 'n', 'N', 0x0E, 0x0E, 0x00, 0x01,
+/* sc=32 */ 'm', 'M', 0x0D, 0x0D, 'm', 'M', 0x0D, 0x0D, 0x00, 0x01,
+/* sc=33 */ ',', '<', NOP, NOP, ',', '<', NOP, NOP, 0x33, 0x00,
+/* sc=34 */ '.', '>', NOP, NOP, '.', '>', NOP, NOP, 0x33, 0x00,
+/* sc=35 */ '/', '?', NOP, NOP, '/', '?', NOP, NOP, 0x33, 0x00,
+/* sc=36 */ RSH, RSH, RSH, RSH, RSH, RSH, RSH, RSH, 0xFF, 0x00,
+/* sc=37 */ '*', '*', 0x0A, 0x0A, '*', '*', 0x0A, 0x0A, 0x33, 0x00,
+/* sc=38 */ LALT, LALT, LALT, LALT, LALT, LALT, LALT, LALT, 0xFF, 0x00,
+/* sc=39 */ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 0x00, 0x00,
+/* sc=3a */ CLK, CLK, CLK, CLK, CLK, CLK, CLK, CLK, 0xFF, 0x00,
+/* sc=3b */ F( 1), F(13), F(25), F(37), S( 1), S(11), S( 1), S(11), 0xFF, 0x00,
+/* sc=3c */ F( 2), F(14), F(26), F(38), S( 2), S(12), S( 2), S(12), 0xFF, 0x00,
+/* sc=3d */ F( 3), F(15), F(27), F(39), S( 3), S(13), S( 3), S(13), 0xFF, 0x00,
+/* sc=3e */ F( 4), F(16), F(28), F(40), S( 4), S(14), S( 4), S(14), 0xFF, 0x00,
+/* sc=3f */ F( 5), F(17), F(29), F(41), S( 5), S(15), S( 5), S(15), 0xFF, 0x00,
+/* sc=40 */ F( 6), F(18), F(30), F(42), S( 6), S(16), S( 6), S(16), 0xFF, 0x00,
+/* sc=41 */ F( 7), F(19), F(31), F(43), S( 7), S( 7), S( 7), S( 7), 0xFF, 0x00,
+/* sc=42 */ F( 8), F(20), F(32), F(44), S( 8), S( 8), S( 8), S( 8), 0xFF, 0x00,
+/* sc=43 */ F( 9), F(21), F(33), F(45), S( 9), S( 9), S( 9), S( 9), 0xFF, 0x00,
+/* sc=44 */ F(10), F(22), F(34), F(46), S(10), S(10), S(10), S(10), 0xFF, 0x00,
+/* sc=45 */ NLK, NLK, NLK, NLK, NLK, NLK, NLK, NLK, 0xFF, 0x00,
+/* sc=46 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+/* sc=47 */ F(49), '7', '7', '7', '7', '7', '7', '7', 0x80, 0x02,
+/* sc=48 */ F(50), '8', '8', '8', '8', '8', '8', '8', 0x80, 0x02,
+/* sc=49 */ F(51), '9', '9', '9', '9', '9', '9', '9', 0x80, 0x02,
+/* sc=4a */ F(52), '-', '-', '-', '-', '-', '-', '-', 0x80, 0x02,
+/* sc=4b */ F(53), '4', '4', '4', '4', '4', '4', '4', 0x80, 0x02,
+/* sc=4c */ NOP, '5', '5', '5', '5', '5', '5', '5', 0x80, 0x02,
+/* sc=4d */ F(55), '6', '6', '6', '6', '6', '6', '6', 0x80, 0x02,
+/* sc=4e */ F(56), '+', '+', '+', '+', '+', '+', '+', 0x80, 0x02,
+/* sc=4f */ F(57), '1', '1', '1', '1', '1', '1', '1', 0x80, 0x02,
+/* sc=50 */ F(58), '2', '2', '2', '2', '2', '2', '2', 0x80, 0x02,
+/* sc=51 */ F(59), '3', '3', '3', '3', '3', '3', '3', 0x80, 0x02,
+/* sc=52 */ F(60), '0', '0', '0', '0', '0', '0', '0', 0x80, 0x02,
+/* sc=53 */ 0x7F, '.', 0x7F, 0x7F, 0x7F, 0x7F, RBT, 0x7F, 0x02, 0x02,
+/* sc=54 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=55 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=56 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=57 */ F(11), F(23), F(35), F(47), S(11), S(11), S(11), S(11), 0xFF, 0x00,
+/* sc=58 */ F(12), F(24), F(36), F(48), S(12), S(12), S(12), S(12), 0xFF, 0x00,
+/* sc=59 */ 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x00, 0x00,
+/* sc=5a */ RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, 0xFF, 0x00,
+/* sc=5b */ '/', '/', '/', '/', '/', '/', '/', '/', 0x00, 0x00,
+/* sc=5c */ NEXT, NOP, DBG, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=5d */ RALT, RALT, RALT, RALT, RALT, RALT, RALT, RALT, 0xFF, 0x00,
+/* sc=5e */ F(49), F(49), F(49), F(49), F(49), F(49), F(49), F(49), 0xFF, 0x00,
+/* sc=5f */ F(50), F(50), F(50), F(50), F(50), F(50), F(50), F(50), 0xFF, 0x00,
+/* sc=60 */ F(51), F(51), F(51), F(51), F(51), F(51), F(51), F(51), 0xFF, 0x00,
+/* sc=61 */ F(53), F(53), F(53), F(53), F(53), F(53), F(53), F(53), 0xFF, 0x00,
+/* sc=62 */ F(55), F(55), F(55), F(55), F(55), F(55), F(55), F(55), 0xFF, 0x00,
+/* sc=63 */ F(57), F(57), F(57), F(57), F(57), F(57), F(57), F(57), 0xFF, 0x00,
+/* sc=64 */ F(58), F(58), F(58), F(58), F(58), F(58), F(58), F(58), 0xFF, 0x00,
+/* sc=65 */ F(59), F(59), F(59), F(59), F(59), F(59), F(59), F(59), 0xFF, 0x00,
+/* sc=66 */ F(60), F(60), F(60), F(60), F(60), F(60), F(60), F(60), 0xFF, 0x00,
+/* sc=67 */ F(54), F(54), F(54), F(54), F(54), F(54), RBT, F(54), 0xFF, 0x00,
+/* sc=68 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+};
+
+#endif
+
+fkeytab_t fkey_tab[60] = {
+/* 00-03 */ {"\033[M", 3}, {"\033[N", 3}, {"\033[O", 3}, {"\033[P", 3},
+/* 04-07 */ {"\033[Q", 3}, {"\033[R", 3}, {"\033[S", 3}, {"\033[T", 3},
+/* 08-0B */ {"\033[U", 3}, {"\033[V", 3}, {"\033[W", 3}, {"\033[X", 3},
+/* 0C-0F */ {"\033[W", 3}, {"\033[X", 3}, {"\033[Y", 3}, {"\033[Z", 3},
+/* 10-13 */ {"\033[a", 3}, {"\033[b", 3}, {"\033[c", 3}, {"\033[d", 3},
+/* 14-17 */ {"\033[e", 3}, {"\033[f", 3}, {"\033[g", 3}, {"\033[h", 3},
+/* 18-1B */ {"\033[g", 3}, {"\033[h", 3}, {"\033[i", 3}, {"\033[j", 3},
+/* 1C-1F */ {"\033[k", 3}, {"\033[l", 3}, {"\033[m", 3}, {"\033[n", 3},
+/* 20-23 */ {"\033[o", 3}, {"\033[p", 3}, {"\033[q", 3}, {"\033[r", 3},
+/* 24-27 */ {"\033[g", 3}, {"\033[h", 3}, {"\033[i", 3}, {"\033[j", 3},
+/* 28-2B */ {"\033[k", 3}, {"\033[l", 3}, {"\033[m", 3}, {"\033[n", 3},
+/* 2C-2F */ {"\033[o", 3}, {"\033[p", 3}, {"\033[q", 3}, {"\033[r", 3},
+/* 30-33 */ {"\033[H", 3}, {"\033[A", 3}, {"\033[I", 3}, {"-" , 1},
+/* 34-37 */ {"\033[D", 3}, {"\177" , 1}, {"\033[C", 3}, {"+" , 1},
+/* 38-3B */ {"\033[F", 3}, {"\033[B", 3}, {"\033[G", 3}, {"\033[L", 3}
+};
diff --git a/sys/isa/rtc.h b/sys/isa/rtc.h
new file mode 100644
index 0000000..9c0f501
--- /dev/null
+++ b/sys/isa/rtc.h
@@ -0,0 +1,109 @@
+/*-
+ * 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.
+ *
+ * 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.
+ *
+ * from: @(#)rtc.h 7.1 (Berkeley) 5/12/91
+ * $Id: rtc.h,v 1.4 1993/12/18 01:12:47 ache Exp $
+ */
+
+#ifndef _I386_ISA_RTC_H_
+#define _I386_ISA_RTC_H_ 1
+
+/*
+ * RTC Register locations
+ */
+
+#define RTC_SEC 0x00 /* seconds */
+#define RTC_SECALRM 0x01 /* seconds alarm */
+#define RTC_MIN 0x02 /* minutes */
+#define RTC_MINALRM 0x03 /* minutes alarm */
+#define RTC_HRS 0x04 /* hours */
+#define RTC_HRSALRM 0x05 /* hours alarm */
+#define RTC_WDAY 0x06 /* week day */
+#define RTC_DAY 0x07 /* day of month */
+#define RTC_MONTH 0x08 /* month of year */
+#define RTC_YEAR 0x09 /* month of year */
+
+#define RTC_STATUSA 0x0a /* status register A */
+#define RTCSA_TUP 0x80 /* time update, don't look now */
+#define RTCSA_DIVIDER 0x20 /* divider correct for 32768 Hz */
+#define RTCSA_8192 0x03
+#define RTCSA_4096 0x04
+#define RTCSA_2048 0x05
+#define RTCSA_1024 0x06 /* default for profiling */
+#define RTCSA_PROF RTCSA_1024
+#define RTC_PROFRATE 1024
+#define RTCSA_512 0x07
+#define RTCSA_256 0x08
+#define RTCSA_128 0x09
+#define RTCSA_NOPROF RTCSA_128
+#define RTC_NOPROFRATE 128
+#define RTCSA_64 0x0a
+#define RTCSA_32 0x0b
+
+#define RTC_STATUSB 0x0b /* status register B */
+#define RTCSB_HALT 0x80 /* stop clock updates */
+#define RTCSB_PINTR 0x40 /* periodic clock interrupt */
+#define RTCSB_24HR 0x02 /* 24-hour mode */
+
+#define RTC_INTR 0x0c /* status register C (R) interrupt source */
+#define RTCIR_UPDATE 0x10 /* update intr */
+#define RTCIR_ALARM 0x20 /* alarm intr */
+#define RTCIR_PERIOD 0x40 /* periodic intr */
+#define RTCIR_INT 0x80 /* interrupt output signal */
+
+#define RTC_STATUSD 0x0d /* status register D (R) Lost Power */
+#define RTCSD_PWR 0x80 /* clock lost power */
+
+#define RTC_DIAG 0x0e /* status register E - bios diagnostic */
+#define RTCDG_BITS "\020\010clock_battery\007ROM_cksum\006config_unit\005memory_size\004fixed_disk\003invalid_time"
+
+#define RTC_RESET 0x0f /* status register F - reset code byte */
+#define RTCRS_RST 0x00 /* normal reset */
+#define RTCRS_LOAD 0x04 /* load system */
+
+#define RTC_FDISKETTE 0x10 /* diskette drive type in upper/lower nibble */
+#define RTCFDT_NONE 0 /* none present */
+#define RTCFDT_360K 0x10 /* 360K */
+#define RTCFDT_12M 0x20 /* 1.2M */
+#define RTCFDT_720K 0x30 /* 720K */
+#define RTCFDT_144M 0x40 /* 1.44M */
+
+#define RTC_BASELO 0x15 /* low byte of basemem size */
+#define RTC_BASEHI 0x16 /* high byte of basemem size */
+#define RTC_EXTLO 0x17 /* low byte of extended mem size */
+#define RTC_EXTHI 0x18 /* low byte of extended mem size */
+
+#define RTC_CENTURY 0x32 /* current century - please increment in Dec99*/
+#endif /* _I386_ISA_RTC_H_ */
diff --git a/sys/isa/sio.c b/sys/isa/sio.c
new file mode 100644
index 0000000..99f913f
--- /dev/null
+++ b/sys/isa/sio.c
@@ -0,0 +1,1957 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 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.
+ *
+ * from: @(#)com.c 7.5 (Berkeley) 5/16/91
+ * $Id: sio.c,v 1.50 1994/08/23 07:52:23 paul Exp $
+ */
+
+#include "sio.h"
+#if NSIO > 0
+/*
+ * Serial driver, based on 386BSD-0.1 com driver.
+ * Mostly rewritten to use pseudo-DMA.
+ * Works for National Semiconductor NS8250-NS16550AF UARTs.
+ * COM driver, based on HP dca driver.
+ */
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/ioctl.h>
+#define TTYDEFCHARS /* XXX TK2.0 */
+#include <sys/tty.h>
+#undef TTYDEFCHARS
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/conf.h>
+#include <sys/dkstat.h>
+#include <sys/file.h>
+#include <sys/uio.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/syslog.h>
+
+#include <i386/isa/icu.h> /* XXX just to get at `imen' */
+#include <i386/isa/isa.h>
+#include <i386/isa/isa_device.h>
+#include <i386/isa/sioreg.h>
+#include <i386/isa/ic/ns16550.h>
+
+/*
+ * XXX temporary kludges for 2.0 (XXX TK2.0).
+ */
+#define TS_RTS_IFLOW 0
+#define TSA_CARR_ON(tp) ((void *)&(tp)->t_rawq)
+#define TSA_OCOMPLETE(tp) ((void *)&(tp)->t_outq)
+#define TSA_OLOWAT(tp) ((void *)&(tp)->t_outq)
+void
+termioschars(t)
+ struct termios *t;
+{
+
+ bcopy(ttydefchars, t->c_cc, sizeof t->c_cc);
+}
+
+#define LOTS_OF_EVENTS 64 /* helps separate urgent events from input */
+#define RB_I_HIGH_WATER (TTYHOG - 2 * RS_IBUFSIZE)
+#define RS_IBUFSIZE 256
+#define TTY_BI TTY_FE /* XXX */
+#define TTY_OE TTY_PE /* XXX */
+
+#define CALLOUT_MASK 0x80
+#define CONTROL_MASK 0x60
+#define CONTROL_INIT_STATE 0x20
+#define CONTROL_LOCK_STATE 0x40
+#define DEV_TO_UNIT(dev) (MINOR_TO_UNIT(minor(dev)))
+#define MINOR_MAGIC_MASK (CALLOUT_MASK | CONTROL_MASK)
+#define MINOR_TO_UNIT(mynor) ((mynor) & ~MINOR_MAGIC_MASK)
+
+#ifdef COM_MULTIPORT
+/* checks in flags for multiport and which is multiport "master chip"
+ * for a given card
+ */
+#define COM_ISMULTIPORT(dev) ((dev)->id_flags & 0x01)
+#define COM_MPMASTER(dev) (((dev)->id_flags >> 8) & 0x0ff)
+#define COM_NOTAST4(dev) ((dev)->id_flags & 0x04)
+#endif /* COM_MULTIPORT */
+
+#define COM_NOFIFO(dev) ((dev)->id_flags & 0x02)
+#define COM_VERBOSE(dev) ((dev)->id_flags & 0x80)
+
+#define com_scr 7 /* scratch register for 16450-16550 (R/W) */
+
+/*
+ * Input buffer watermarks.
+ * The external device is asked to stop sending when the buffer exactly reaches
+ * high water, or when the high level requests it.
+ * The high level is notified immediately (rather than at a later clock tick)
+ * when this watermark is reached.
+ * The buffer size is chosen so the watermark should almost never be reached.
+ * The low watermark is invisibly 0 since the buffer is always emptied all at
+ * once.
+ */
+#define RS_IHIGHWATER (3 * RS_IBUFSIZE / 4)
+
+/*
+ * com state bits.
+ * (CS_BUSY | CS_TTGO) and (CS_BUSY | CS_TTGO | CS_ODEVREADY) must be higher
+ * than the other bits so that they can be tested as a group without masking
+ * off the low bits.
+ *
+ * The following com and tty flags correspond closely:
+ * TS_BUSY = CS_BUSY (maintained by comstart() and comflush())
+ * CS_TTGO = ~TS_TTSTOP (maintained by comstart() and siostop())
+ * CS_CTS_OFLOW = CCTS_OFLOW (maintained by comparam())
+ * CS_RTS_IFLOW = CRTS_IFLOW (maintained by comparam())
+ * TS_FLUSH is not used.
+ * XXX I think TIOCSETA doesn't clear TS_TTSTOP when it clears IXON.
+ * XXX CS_*FLOW should be CF_*FLOW in com->flags (control flags not state).
+ */
+#define CS_BUSY 0x80 /* output in progress */
+#define CS_TTGO 0x40 /* output not stopped by XOFF */
+#define CS_ODEVREADY 0x20 /* external device h/w ready (CTS) */
+#define CS_CHECKMSR 1 /* check of MSR scheduled */
+#define CS_CTS_OFLOW 2 /* use CTS output flow control */
+#define CS_DTR_OFF 0x10 /* DTR held off */
+#define CS_ODONE 4 /* output completed */
+#define CS_RTS_IFLOW 8 /* use RTS input flow control */
+
+static char const * const error_desc[] = {
+#define CE_OVERRUN 0
+ "silo overflow",
+#define CE_INTERRUPT_BUF_OVERFLOW 1
+ "interrupt-level buffer overflow",
+#define CE_TTY_BUF_OVERFLOW 2
+ "tty-level buffer overflow",
+};
+
+#define CE_NTYPES 3
+#define CE_RECORD(com, errnum) (++(com)->delta_error_counts[errnum])
+
+/* types. XXX - should be elsewhere */
+typedef u_int Port_t; /* hardware port */
+typedef u_char bool_t; /* boolean */
+
+/* com device structure */
+struct com_s {
+ u_char state; /* miscellaneous flag bits */
+ bool_t active_out; /* nonzero if the callout device is open */
+ u_char cfcr_image; /* copy of value written to CFCR */
+ u_char ftl; /* current rx fifo trigger level */
+ u_char ftl_init; /* ftl_max for next open() */
+ u_char ftl_max; /* maximum ftl for curent open() */
+ bool_t hasfifo; /* nonzero for 16550 UARTs */
+ u_char mcr_image; /* copy of value written to MCR */
+#ifdef COM_MULTIPORT
+ bool_t multiport; /* is this unit part of a multiport device? */
+#endif /* COM_MULTIPORT */
+ int dtr_wait; /* time to hold DTR down on close (* 1/hz) */
+ u_int tx_fifo_size;
+ u_int wopeners; /* # processes waiting for DCD in open() */
+
+ /*
+ * The high level of the driver never reads status registers directly
+ * because there would be too many side effects to handle conveniently.
+ * Instead, it reads copies of the registers stored here by the
+ * interrupt handler.
+ */
+ u_char last_modem_status; /* last MSR read by intr handler */
+ u_char prev_modem_status; /* last MSR handled by high level */
+
+ u_char hotchar; /* ldisc-specific char to be handled ASAP */
+ u_char *ibuf; /* start of input buffer */
+ u_char *ibufend; /* end of input buffer */
+ u_char *ihighwater; /* threshold in input buffer */
+ u_char *iptr; /* next free spot in input buffer */
+
+ u_char *obufend; /* end of output buffer */
+ u_char *optr; /* next char to output */
+
+ Port_t data_port; /* i/o ports */
+ Port_t int_id_port;
+ Port_t iobase;
+ Port_t modem_ctl_port;
+ Port_t line_status_port;
+ Port_t modem_status_port;
+
+ struct tty *tp; /* cross reference */
+
+ /* Initial state. */
+ struct termios it_in; /* should be in struct tty */
+ struct termios it_out;
+
+ /* Lock state. */
+ struct termios lt_in; /* should be in struct tty */
+ struct termios lt_out;
+
+#ifdef TIOCTIMESTAMP
+ bool_t do_timestamp;
+ struct timeval timestamp;
+#endif
+
+ u_long bytes_in; /* statistics */
+ u_long bytes_out;
+ u_int delta_error_counts[CE_NTYPES];
+ u_int error_counts[CE_NTYPES];
+
+ /*
+ * Ping-pong input buffers. The extra factor of 2 in the sizes is
+ * to allow for an error byte for each input byte.
+ */
+#define CE_INPUT_OFFSET RS_IBUFSIZE
+ u_char ibuf1[2 * RS_IBUFSIZE];
+ u_char ibuf2[2 * RS_IBUFSIZE];
+
+ /*
+ * Output buffer. Someday we should avoid copying. Twice.
+ */
+ u_char obuf[256];
+};
+
+/*
+ * The public functions in the com module ought to be declared in a com-driver
+ * system header.
+ */
+
+/* Interrupt handling entry points. */
+void siointr __P((int unit));
+void siopoll __P((void));
+
+/* Device switch entry points. */
+int sioopen __P((dev_t dev, int oflags, int devtype,
+ struct proc *p));
+int sioclose __P((dev_t dev, int fflag, int devtype,
+ struct proc *p));
+int sioread __P((dev_t dev, struct uio *uio, int ioflag));
+int siowrite __P((dev_t dev, struct uio *uio, int ioflag));
+int sioioctl __P((dev_t dev, int cmd, caddr_t data,
+ int fflag, struct proc *p));
+void siostop __P((struct tty *tp, int rw));
+#define sioreset noreset
+int sioselect __P((dev_t dev, int rw, struct proc *p));
+#define siommap nommap
+#define siostrategy nostrategy
+
+/* Console device entry points. */
+int siocngetc __P((dev_t dev));
+struct consdev;
+void siocninit __P((struct consdev *cp));
+void siocnprobe __P((struct consdev *cp));
+void siocnputc __P((dev_t dev, int c));
+
+static int sioattach __P((struct isa_device *dev));
+static timeout_t siodtrwakeup;
+static void comflush __P((struct com_s *com));
+static void comhardclose __P((struct com_s *com));
+static void siointr1 __P((struct com_s *com));
+static void commctl __P((struct com_s *com, int bits, int how));
+static int comparam __P((struct tty *tp, struct termios *t));
+static int sioprobe __P((struct isa_device *dev));
+static void comstart __P((struct tty *tp));
+static timeout_t comwakeup;
+static int tiocm_xxx2mcr __P((int tiocm_xxx));
+
+/* table and macro for fast conversion from a unit number to its com struct */
+static struct com_s *p_com_addr[NSIO];
+#define com_addr(unit) (p_com_addr[unit])
+
+#ifdef TIOCTIMESTAMP
+static struct timeval intr_timestamp;
+#endif
+
+struct isa_driver siodriver = {
+ sioprobe, sioattach, "sio"
+};
+
+#ifdef COMCONSOLE
+static int comconsole = COMCONSOLE;
+#else
+static int comconsole = -1;
+#endif
+static speed_t comdefaultrate = TTYDEF_SPEED;
+static u_int com_events; /* input chars + weighted output completions */
+static int commajor;
+#if 0 /* XXX TK2.0 */
+struct tty *sio_tty[NSIO];
+#else
+struct tty sio_tty[NSIO];
+#endif
+extern struct tty *constty; /* XXX */
+
+#ifdef KGDB
+#include "machine/remote-sl.h"
+
+extern int kgdb_dev;
+extern int kgdb_rate;
+extern int kgdb_debug_init;
+#endif
+
+static struct speedtab comspeedtab[] = {
+ 0, 0,
+ 50, COMBRD(50),
+ 75, COMBRD(75),
+ 110, COMBRD(110),
+ 134, COMBRD(134),
+ 150, COMBRD(150),
+ 200, COMBRD(200),
+ 300, COMBRD(300),
+ 600, COMBRD(600),
+ 1200, COMBRD(1200),
+ 1800, COMBRD(1800),
+ 2400, COMBRD(2400),
+ 4800, COMBRD(4800),
+ 9600, COMBRD(9600),
+ 19200, COMBRD(19200),
+ 38400, COMBRD(38400),
+ 57600, COMBRD(57600),
+ 115200, COMBRD(115200),
+ -1, -1
+};
+
+/* XXX - configure this list */
+static Port_t likely_com_ports[] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, };
+
+static int
+sioprobe(dev)
+ struct isa_device *dev;
+{
+ static bool_t already_init;
+ Port_t *com_ptr;
+ bool_t failures[10];
+ int fn;
+ struct isa_device *idev;
+ Port_t iobase;
+ u_char mcr_image;
+ int result;
+
+ if (!already_init) {
+ /*
+ * Turn off MCR_IENABLE for all likely serial ports. An unused
+ * port with its MCR_IENABLE gate open will inhibit interrupts
+ * from any used port that shares the interrupt vector.
+ * XXX the gate enable is elsewhere for some multiports.
+ */
+ for (com_ptr = likely_com_ports;
+ com_ptr < &likely_com_ports[sizeof likely_com_ports
+ / sizeof likely_com_ports[0]];
+ ++com_ptr)
+ outb(*com_ptr + com_mcr, 0);
+ already_init = TRUE;
+ }
+
+ /*
+ * If the port is on a multiport card and has a master port,
+ * initialize the common interrupt control register in the
+ * master and prepare to leave MCR_IENABLE clear in the mcr.
+ * Otherwise, prepare to set MCR_IENABLE in the mcr.
+ * Point idev to the device struct giving the correct id_irq.
+ * This is the struct for the master device if there is one.
+ */
+ idev = dev;
+ mcr_image = MCR_IENABLE;
+#ifdef COM_MULTIPORT
+ if (COM_ISMULTIPORT(dev)) {
+ idev = find_isadev(isa_devtab_tty, &siodriver,
+ COM_MPMASTER(dev));
+ if (idev == NULL) {
+ printf("sio%d: master device %d not found\n",
+ dev->id_unit, COM_MPMASTER(dev));
+ return (0);
+ }
+ if (idev->id_irq == 0) {
+ printf("sio%d: master device %d irq not configured\n",
+ dev->id_unit, COM_MPMASTER(dev));
+ return (0);
+ }
+ if (!COM_NOTAST4(dev)) {
+ outb(idev->id_iobase + com_scr, 0x80);
+ mcr_image = 0;
+ }
+ }
+ else
+#endif /* COM_MULTIPORT */
+ if (idev->id_irq == 0) {
+ printf("sio%d: irq not configured\n", dev->id_unit);
+ return (0);
+ }
+
+ bzero(failures, sizeof failures);
+ iobase = dev->id_iobase;
+
+ /*
+ * We don't want to get actual interrupts, just masked ones.
+ * Interrupts from this line should already be masked in the ICU,
+ * but mask them in the processor as well in case there are some
+ * (misconfigured) shared interrupts.
+ */
+ disable_intr();
+
+ /*
+ * XXX DELAY() reenables CPU interrupts. This is a problem for
+ * shared interrupts after the first device using one has been
+ * successfully probed - config_isadev() has enabled the interrupt
+ * in the ICU.
+ */
+ outb(IO_ICU1 + 1, 0xff);
+
+ /*
+ * Initialize the speed and the word size and wait long enough to
+ * drain the maximum of 16 bytes of junk in device output queues.
+ * The speed is undefined after a master reset and must be set
+ * before relying on anything related to output. There may be
+ * junk after a (very fast) soft reboot and (apparently) after
+ * master reset.
+ * XXX what about the UART bug avoided by waiting in comparam()?
+ * We don't want to to wait long enough to drain at 2 bps.
+ */
+ outb(iobase + com_cfcr, CFCR_DLAB);
+ outb(iobase + com_dlbl, COMBRD(9600) & 0xff);
+ outb(iobase + com_dlbh, (u_int) COMBRD(9600) >> 8);
+ outb(iobase + com_cfcr, CFCR_8BITS);
+ DELAY((16 + 1) * 9600 / 10);
+
+ /*
+ * Enable the interrupt gate and disable device interupts. This
+ * should leave the device driving the interrupt line low and
+ * guarantee an edge trigger if an interrupt can be generated.
+ */
+ outb(iobase + com_mcr, mcr_image);
+ outb(iobase + com_ier, 0);
+
+ /*
+ * Attempt to set loopback mode so that we can send a null byte
+ * without annoying any external device.
+ */
+ outb(iobase + com_mcr, mcr_image | MCR_LOOPBACK);
+
+ /*
+ * Attempt to generate an output interrupt. On 8250's, setting
+ * IER_ETXRDY generates an interrupt independent of the current
+ * setting and independent of whether the THR is empty. On 16450's,
+ * setting IER_ETXRDY generates an interrupt independent of the
+ * current setting. On 16550A's, setting IER_ETXRDY only
+ * generates an interrupt when IER_ETXRDY is not already set.
+ */
+ outb(iobase + com_ier, IER_ETXRDY);
+
+ /*
+ * On some 16x50 incompatibles, setting IER_ETXRDY doesn't generate
+ * an interrupt. They'd better generate one for actually doing
+ * output. Loopback may be broken on the same incompatibles but
+ * it's unlikely to do more than allow the null byte out.
+ */
+ outb(iobase + com_data, 0);
+ DELAY((2 + 1) * 9600 / 10);
+
+ /*
+ * Turn off loopback mode so that the interrupt gate works again
+ * (MCR_IENABLE was hidden). This should leave the device driving
+ * an interrupt line high. It doesn't matter if the interrupt
+ * line oscillates while we are not looking at it, since interrupts
+ * are disabled.
+ */
+ outb(iobase + com_mcr, mcr_image);
+
+ /*
+ * Check that
+ * o the CFCR, IER and MCR in UART hold the values written to them
+ * (the values happen to be all distinct - this is good for
+ * avoiding false positive tests from bus echoes).
+ * o an output interrupt is generated and its vector is correct.
+ * o the interrupt goes away when the IIR in the UART is read.
+ */
+ failures[0] = inb(iobase + com_cfcr) - CFCR_8BITS;
+ failures[1] = inb(iobase + com_ier) - IER_ETXRDY;
+ failures[2] = inb(iobase + com_mcr) - mcr_image;
+ if (idev->id_irq != 0)
+ failures[3] = isa_irq_pending(idev) ? 0 : 1;
+ failures[4] = (inb(iobase + com_iir) & IIR_IMASK) - IIR_TXRDY;
+ failures[5] = isa_irq_pending(idev) ? 1 : 0;
+ failures[6] = (inb(iobase + com_iir) & IIR_IMASK) - IIR_NOPEND;
+
+ /*
+ * Turn off all device interrupts and check that they go off properly.
+ * Leave MCR_IENABLE alone. For ports without a master port, it gates
+ * the OUT2 output of the UART to
+ * the ICU input. Closing the gate would give a floating ICU input
+ * (unless there is another device driving at) and spurious interrupts.
+ * (On the system that this was first tested on, the input floats high
+ * and gives a (masked) interrupt as soon as the gate is closed.)
+ */
+ outb(iobase + com_ier, 0);
+ outb(iobase + com_cfcr, CFCR_8BITS); /* dummy to avoid bus echo */
+ failures[7] = inb(iobase + com_ier);
+ failures[8] = isa_irq_pending(idev) ? 1 : 0;
+ failures[9] = (inb(iobase + com_iir) & IIR_IMASK) - IIR_NOPEND;
+
+ outb(IO_ICU1 + 1, imen); /* XXX */
+ enable_intr();
+
+ result = IO_COMSIZE;
+ for (fn = 0; fn < sizeof failures; ++fn)
+ if (failures[fn]) {
+ outb(iobase + com_mcr, 0);
+ result = 0;
+ if (COM_VERBOSE(dev))
+ printf("sio%d: probe test %d failed\n",
+ dev->id_unit, fn);
+ }
+ return (result);
+}
+
+static int
+sioattach(isdp)
+ struct isa_device *isdp;
+{
+ struct com_s *com;
+ static bool_t comwakeup_started = FALSE;
+ Port_t iobase;
+ int s;
+ int unit;
+
+ isdp->id_ri_flags |= RI_FAST;
+ iobase = isdp->id_iobase;
+ unit = isdp->id_unit;
+ com = malloc(sizeof *com, M_TTYS, M_NOWAIT);
+ if (com == NULL)
+ return (0);
+
+ /*
+ * sioprobe() has initialized the device registers as follows:
+ * o cfcr = CFCR_8BITS.
+ * It is most important that CFCR_DLAB is off, so that the
+ * data port is not hidden when we enable interrupts.
+ * o ier = 0.
+ * Interrupts are only enabled when the line is open.
+ * o mcr = MCR_IENABLE, or 0 if the port has a master port.
+ * Keeping MCR_DTR and MCR_RTS off might stop the external
+ * device from sending before we are ready.
+ */
+ bzero(com, sizeof *com);
+ com->cfcr_image = CFCR_8BITS;
+ com->dtr_wait = 3 * hz;
+ com->tx_fifo_size = 1;
+ com->iptr = com->ibuf = com->ibuf1;
+ com->ibufend = com->ibuf1 + RS_IBUFSIZE;
+ com->ihighwater = com->ibuf1 + RS_IHIGHWATER;
+ com->iobase = iobase;
+ com->data_port = iobase + com_data;
+ com->int_id_port = iobase + com_iir;
+ com->modem_ctl_port = iobase + com_mcr;
+ com->mcr_image = inb(com->modem_ctl_port);
+ com->line_status_port = iobase + com_lsr;
+ com->modem_status_port = iobase + com_msr;
+
+ /*
+ * We don't use all the flags from <sys/ttydefaults.h> since they
+ * are only relevant for logins. It's important to have echo off
+ * initially so that the line doesn't start blathering before the
+ * echo flag can be turned off.
+ */
+ com->it_in.c_iflag = 0;
+ com->it_in.c_oflag = 0;
+ com->it_in.c_cflag = TTYDEF_CFLAG;
+ com->it_in.c_lflag = 0;
+ if (unit == comconsole) {
+ com->it_in.c_iflag = TTYDEF_IFLAG;
+ com->it_in.c_oflag = TTYDEF_OFLAG;
+ com->it_in.c_cflag = TTYDEF_CFLAG | CLOCAL;
+ com->it_in.c_lflag = TTYDEF_LFLAG;
+ com->lt_out.c_cflag = com->lt_in.c_cflag = CLOCAL;
+ }
+ termioschars(&com->it_in);
+ com->it_in.c_ispeed = com->it_in.c_ospeed = comdefaultrate;
+ com->it_out = com->it_in;
+
+ /* attempt to determine UART type */
+ printf("sio%d: type", unit);
+#ifdef COM_MULTIPORT
+ if (!COM_ISMULTIPORT(isdp))
+#endif
+ {
+ u_char scr;
+ u_char scr1;
+ u_char scr2;
+
+ scr = inb(iobase + com_scr);
+ outb(iobase + com_scr, 0xa5);
+ scr1 = inb(iobase + com_scr);
+ outb(iobase + com_scr, 0x5a);
+ scr2 = inb(iobase + com_scr);
+ outb(iobase + com_scr, scr);
+ if (scr1 != 0xa5 || scr2 != 0x5a) {
+ printf(" 8250");
+ goto determined_type;
+ }
+ }
+ outb(iobase + com_fifo, FIFO_ENABLE | FIFO_TRIGGER_14);
+ DELAY(100);
+ switch (inb(com->int_id_port) & IIR_FIFO_MASK) {
+ case FIFO_TRIGGER_1:
+ printf(" 16450");
+ break;
+ case FIFO_TRIGGER_4:
+ printf(" 16450?");
+ break;
+ case FIFO_TRIGGER_8:
+ printf(" 16550?");
+ break;
+ case FIFO_TRIGGER_14:
+ printf(" 16550A");
+ if (COM_NOFIFO(isdp))
+ printf(" fifo disabled");
+ else {
+ com->hasfifo = TRUE;
+ com->ftl_init = FIFO_TRIGGER_14;
+ com->tx_fifo_size = 16;
+ }
+ break;
+ }
+ outb(iobase + com_fifo, 0);
+determined_type: ;
+
+#ifdef COM_MULTIPORT
+ if (COM_ISMULTIPORT(isdp)) {
+ com->multiport = TRUE;
+ printf(" (multiport");
+ if (unit == COM_MPMASTER(isdp))
+ printf(" master");
+ printf(")");
+ }
+#endif /* COM_MULTIPORT */
+ printf("\n");
+
+#ifdef KGDB
+ if (kgdb_dev == makedev(commajor, unit)) {
+ if (unit == comconsole)
+ kgdb_dev = -1; /* can't debug over console port */
+ else {
+ int divisor;
+
+ /*
+ * XXX now unfinished and broken. Need to do
+ * something more like a full open(). There's no
+ * suitable interrupt handler so don't enable device
+ * interrupts. Watch out for null tp's.
+ */
+ outb(iobase + com_cfcr, CFCR_DLAB);
+ divisor = ttspeedtab(kgdb_rate, comspeedtab);
+ outb(iobase + com_dlbl, divisor & 0xFF);
+ outb(iobase + com_dlbh, (u_int) divisor >> 8);
+ outb(iobase + com_cfcr, CFCR_8BITS);
+ outb(com->modem_status_port,
+ com->mcr_image |= MCR_DTR | MCR_RTS);
+
+ if (kgdb_debug_init) {
+ /*
+ * Print prefix of device name,
+ * let kgdb_connect print the rest.
+ */
+ printf("sio%d: ", unit);
+ kgdb_connect(1);
+ } else
+ printf("sio%d: kgdb enabled\n", unit);
+ }
+ }
+#endif
+
+ s = spltty();
+ com_addr(unit) = com;
+ splx(s);
+ if (!comwakeup_started) {
+ comwakeup((void *)NULL);
+ comwakeup_started = TRUE;
+ }
+ return (1);
+}
+
+/* ARGSUSED */
+int
+sioopen(dev, flag, mode, p)
+ dev_t dev;
+ int flag;
+ int mode;
+ struct proc *p;
+{
+ struct com_s *com;
+ int error;
+ Port_t iobase;
+ int mynor;
+ int s;
+ struct tty *tp;
+ int unit;
+
+ mynor = minor(dev);
+ unit = MINOR_TO_UNIT(mynor);
+ if ((u_int) unit >= NSIO || (com = com_addr(unit)) == NULL)
+ return (ENXIO);
+ if (mynor & CONTROL_MASK)
+ return (0);
+#if 0 /* XXX TK2.0 */
+ tp = com->tp = sio_tty[unit] = ttymalloc(sio_tty[unit]);
+#else
+ tp = com->tp = &sio_tty[unit];
+#endif
+ s = spltty();
+ /*
+ * We jump to this label after all non-interrupted sleeps to pick
+ * up any changes of the device state.
+ */
+open_top:
+ while (com->state & CS_DTR_OFF) {
+ error = tsleep(&com->dtr_wait, TTIPRI | PCATCH, "siodtr", 0);
+ if (error != 0)
+ goto out;
+ }
+ if (tp->t_state & TS_ISOPEN) {
+ /*
+ * The device is open, so everything has been initialized.
+ * Handle conflicts.
+ */
+ if (mynor & CALLOUT_MASK) {
+ if (!com->active_out) {
+ error = EBUSY;
+ goto out;
+ }
+ } else {
+ if (com->active_out) {
+ if (flag & O_NONBLOCK) {
+ error = EBUSY;
+ goto out;
+ }
+ error = tsleep(&com->active_out,
+ TTIPRI | PCATCH, "siobi", 0);
+ if (error != 0)
+ goto out;
+ goto open_top;
+ }
+ }
+ if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) {
+ error = EBUSY;
+ goto out;
+ }
+ } else {
+ /*
+ * The device isn't open, so there are no conflicts.
+ * Initialize it. Initialization is done twice in many
+ * cases: to preempt sleeping callin opens if we are
+ * callout, and to complete a callin open after DCD rises.
+ */
+ tp->t_oproc = comstart;
+ tp->t_param = comparam;
+ tp->t_dev = dev;
+ tp->t_termios = mynor & CALLOUT_MASK
+ ? com->it_out : com->it_in;
+ commctl(com, MCR_DTR | MCR_RTS, DMSET);
+ com->ftl_max = com->ftl_init;
+ ++com->wopeners;
+ error = comparam(tp, &tp->t_termios);
+ --com->wopeners;
+ if (error != 0)
+ goto out;
+ /*
+ * XXX we should goto open_top if comparam() slept.
+ */
+ ttsetwater(tp);
+ iobase = com->iobase;
+ if (com->hasfifo) {
+ /* Drain fifo. */
+ outb(iobase + com_fifo,
+ FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST
+ | com->ftl);
+ DELAY(100);
+ }
+ disable_intr();
+ (void) inb(com->line_status_port);
+ (void) inb(com->data_port);
+ com->prev_modem_status =
+ com->last_modem_status = inb(com->modem_status_port);
+ outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS
+ | IER_EMSC);
+ enable_intr();
+ /*
+ * Handle initial DCD. Callout devices get a fake initial
+ * DCD (trapdoor DCD). If we are callout, then any sleeping
+ * callin opens get woken up and resume sleeping on "siobi"
+ * instead of "siodcd".
+ */
+ if (com->prev_modem_status & MSR_DCD || mynor & CALLOUT_MASK)
+ (*linesw[tp->t_line].l_modem)(tp, 1);
+ }
+ /*
+ * Wait for DCD if necessary.
+ */
+ if (!(tp->t_state & TS_CARR_ON) && !(mynor & CALLOUT_MASK)
+ && !(tp->t_cflag & CLOCAL) && !(flag & O_NONBLOCK)) {
+ ++com->wopeners;
+ error = tsleep(TSA_CARR_ON(tp), TTIPRI | PCATCH, "siodcd", 0);
+ --com->wopeners;
+ if (error != 0)
+ goto out;
+ goto open_top;
+ }
+ error = (*linesw[tp->t_line].l_open)(dev, tp);
+ if (tp->t_state & TS_ISOPEN && mynor & CALLOUT_MASK)
+ com->active_out = TRUE;
+out:
+ splx(s);
+ if (!(tp->t_state & TS_ISOPEN) && com->wopeners == 0)
+ comhardclose(com);
+ return (error);
+}
+
+/*ARGSUSED*/
+int
+sioclose(dev, flag, mode, p)
+ dev_t dev;
+ int flag;
+ int mode;
+ struct proc *p;
+{
+ struct com_s *com;
+ int mynor;
+ int s;
+ struct tty *tp;
+
+ mynor = minor(dev);
+ if (mynor & CONTROL_MASK)
+ return (0);
+ com = com_addr(MINOR_TO_UNIT(mynor));
+ tp = com->tp;
+ s = spltty();
+ (*linesw[tp->t_line].l_close)(tp, flag);
+ siostop(tp, FREAD | FWRITE);
+ comhardclose(com);
+ ttyclose(tp);
+ splx(s);
+ return (0);
+}
+
+static void
+comhardclose(com)
+ struct com_s *com;
+{
+ Port_t iobase;
+ int s;
+ struct tty *tp;
+ int unit;
+
+ unit = DEV_TO_UNIT(com->tp->t_dev);
+ iobase = com->iobase;
+ s = spltty();
+#ifdef TIOCTIMESTAMP
+ com->do_timestamp = 0;
+#endif
+ outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
+#ifdef KGDB
+ /* do not disable interrupts or hang up if debugging */
+ if (kgdb_dev != makedev(commajor, unit))
+#endif
+ {
+ outb(iobase + com_ier, 0);
+ tp = com->tp;
+ if (tp->t_cflag & HUPCL
+ /*
+ * XXX we will miss any carrier drop between here and the
+ * next open. Perhaps we should watch DCD even when the
+ * port is closed; it is not sufficient to check it at
+ * the next open because it might go up and down while
+ * we're not watching.
+ */
+ || !com->active_out
+ && !(com->prev_modem_status & MSR_DCD)
+ && !(com->it_in.c_cflag & CLOCAL)
+ || !(tp->t_state & TS_ISOPEN)) {
+ commctl(com, MCR_RTS, DMSET);
+ if (com->dtr_wait != 0) {
+ timeout(siodtrwakeup, com, com->dtr_wait);
+ com->state |= CS_DTR_OFF;
+ }
+ }
+ }
+ com->active_out = FALSE;
+ wakeup(&com->active_out);
+ wakeup(TSA_CARR_ON(tp)); /* restart any wopeners */
+ splx(s);
+}
+
+int
+sioread(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ int mynor;
+ struct tty *tp;
+
+ mynor = minor(dev);
+ if (mynor & CONTROL_MASK)
+ return (ENODEV);
+ tp = com_addr(MINOR_TO_UNIT(mynor))->tp;
+ return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
+}
+
+int
+siowrite(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ int mynor;
+ struct tty *tp;
+ int unit;
+
+ mynor = minor(dev);
+ if (mynor & CONTROL_MASK)
+ return (ENODEV);
+ unit = MINOR_TO_UNIT(mynor);
+ tp = com_addr(unit)->tp;
+ /*
+ * (XXX) We disallow virtual consoles if the physical console is
+ * a serial port. This is in case there is a display attached that
+ * is not the console. In that situation we don't need/want the X
+ * server taking over the console.
+ */
+ if (constty && unit == comconsole)
+ constty = NULL;
+ return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
+}
+
+static void
+siodtrwakeup(chan)
+ void *chan;
+{
+ struct com_s *com;
+
+ com = (struct com_s *)chan;
+ com->state &= ~CS_DTR_OFF;
+ wakeup(&com->dtr_wait);
+}
+
+#ifdef TIOCTIMESTAMP
+/* Interrupt routine for timekeeping purposes */
+void
+siointrts(unit)
+ int unit;
+{
+ microtime(&intr_timestamp);
+ siointr(unit);
+}
+#endif
+
+void
+siointr(unit)
+ int unit;
+{
+#ifndef COM_MULTIPORT
+ siointr1(com_addr(unit));
+#else /* COM_MULTIPORT */
+ struct com_s *com;
+ bool_t possibly_more_intrs;
+
+ /*
+ * Loop until there is no activity on any port. This is necessary
+ * to get an interrupt edge more than to avoid another interrupt.
+ * If the IRQ signal is just an OR of the IRQ signals from several
+ * devices, then the edge from one may be lost because another is
+ * on.
+ */
+ do {
+ possibly_more_intrs = FALSE;
+ for (unit = 0; unit < NSIO; ++unit) {
+ com = com_addr(unit);
+ if (com != NULL
+ && (inb(com->int_id_port) & IIR_IMASK)
+ != IIR_NOPEND) {
+ siointr1(com);
+ possibly_more_intrs = TRUE;
+ }
+ }
+ } while (possibly_more_intrs);
+#endif /* COM_MULTIPORT */
+}
+
+static void
+siointr1(com)
+ struct com_s *com;
+{
+ u_char line_status;
+ u_char modem_status;
+ u_char *ioptr;
+ u_char recv_data;
+
+#ifdef TIOCTIMESTAMP
+ if (com->do_timestamp)
+ /* XXX a little bloat here... */
+ com->timestamp = intr_timestamp;
+#endif
+ while (TRUE) {
+ line_status = inb(com->line_status_port);
+
+ /* input event? (check first to help avoid overruns) */
+ while (line_status & LSR_RCV_MASK) {
+ /* break/unnattached error bits or real input? */
+ if (!(line_status & LSR_RXRDY))
+ recv_data = 0;
+ else
+ recv_data = inb(com->data_port);
+ ++com->bytes_in;
+ if (com->hotchar != 0 && recv_data == com->hotchar)
+ setsofttty();
+#ifdef KGDB
+ /* trap into kgdb? (XXX - needs testing and optim) */
+ if (recv_data == FRAME_END
+ && !(com->tp->t_state & TS_ISOPEN)
+ && kgdb_dev == makedev(commajor, unit)) {
+ kgdb_connect(0);
+ continue;
+ }
+#endif /* KGDB */
+ ioptr = com->iptr;
+ if (ioptr >= com->ibufend)
+ CE_RECORD(com, CE_INTERRUPT_BUF_OVERFLOW);
+ else {
+ ++com_events;
+#if 0 /* for testing input latency vs efficiency */
+if (com->iptr - com->ibuf == 8)
+ setsofttty();
+#endif
+ ioptr[0] = recv_data;
+ ioptr[CE_INPUT_OFFSET] = line_status;
+ com->iptr = ++ioptr;
+ if (ioptr == com->ihighwater
+ && com->state & CS_RTS_IFLOW)
+ outb(com->modem_ctl_port,
+ com->mcr_image &= ~MCR_RTS);
+ /* XXX - move this out of isr */
+ if (line_status & LSR_OE)
+ CE_RECORD(com, CE_OVERRUN);
+ }
+
+ /*
+ * "& 0x7F" is to avoid the gcc-1.40 generating a slow
+ * jump from the top of the loop to here
+ */
+ line_status = inb(com->line_status_port) & 0x7F;
+ }
+
+ /* modem status change? (always check before doing output) */
+ modem_status = inb(com->modem_status_port);
+ if (modem_status != com->last_modem_status) {
+ /*
+ * Schedule high level to handle DCD changes. Note
+ * that we don't use the delta bits anywhere. Some
+ * UARTs mess them up, and it's easy to remember the
+ * previous bits and calculate the delta.
+ */
+ com->last_modem_status = modem_status;
+ if (!(com->state & CS_CHECKMSR)) {
+ com_events += LOTS_OF_EVENTS;
+ com->state |= CS_CHECKMSR;
+ setsofttty();
+ }
+
+ /* handle CTS change immediately for crisp flow ctl */
+ if (com->state & CS_CTS_OFLOW) {
+ if (modem_status & MSR_CTS)
+ com->state |= CS_ODEVREADY;
+ else
+ com->state &= ~CS_ODEVREADY;
+ }
+ }
+
+ /* output queued and everything ready? */
+ if (line_status & LSR_TXRDY
+ && com->state >= (CS_ODEVREADY | CS_BUSY | CS_TTGO)) {
+ ioptr = com->optr;
+ if (com->tx_fifo_size > 1) {
+ u_int ocount;
+
+ ocount = com->obufend - ioptr;
+ if (ocount > com->tx_fifo_size)
+ ocount = com->tx_fifo_size;
+ com->bytes_out += ocount;
+ do
+ outb(com->data_port, *ioptr++);
+ while (--ocount != 0);
+ } else {
+ outb(com->data_port, *ioptr++);
+ ++com->bytes_out;
+ }
+ com->optr = ioptr;
+ if (ioptr >= com->obufend) {
+ /* output just completed */
+ com_events += LOTS_OF_EVENTS;
+ com->state ^= (CS_ODONE | CS_BUSY);
+ setsofttty(); /* handle at high level ASAP */
+ }
+ }
+
+ /* finished? */
+#ifndef COM_MULTIPORT
+ if ((inb(com->int_id_port) & IIR_IMASK) == IIR_NOPEND)
+#endif /* COM_MULTIPORT */
+ return;
+ }
+}
+
+static int
+tiocm_xxx2mcr(tiocm_xxx)
+ int tiocm_xxx;
+{
+ int mcr;
+
+ mcr = 0;
+ if (tiocm_xxx & TIOCM_DTR)
+ mcr |= MCR_DTR;
+ if (tiocm_xxx & TIOCM_RTS)
+ mcr |= MCR_RTS;
+ return (mcr);
+}
+
+int
+sioioctl(dev, cmd, data, flag, p)
+ dev_t dev;
+ int cmd;
+ caddr_t data;
+ int flag;
+ struct proc *p;
+{
+ struct com_s *com;
+ int error;
+ Port_t iobase;
+ int mcr;
+ int msr;
+ int mynor;
+ int s;
+ int tiocm_xxx;
+ struct tty *tp;
+
+ mynor = minor(dev);
+ com = com_addr(MINOR_TO_UNIT(mynor));
+ if (mynor & CONTROL_MASK) {
+ struct termios *ct;
+
+ switch (mynor & CONTROL_MASK) {
+ case CONTROL_INIT_STATE:
+ ct = mynor & CALLOUT_MASK ? &com->it_out : &com->it_in;
+ break;
+ case CONTROL_LOCK_STATE:
+ ct = mynor & CALLOUT_MASK ? &com->lt_out : &com->lt_in;
+ break;
+ default:
+ return (ENODEV); /* /dev/nodev */
+ }
+ switch (cmd) {
+ case TIOCSETA:
+ error = suser(p->p_ucred, &p->p_acflag);
+ if (error)
+ return (error);
+ *ct = *(struct termios *)data;
+ return (0);
+ case TIOCGETA:
+ *(struct termios *)data = *ct;
+ return (0);
+ case TIOCGETD:
+ *(int *)data = TTYDISC;
+ return (0);
+ case TIOCGWINSZ:
+ bzero(data, sizeof(struct winsize));
+ return (0);
+ default:
+ return (ENOTTY);
+ }
+ }
+ tp = com->tp;
+ if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
+ int cc;
+ struct termios *dt = (struct termios *)data;
+ struct termios *lt = mynor & CALLOUT_MASK
+ ? &com->lt_out : &com->lt_in;
+
+ dt->c_iflag = (tp->t_iflag & lt->c_iflag)
+ | (dt->c_iflag & ~lt->c_iflag);
+ dt->c_oflag = (tp->t_oflag & lt->c_oflag)
+ | (dt->c_oflag & ~lt->c_oflag);
+ dt->c_cflag = (tp->t_cflag & lt->c_cflag)
+ | (dt->c_cflag & ~lt->c_cflag);
+ dt->c_lflag = (tp->t_lflag & lt->c_lflag)
+ | (dt->c_lflag & ~lt->c_lflag);
+ for (cc = 0; cc < NCCS; ++cc)
+ if (lt->c_cc[cc] != 0)
+ dt->c_cc[cc] = tp->t_cc[cc];
+ if (lt->c_ispeed != 0)
+ dt->c_ispeed = tp->t_ispeed;
+ if (lt->c_ospeed != 0)
+ dt->c_ospeed = tp->t_ospeed;
+ }
+ error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
+ if (error >= 0)
+ return (error);
+ error = ttioctl(tp, cmd, data, flag);
+ if (error >= 0)
+ return (error);
+ iobase = com->iobase;
+ s = spltty();
+ switch (cmd) {
+ case TIOCSBRK:
+ outb(iobase + com_cfcr, com->cfcr_image |= CFCR_SBREAK);
+ break;
+ case TIOCCBRK:
+ outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
+ break;
+ case TIOCSDTR:
+ commctl(com, MCR_DTR, DMBIS);
+ break;
+ case TIOCCDTR:
+ commctl(com, MCR_DTR, DMBIC);
+ break;
+ case TIOCMSET:
+ commctl(com, tiocm_xxx2mcr(*(int *)data), DMSET);
+ break;
+ case TIOCMBIS:
+ commctl(com, tiocm_xxx2mcr(*(int *)data), DMBIS);
+ break;
+ case TIOCMBIC:
+ commctl(com, tiocm_xxx2mcr(*(int *)data), DMBIC);
+ break;
+ case TIOCMGET:
+ tiocm_xxx = TIOCM_LE; /* XXX - always enabled while open */
+ mcr = com->mcr_image;
+ if (mcr & MCR_DTR)
+ tiocm_xxx |= TIOCM_DTR;
+ if (mcr & MCR_RTS)
+ tiocm_xxx |= TIOCM_RTS;
+ msr = com->prev_modem_status;
+ if (msr & MSR_CTS)
+ tiocm_xxx |= TIOCM_CTS;
+ if (msr & MSR_DCD)
+ tiocm_xxx |= TIOCM_CD;
+ if (msr & MSR_DSR)
+ tiocm_xxx |= TIOCM_DSR;
+ /*
+ * XXX - MSR_RI is naturally volatile, and we make MSR_TERI
+ * more volatile by reading the modem status a lot. Perhaps
+ * we should latch both bits until the status is read here.
+ */
+ if (msr & (MSR_RI | MSR_TERI))
+ tiocm_xxx |= TIOCM_RI;
+ *(int *)data = tiocm_xxx;
+ break;
+ case TIOCMSDTRWAIT:
+ /* must be root since the wait applies to following logins */
+ error = suser(p->p_ucred, &p->p_acflag);
+ if (error != 0) {
+ splx(s);
+ return (EPERM);
+ }
+ com->dtr_wait = *(int *)data * 100 / hz;
+ break;
+ case TIOCMGDTRWAIT:
+ *(int *)data = com->dtr_wait;
+ break;
+#ifdef TIOCTIMESTAMP
+ case TIOCTIMESTAMP:
+ com->do_timestamp = TRUE;
+ *(struct timeval *)data = com->timestamp;
+ break;
+#endif
+ default:
+ splx(s);
+ return (ENOTTY);
+ }
+ splx(s);
+ return (0);
+}
+
+/* cancel pending output */
+static void
+comflush(com)
+ struct com_s *com;
+{
+ disable_intr();
+ if (com->state & CS_ODONE)
+ com_events -= LOTS_OF_EVENTS;
+ com->state &= ~(CS_ODONE | CS_BUSY);
+ enable_intr();
+ com->tp->t_state &= ~TS_BUSY;
+}
+
+void
+siopoll()
+{
+ int unit;
+
+ if (com_events == 0)
+ return;
+repeat:
+ for (unit = 0; unit < NSIO; ++unit) {
+ u_char *buf;
+ struct com_s *com;
+ u_char *ibuf;
+ int incc;
+ struct tty *tp;
+
+ com = com_addr(unit);
+ if (com == NULL)
+ continue;
+ tp = com->tp;
+ if (tp == NULL)
+ continue;
+
+ /* switch the role of the low-level input buffers */
+ if (com->iptr == (ibuf = com->ibuf)) {
+ buf = NULL; /* not used, but compiler can't tell */
+ incc = 0;
+ } else {
+ /*
+ * Prepare to reduce input latency for packet
+ * discplines with a end of packet character.
+ * XXX should be elsewhere.
+ */
+ if (tp->t_line == SLIPDISC)
+ com->hotchar = 0xc0;
+ else if (tp->t_line == PPPDISC)
+ com->hotchar = 0x7e;
+ else
+ com->hotchar = 0;
+ buf = ibuf;
+ disable_intr();
+ incc = com->iptr - buf;
+ com_events -= incc;
+ if (ibuf == com->ibuf1)
+ ibuf = com->ibuf2;
+ else
+ ibuf = com->ibuf1;
+ com->ibufend = ibuf + RS_IBUFSIZE;
+ com->ihighwater = ibuf + RS_IHIGHWATER;
+ com->iptr = ibuf;
+
+ /*
+ * There is now room for another low-level buffer full
+ * of input, so enable RTS if it is now disabled and
+ * there is room in the high-level buffer.
+ */
+ /*
+ * XXX this used not to look at CS_RTS_IFLOW. The
+ * change is to allow full control of MCR_RTS via
+ * ioctls after turning CS_RTS_IFLOW off. Check
+ * for races. We shouldn't allow the ioctls while
+ * CS_RTS_IFLOW is on.
+ */
+ if ((com->state & CS_RTS_IFLOW)
+ && !(com->mcr_image & MCR_RTS)
+ && !(tp->t_state & TS_RTS_IFLOW))
+ outb(com->modem_ctl_port,
+ com->mcr_image |= MCR_RTS);
+ enable_intr();
+ com->ibuf = ibuf;
+ }
+
+ if (com->state & CS_CHECKMSR) {
+ u_char delta_modem_status;
+
+ disable_intr();
+ delta_modem_status = com->last_modem_status
+ ^ com->prev_modem_status;
+ com->prev_modem_status = com->last_modem_status;
+ com_events -= LOTS_OF_EVENTS;
+ com->state &= ~CS_CHECKMSR;
+ enable_intr();
+ if (delta_modem_status & MSR_DCD)
+ (*linesw[tp->t_line].l_modem)
+ (tp, com->prev_modem_status & MSR_DCD);
+ }
+
+ /* XXX */
+ if (TRUE) {
+ u_int delta;
+ int errnum;
+ u_long total;
+
+ for (errnum = 0; errnum < CE_NTYPES; ++errnum) {
+ disable_intr();
+ delta = com->delta_error_counts[errnum];
+ com->delta_error_counts[errnum] = 0;
+ enable_intr();
+ if (delta == 0 || !(tp->t_state & TS_ISOPEN))
+ continue;
+ total = com->error_counts[errnum] += delta;
+ log(LOG_WARNING,
+ "sio%d: %u more %s%s (total %lu)\n",
+ unit, delta, error_desc[errnum],
+ delta == 1 ? "" : "s", total);
+ if (errnum == CE_OVERRUN && com->hasfifo
+ && com->ftl > FIFO_TRIGGER_1) {
+ static u_char ftl_in_bytes[] =
+ { 1, 4, 8, 14, };
+
+ com->ftl_init = FIFO_TRIGGER_8;
+#define FIFO_TRIGGER_DELTA FIFO_TRIGGER_4
+ com->ftl_max =
+ com->ftl -= FIFO_TRIGGER_DELTA;
+ outb(com->iobase + com_fifo,
+ FIFO_ENABLE | com->ftl);
+ log(LOG_WARNING,
+ "sio%d: reduced fifo trigger level to %d\n",
+ unit,
+ ftl_in_bytes[com->ftl
+ / FIFO_TRIGGER_DELTA]);
+ }
+ }
+ }
+ if (com->state & CS_ODONE) {
+ comflush(com);
+ /* XXX - why isn't the table used for t_line == 0? */
+ if (tp->t_line != 0)
+ (*linesw[tp->t_line].l_start)(tp);
+ else
+ comstart(tp);
+ }
+ if (incc <= 0 || !(tp->t_state & TS_ISOPEN))
+ continue;
+ if (com->state & CS_RTS_IFLOW
+ && tp->t_rawq.c_cc + incc >= RB_I_HIGH_WATER
+ && !(tp->t_state & TS_RTS_IFLOW)
+ /*
+ * XXX - need RTS flow control for all line disciplines.
+ * Only have it in standard one now.
+ */
+ && linesw[tp->t_line].l_rint == ttyinput) {
+ tp->t_state |= TS_RTS_IFLOW;
+ ttstart(tp);
+ }
+ /*
+ * Avoid the grotesquely inefficient lineswitch routine
+ * (ttyinput) in "raw" mode. It usually takes about 450
+ * instructions (that's without canonical processing or echo!).
+ * slinput is reasonably fast (usually 40 instructions plus
+ * call overhead).
+ */
+ if (!(tp->t_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP
+ | IXOFF | IXON))
+ && !(tp->t_lflag & (ECHO | ECHONL | ICANON | IEXTEN | ISIG
+ | PENDIN))
+ && !(tp->t_state & (TS_CNTTB | TS_LNCH))
+ && linesw[tp->t_line].l_rint == ttyinput) {
+ tk_nin += incc;
+ tk_rawcc += incc;
+ tp->t_rawcc += incc;
+ com->delta_error_counts[CE_TTY_BUF_OVERFLOW]
+ += b_to_q((char *)buf, incc, &tp->t_rawq);
+ ttwakeup(tp);
+ if (tp->t_state & TS_TTSTOP
+ && (tp->t_iflag & IXANY
+ || tp->t_cc[VSTART] == tp->t_cc[VSTOP])) {
+ tp->t_state &= ~TS_TTSTOP;
+ tp->t_lflag &= ~FLUSHO;
+ ttstart(tp);
+ }
+ } else {
+ do {
+ u_char line_status;
+ int recv_data;
+
+ line_status = (u_char) buf[CE_INPUT_OFFSET];
+ recv_data = (u_char) *buf++;
+ if (line_status
+ & (LSR_BI | LSR_FE | LSR_OE | LSR_PE)) {
+ if (line_status & LSR_BI)
+ recv_data |= TTY_BI;
+ if (line_status & LSR_FE)
+ recv_data |= TTY_FE;
+ if (line_status & LSR_OE)
+ recv_data |= TTY_OE;
+ if (line_status & LSR_PE)
+ recv_data |= TTY_PE;
+ }
+ (*linesw[tp->t_line].l_rint)(recv_data, tp);
+ } while (--incc > 0);
+ }
+ if (com_events == 0)
+ break;
+ }
+ if (com_events >= LOTS_OF_EVENTS)
+ goto repeat;
+}
+
+static int
+comparam(tp, t)
+ struct tty *tp;
+ struct termios *t;
+{
+ u_int cfcr;
+ int cflag;
+ struct com_s *com;
+ int divisor;
+ int error;
+ Port_t iobase;
+ int s;
+ int unit;
+
+ /* check requested parameters */
+ divisor = ttspeedtab(t->c_ospeed, comspeedtab);
+ if (t->c_ispeed == 0)
+ t->c_ispeed = t->c_ospeed;
+ if (divisor < 0 || divisor > 0 && t->c_ispeed != t->c_ospeed)
+ return (EINVAL);
+
+ /* parameters are OK, convert them to the com struct and the device */
+ unit = DEV_TO_UNIT(tp->t_dev);
+ com = com_addr(unit);
+ iobase = com->iobase;
+ s = spltty();
+ if (divisor == 0)
+ commctl(com, MCR_DTR, DMBIC); /* hang up line */
+ else
+ commctl(com, MCR_DTR, DMBIS);
+ cflag = t->c_cflag;
+ switch (cflag & CSIZE) {
+ case CS5:
+ cfcr = CFCR_5BITS;
+ break;
+ case CS6:
+ cfcr = CFCR_6BITS;
+ break;
+ case CS7:
+ cfcr = CFCR_7BITS;
+ break;
+ default:
+ cfcr = CFCR_8BITS;
+ break;
+ }
+ if (cflag & PARENB) {
+ cfcr |= CFCR_PENAB;
+ if (!(cflag & PARODD))
+ cfcr |= CFCR_PEVEN;
+ }
+ if (cflag & CSTOPB)
+ cfcr |= CFCR_STOPB;
+
+ if (com->hasfifo) {
+ /*
+ * Use a fifo trigger level low enough so that the input
+ * latency from the fifo is less than about 16 msec and
+ * the total latency is less than about 30 msec. These
+ * latencies are reasonable for humans. Serial comms
+ * protocols shouldn't expect anything better since modem
+ * latencies are larger.
+ */
+ com->ftl = t->c_ospeed <= 4800
+ ? FIFO_TRIGGER_1 : FIFO_TRIGGER_14;
+ if (com->ftl > com->ftl_max)
+ com->ftl = com->ftl_max;
+ outb(iobase + com_fifo, FIFO_ENABLE | com->ftl);
+ }
+
+ /*
+ * Some UARTs lock up if the divisor latch registers are selected
+ * while the UART is doing output (they refuse to transmit anything
+ * more until given a hard reset). Fix this by stopping filling
+ * the device buffers and waiting for them to drain. Reading the
+ * line status port outside of siointr1() might lose some receiver
+ * error bits, but that is acceptable here.
+ */
+ disable_intr();
+retry:
+ com->state &= ~CS_TTGO;
+ enable_intr();
+ while ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY))
+ != (LSR_TSRE | LSR_TXRDY)) {
+ error = ttysleep(tp, TSA_OCOMPLETE(tp), TTIPRI | PCATCH,
+ "siotx", hz / 100);
+ if (error != 0 && error != EAGAIN) {
+ if (!(tp->t_state & TS_TTSTOP)) {
+ disable_intr();
+ com->state |= CS_TTGO;
+ enable_intr();
+ }
+ splx(s);
+ return (error);
+ }
+ }
+
+ disable_intr(); /* very important while com_data is hidden */
+
+ /*
+ * XXX - clearing CS_TTGO is not sufficient to stop further output,
+ * because siopoll() calls comstart() which usually sets it again
+ * because TS_TTSTOP is clear. Setting TS_TTSTOP would not be
+ * sufficient, for similar reasons.
+ */
+ if ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY))
+ != (LSR_TSRE | LSR_TXRDY))
+ goto retry;
+
+ if (divisor != 0) {
+ outb(iobase + com_cfcr, cfcr | CFCR_DLAB);
+ outb(iobase + com_dlbl, divisor & 0xFF);
+ outb(iobase + com_dlbh, (u_int) divisor >> 8);
+ }
+ outb(iobase + com_cfcr, com->cfcr_image = cfcr);
+ if (!(tp->t_state & TS_TTSTOP))
+ com->state |= CS_TTGO;
+ if (cflag & CRTS_IFLOW)
+ com->state |= CS_RTS_IFLOW; /* XXX - secondary changes? */
+ else
+ com->state &= ~CS_RTS_IFLOW;
+
+ /*
+ * Set up state to handle output flow control.
+ * XXX - worth handling MDMBUF (DCD) flow control at the lowest level?
+ * Now has 10+ msec latency, while CTS flow has 50- usec latency.
+ */
+ com->state &= ~CS_CTS_OFLOW;
+ com->state |= CS_ODEVREADY;
+ if (cflag & CCTS_OFLOW) {
+ com->state |= CS_CTS_OFLOW;
+ if (!(com->last_modem_status & MSR_CTS))
+ com->state &= ~CS_ODEVREADY;
+ }
+
+ /*
+ * Recover from fiddling with CS_TTGO. We used to call siointr1()
+ * unconditionally, but that defeated the careful discarding of
+ * stale input in sioopen().
+ */
+ if (com->state >= (CS_BUSY | CS_TTGO))
+ siointr1(com);
+
+ enable_intr();
+ splx(s);
+ return (0);
+}
+
+static void
+comstart(tp)
+ struct tty *tp;
+{
+ struct com_s *com;
+ int s;
+ int unit;
+
+ unit = DEV_TO_UNIT(tp->t_dev);
+ com = com_addr(unit);
+ s = spltty();
+ disable_intr();
+ if (tp->t_state & TS_TTSTOP)
+ com->state &= ~CS_TTGO;
+ else
+ com->state |= CS_TTGO;
+ if (tp->t_state & TS_RTS_IFLOW) {
+ if (com->mcr_image & MCR_RTS && com->state & CS_RTS_IFLOW)
+ outb(com->modem_ctl_port, com->mcr_image &= ~MCR_RTS);
+ } else {
+ /*
+ * XXX don't raise MCR_RTS if CTS_RTS_IFLOW is off. Set it
+ * appropriately in comparam() if RTS-flow is being changed.
+ * Check for races.
+ */
+ if (!(com->mcr_image & MCR_RTS) && com->iptr < com->ihighwater)
+ outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
+ }
+ enable_intr();
+ if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))
+ goto out;
+#if 0 /* XXX TK2.0 */
+ if (tp->t_state & (TS_SO_OCOMPLETE | TS_SO_OLOWAT) || tp->t_wsel)
+ ttwwakeup(tp);
+#else
+ if (tp->t_outq.c_cc <= tp->t_lowat) {
+ if (tp->t_state & TS_ASLEEP) {
+ tp->t_state &= ~TS_ASLEEP;
+ wakeup(TSA_OLOWAT(tp));
+ }
+ selwakeup(&tp->t_wsel);
+ }
+#endif
+ if (com->state & CS_BUSY) {
+ disable_intr();
+ siointr1(com);
+ enable_intr();
+ } else if (tp->t_outq.c_cc != 0) {
+ u_int ocount;
+
+ tp->t_state |= TS_BUSY;
+ ocount = q_to_b(&tp->t_outq, com->obuf, sizeof com->obuf);
+ disable_intr();
+ com->obufend = (com->optr = com->obuf) + ocount;
+ com->state |= CS_BUSY;
+ siointr1(com); /* fake interrupt to start output */
+ enable_intr();
+ }
+out:
+ splx(s);
+}
+
+void
+siostop(tp, rw)
+ struct tty *tp;
+ int rw;
+{
+ struct com_s *com;
+
+ com = com_addr(DEV_TO_UNIT(tp->t_dev));
+ if (rw & FWRITE)
+ comflush(com);
+ disable_intr();
+ if (rw & FREAD) {
+ com_events -= (com->iptr - com->ibuf);
+ com->iptr = com->ibuf;
+ }
+ if (tp->t_state & TS_TTSTOP)
+ com->state &= ~CS_TTGO;
+ else
+ com->state |= CS_TTGO;
+ enable_intr();
+}
+
+int
+sioselect(dev, rw, p)
+ dev_t dev;
+ int rw;
+ struct proc *p;
+{
+ if (minor(dev) & CONTROL_MASK)
+ return (ENODEV);
+ return (ttselect(dev & ~MINOR_MAGIC_MASK, rw, p));
+}
+
+static void
+commctl(com, bits, how)
+ struct com_s *com;
+ int bits;
+ int how;
+{
+ disable_intr();
+ switch (how) {
+ case DMSET:
+ outb(com->modem_ctl_port,
+ com->mcr_image = bits | (com->mcr_image & MCR_IENABLE));
+ break;
+ case DMBIS:
+ outb(com->modem_ctl_port, com->mcr_image |= bits);
+ break;
+ case DMBIC:
+ outb(com->modem_ctl_port, com->mcr_image &= ~bits);
+ break;
+ }
+ enable_intr();
+}
+
+static void
+comwakeup(chan)
+ void *chan;
+{
+ int unit;
+
+ timeout(comwakeup, (void *)NULL, hz / 100);
+
+ if (com_events != 0) {
+ int s;
+
+ s = splsofttty();
+ siopoll();
+ splx(s);
+ }
+
+ /* recover from lost output interrupts */
+ for (unit = 0; unit < NSIO; ++unit) {
+ struct com_s *com;
+
+ com = com_addr(unit);
+ if (com != NULL && com->state >= (CS_BUSY | CS_TTGO)) {
+ disable_intr();
+ siointr1(com);
+ enable_intr();
+ }
+ }
+}
+
+/*
+ * Following are all routines needed for SIO to act as console
+ */
+#include "i386/i386/cons.h"
+
+struct siocnstate {
+ u_char dlbl;
+ u_char dlbh;
+ u_char ier;
+ u_char cfcr;
+ u_char mcr;
+};
+
+static Port_t siocniobase;
+
+static void siocnclose __P((struct siocnstate *sp));
+static void siocnopen __P((struct siocnstate *sp));
+static void siocntxwait __P((void));
+
+static void
+siocntxwait()
+{
+ int timo;
+
+ /*
+ * Wait for any pending transmission to finish. Required to avoid
+ * the UART lockup bug when the speed is changed, and for normal
+ * transmits.
+ */
+ timo = 100000;
+ while ((inb(siocniobase + com_lsr) & (LSR_TSRE | LSR_TXRDY))
+ != (LSR_TSRE | LSR_TXRDY) && --timo != 0)
+ ;
+}
+
+static void
+siocnopen(sp)
+ struct siocnstate *sp;
+{
+ int divisor;
+ Port_t iobase;
+
+ /*
+ * Save all the device control registers except the fifo register
+ * and set our default ones (cs8 -parenb speed=comdefaultrate).
+ * We can't save the fifo register since it is read-only.
+ */
+ iobase = siocniobase;
+ sp->ier = inb(iobase + com_ier);
+ outb(iobase + com_ier, 0); /* spltty() doesn't stop siointr() */
+ siocntxwait();
+ sp->cfcr = inb(iobase + com_cfcr);
+ outb(iobase + com_cfcr, CFCR_DLAB);
+ sp->dlbl = inb(iobase + com_dlbl);
+ sp->dlbh = inb(iobase + com_dlbh);
+ divisor = ttspeedtab(comdefaultrate, comspeedtab);
+ outb(iobase + com_dlbl, divisor & 0xFF);
+ outb(iobase + com_dlbh, (u_int) divisor >> 8);
+ outb(iobase + com_cfcr, CFCR_8BITS);
+ sp->mcr = inb(iobase + com_mcr);
+ outb(iobase + com_mcr, MCR_DTR | MCR_RTS);
+}
+
+static void
+siocnclose(sp)
+ struct siocnstate *sp;
+{
+ Port_t iobase;
+
+ /*
+ * Restore the device control registers.
+ */
+ siocntxwait();
+ iobase = siocniobase;
+ outb(iobase + com_cfcr, CFCR_DLAB);
+ outb(iobase + com_dlbl, sp->dlbl);
+ outb(iobase + com_dlbh, sp->dlbh);
+ outb(iobase + com_cfcr, sp->cfcr);
+ /*
+ * XXX damp oscllations of MCR_DTR and MCR_RTS by not restoring them.
+ */
+ outb(iobase + com_mcr, sp->mcr | MCR_DTR | MCR_RTS);
+ outb(iobase + com_ier, sp->ier);
+}
+
+void
+siocnprobe(cp)
+ struct consdev *cp;
+{
+ int unit;
+
+ /* locate the major number */
+ /* XXX - should be elsewhere since KGDB uses it */
+ for (commajor = 0; commajor < nchrdev; commajor++)
+ if (cdevsw[commajor].d_open == sioopen)
+ break;
+
+ /* XXX: ick */
+ unit = DEV_TO_UNIT(CONUNIT);
+ siocniobase = CONADDR;
+
+ /* make sure hardware exists? XXX */
+
+ /* initialize required fields */
+ cp->cn_dev = makedev(commajor, unit);
+#ifdef COMCONSOLE
+ cp->cn_pri = CN_REMOTE; /* Force a serial port console */
+#else
+ cp->cn_pri = CN_NORMAL;
+#endif
+}
+
+void
+siocninit(cp)
+ struct consdev *cp;
+{
+ /*
+ * XXX can delete more comconsole stuff now that i/o routines are
+ * fairly reentrant.
+ */
+ comconsole = DEV_TO_UNIT(cp->cn_dev);
+}
+
+int
+siocngetc(dev)
+ dev_t dev;
+{
+ int c;
+ Port_t iobase;
+ int s;
+ struct siocnstate sp;
+
+ iobase = siocniobase;
+ s = spltty();
+ siocnopen(&sp);
+ while (!(inb(iobase + com_lsr) & LSR_RXRDY))
+ ;
+ c = inb(iobase + com_data);
+ siocnclose(&sp);
+ splx(s);
+ return (c);
+}
+
+void
+siocnputc(dev, c)
+ dev_t dev;
+ int c;
+{
+ int s;
+ struct siocnstate sp;
+
+ s = spltty();
+ siocnopen(&sp);
+ siocntxwait();
+ outb(siocniobase + com_data, c);
+ siocnclose(&sp);
+ splx(s);
+}
+
+#endif /* NSIO > 0 */
diff --git a/sys/isa/sioreg.h b/sys/isa/sioreg.h
new file mode 100644
index 0000000..4b0f1b6
--- /dev/null
+++ b/sys/isa/sioreg.h
@@ -0,0 +1,114 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 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.
+ *
+ * from: @(#)comreg.h 7.2 (Berkeley) 5/9/91
+ * $Id$
+ */
+
+
+/* 16 bit baud rate divisor (lower byte in dca_data, upper in dca_ier) */
+#define COMBRD(x) (1843200 / (16*(x)))
+
+/* interrupt enable register */
+#define IER_ERXRDY 0x1
+#define IER_ETXRDY 0x2
+#define IER_ERLS 0x4
+#define IER_EMSC 0x8
+
+/* interrupt identification register */
+#define IIR_IMASK 0xf
+#define IIR_RXTOUT 0xc
+#define IIR_RLS 0x6
+#define IIR_RXRDY 0x4
+#define IIR_TXRDY 0x2
+#define IIR_NOPEND 0x1
+#define IIR_MLSC 0x0
+#define IIR_FIFO_MASK 0xc0 /* set if FIFOs are enabled */
+
+/* fifo control register */
+#define FIFO_ENABLE 0x01
+#define FIFO_RCV_RST 0x02
+#define FIFO_XMT_RST 0x04
+#define FIFO_DMA_MODE 0x08
+#define FIFO_TRIGGER_1 0x00
+#define FIFO_TRIGGER_4 0x40
+#define FIFO_TRIGGER_8 0x80
+#define FIFO_TRIGGER_14 0xc0
+
+/* character format control register */
+#define CFCR_DLAB 0x80
+#define CFCR_SBREAK 0x40
+#define CFCR_PZERO 0x30
+#define CFCR_PONE 0x20
+#define CFCR_PEVEN 0x10
+#define CFCR_PODD 0x00
+#define CFCR_PENAB 0x08
+#define CFCR_STOPB 0x04
+#define CFCR_8BITS 0x03
+#define CFCR_7BITS 0x02
+#define CFCR_6BITS 0x01
+#define CFCR_5BITS 0x00
+
+/* modem control register */
+#define MCR_LOOPBACK 0x10
+#define MCR_IENABLE 0x08
+#define MCR_DRS 0x04
+#define MCR_RTS 0x02
+#define MCR_DTR 0x01
+
+/* line status register */
+#define LSR_RCV_FIFO 0x80
+#define LSR_TSRE 0x40
+#define LSR_TXRDY 0x20
+#define LSR_BI 0x10
+#define LSR_FE 0x08
+#define LSR_PE 0x04
+#define LSR_OE 0x02
+#define LSR_RXRDY 0x01
+#define LSR_RCV_MASK 0x1f
+
+/* modem status register */
+#define MSR_DCD 0x80
+#define MSR_RI 0x40
+#define MSR_DSR 0x20
+#define MSR_CTS 0x10
+#define MSR_DDCD 0x08
+#define MSR_TERI 0x04
+#define MSR_DDSR 0x02
+#define MSR_DCTS 0x01
+
+/*
+ * WARNING: Serial console is assumed to be at COM1 address
+ * and CONUNIT must be 0.
+ */
+#define CONADDR (0x3f8)
+#define CONUNIT (0)
diff --git a/sys/isa/syscons.c b/sys/isa/syscons.c
new file mode 100644
index 0000000..eae66d6
--- /dev/null
+++ b/sys/isa/syscons.c
@@ -0,0 +1,2707 @@
+/*-
+ * Copyright (c) 1992-1994 Søren Schmidt
+ * 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.
+ *
+ * $Id: syscons.c,v 1.51 1994/08/17 19:32:23 sos Exp $
+ */
+
+#include "sc.h"
+
+#if NSC > 0
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/ioctl.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/tty.h>
+#include <sys/uio.h>
+#include <sys/callout.h>
+#include <sys/kernel.h>
+#include <sys/syslog.h>
+#include <sys/errno.h>
+#include <sys/malloc.h>
+#include <machine/console.h>
+#include <machine/psl.h>
+#include <machine/frame.h>
+#include <machine/pc/display.h>
+#include <i386/isa/isa.h>
+#include <i386/isa/isa_device.h>
+#include <i386/isa/timerreg.h>
+#include <i386/isa/kbdtables.h>
+#include <i386/i386/cons.h>
+
+#if !defined(NCONS)
+#define NCONS 12
+#endif
+
+#if !defined(NO_HARDFONTS)
+#include <i386/isa/iso8859.font>
+#endif
+
+/* status flags */
+#define LOCK_KEY_MASK 0x0000F
+#define LED_MASK 0x00007
+#define UNKNOWN_MODE 0x00010
+#define KBD_RAW_MODE 0x00020
+#define SWITCH_WAIT_REL 0x00040
+#define SWITCH_WAIT_ACQ 0x00080
+
+/* video hardware memory addresses */
+#define VIDEOMEM 0x000A0000
+
+/* misc defines */
+#define MAX_ESC_PAR 5
+#define TEXT80x25 1
+#define TEXT80x50 2
+#define LOAD 1
+#define SAVE 0
+#define COL 80
+#define ROW 25
+#define BELL_DURATION 5
+#define BELL_PITCH 800
+#define TIMER_FREQ 1193182 /* should be in isa.h */
+#define CONSOLE_BUFSIZE 1024
+#define PCBURST 128
+#define FONT_8_LOADED 0x001
+#define FONT_14_LOADED 0x002
+#define FONT_16_LOADED 0x004
+
+/* defines related to hardware addresses */
+#define MONO_BASE 0x3B4 /* crt controller base mono */
+#define COLOR_BASE 0x3D4 /* crt controller base color */
+#define ATC IO_VGA+0x00 /* attribute controller */
+#define TSIDX IO_VGA+0x04 /* timing sequencer idx */
+#define TSREG IO_VGA+0x05 /* timing sequencer data */
+#define PIXMASK IO_VGA+0x06 /* pixel write mask */
+#define PALRADR IO_VGA+0x07 /* palette read address */
+#define PALWADR IO_VGA+0x08 /* palette write address */
+#define PALDATA IO_VGA+0x09 /* palette data register */
+#define GDCIDX IO_VGA+0x0E /* graph data controller idx */
+#define GDCREG IO_VGA+0x0F /* graph data controller data */
+
+/* special characters */
+#define cntlc 0x03
+#define cntld 0x04
+#define bs 0x08
+#define lf 0x0a
+#define cr 0x0d
+#define del 0x7f
+
+typedef struct term_stat {
+ int esc; /* processing escape sequence */
+ int num_param; /* # of parameters to ESC */
+ int last_param; /* last parameter # */
+ int param[MAX_ESC_PAR]; /* contains ESC parameters */
+ int cur_attr; /* current attributes */
+ int std_attr; /* normal attributes */
+ int rev_attr; /* reverse attributes */
+} term_stat;
+
+typedef struct scr_stat {
+ u_short *crt_base; /* address of screen memory */
+ u_short *scr_buf; /* buffer when off screen */
+ u_short *crtat; /* cursor address */
+ int xpos; /* current X position */
+ int ypos; /* current Y position */
+ int xsize; /* X size */
+ int ysize; /* Y size */
+ term_stat term; /* terminal emulation stuff */
+ char cursor_start; /* cursor start line # */
+ char cursor_end; /* cursor end line # */
+ u_char border; /* border color */
+ u_short bell_duration;
+ u_short bell_pitch;
+ u_short status; /* status (bitfield) */
+ u_short mode; /* mode */
+ pid_t pid; /* pid of controlling proc */
+ struct proc *proc; /* proc* of controlling proc */
+ struct vt_mode smode; /* switch mode */
+} scr_stat;
+
+typedef struct default_attr {
+ int std_attr; /* normal attributes */
+ int rev_attr; /* reverse attributes */
+} default_attr;
+
+static default_attr user_default = {
+ (FG_LIGHTGREY | BG_BLACK) << 8,
+ (FG_BLACK | BG_LIGHTGREY) << 8
+};
+
+static default_attr kernel_default = {
+ (FG_WHITE | BG_BLACK) << 8,
+ (FG_BLACK | BG_LIGHTGREY) << 8
+};
+
+static scr_stat console[NCONS];
+static scr_stat *cur_console = &console[0];
+static scr_stat *new_scp, *old_scp;
+static term_stat kernel_console;
+static default_attr *current_default;
+static int console_buffer_count;
+static char console_buffer[CONSOLE_BUFSIZE];
+static int switch_in_progress = 0;
+static u_short *crtat = 0;
+static u_int crtc_addr = MONO_BASE;
+static char crtc_vga = 0;
+static u_char shfts = 0, ctls = 0, alts = 0, agrs = 0, metas = 0;
+static u_char nlkcnt = 0, clkcnt = 0, slkcnt = 0, alkcnt = 0;
+static char *font_8 = NULL, *font_14 = NULL, *font_16 = NULL;
+static int fonts_loaded = 0;
+static char palette[3*256];
+static const u_int n_fkey_tab = sizeof(fkey_tab) / sizeof(*fkey_tab);
+static int cur_cursor_pos = -1;
+static char in_putc = 0;
+static char polling = 0;
+#if ASYNCH
+static u_char kbd_reply = 0;
+#endif
+static int delayed_next_scr;
+static char saved_console = -1; /* saved console number */
+static long scrn_blank_time = 0; /* screen saver timeout value */
+static int scrn_blanked = 0; /* screen saver active flag */
+static int scrn_saver = 0; /* screen saver routine */
+static long scrn_time_stamp;
+static u_char scr_map[256];
+
+/* function prototypes */
+int pcprobe(struct isa_device *dev);
+int pcattach(struct isa_device *dev);
+int pcopen(dev_t dev, int flag, int mode, struct proc *p);
+int pcclose(dev_t dev, int flag, int mode, struct proc *p);
+int pcread(dev_t dev, struct uio *uio, int flag);
+int pcwrite(dev_t dev, struct uio *uio, int flag);
+int pcparam(struct tty *tp, struct termios *t);
+int pcioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p);
+void pcxint(dev_t dev);
+void pcstart(struct tty *tp);
+void pccnprobe(struct consdev *cp);
+void pccninit(struct consdev *cp);
+void pccnputc(dev_t dev, char c);
+int pccngetc(dev_t dev);
+void scintr(int unit);
+int pcmmap(dev_t dev, int offset, int nprot);
+u_int sgetc(int noblock);
+int getchar(void);
+static void scinit(void);
+static void scput(u_char c);
+static u_int scgetc(int noblock);
+static struct tty *get_tty_ptr(dev_t dev);
+static scr_stat *get_scr_stat(dev_t dev);
+static int get_scr_num();
+static void cursor_shape(int start, int end);
+static void get_cursor_shape(int *start, int *end);
+static void cursor_pos(int force);
+static void clear_screen(scr_stat *scp);
+static int switch_scr(u_int next_scr);
+static void exchange_scr(void);
+static void move_crsr(scr_stat *scp, int x, int y);
+static void move_up(u_short *s, u_short *d, u_int len);
+static void move_down(u_short *s, u_short *d, u_int len);
+static void scan_esc(scr_stat *scp, u_char c);
+static void ansi_put(scr_stat *scp, u_char c);
+static u_char *get_fstr(u_int c, u_int *len);
+static void update_leds(int which);
+static void kbd_wait(void);
+static void kbd_cmd(u_char command);
+static void set_mode(scr_stat *scp);
+static void set_border(int color);
+static void copy_font(int direction, int segment, int size, char* font);
+static void save_palette(void);
+static void load_palette(void);
+static void change_winsize(struct tty *tp, int x, int y);
+
+/* available screen savers */
+static void none_saver(int test);
+static void blank_saver(int test);
+static void fade_saver(int test);
+static void star_saver(int test);
+static void snake_saver(int test);
+
+static const struct {
+ char *name;
+ void (*routine)();
+} screen_savers[] = {
+ { "none", none_saver }, /* 0 */
+ { "blank", blank_saver }, /* 1 */
+ { "fade", fade_saver }, /* 2 */
+ { "star", star_saver }, /* 3 */
+ { "snake", snake_saver }, /* 4 */
+};
+#define SCRN_SAVER(arg) (*screen_savers[scrn_saver].routine)(arg)
+#define NUM_SCRN_SAVERS (sizeof(screen_savers) / sizeof(screen_savers[0]))
+
+/* OS specific stuff */
+#if 0
+#define VIRTUAL_TTY(x) (pccons[x] = ttymalloc(pccons[x]))
+#define CONSOLE_TTY (pccons[NCONS] = ttymalloc(pccons[NCONS]))
+struct tty *pccons[NCONS+1];
+#else
+#define VIRTUAL_TTY(x) &pccons[x]
+#define CONSOLE_TTY &pccons[NCONS]
+struct tty pccons[NCONS+1];
+#endif
+#define timeout_t timeout_func_t
+#define MONO_BUF (KERNBASE+0xB0000)
+#define CGA_BUF (KERNBASE+0xB8000)
+#include "ddb.h"
+#if NDDB > 0
+#define DDB 1
+#endif
+u_short *Crtat = (u_short *)MONO_BUF;
+void consinit(void) {scinit();}
+
+struct isa_driver scdriver = {
+ pcprobe, pcattach, "sc",
+};
+
+
+int
+pcprobe(struct isa_device *dev)
+{
+ int i, retries = 5;
+ unsigned char val;
+
+ /* Enable interrupts and keyboard controller */
+ kbd_wait();
+ outb(KB_STAT, KB_WRITE);
+ kbd_wait();
+ outb(KB_DATA, KB_MODE);
+
+ /* flush any noise in the buffer */
+ while (inb(KB_STAT) & KB_BUF_FULL) {
+ DELAY(10);
+ (void) inb(KB_DATA);
+ }
+
+ /* Reset keyboard hardware */
+ while (retries--) {
+ kbd_wait();
+ outb(KB_DATA, KB_RESET);
+ for (i=0; i<100000; i++) {
+ DELAY(10);
+ val = inb(KB_DATA);
+ if (val == KB_ACK || val == KB_ECHO)
+ goto gotres;
+ if (val == KB_RESEND)
+ break;
+ }
+ }
+gotres:
+ if (!retries)
+ printf("scprobe: keyboard won't accept RESET command\n");
+ else {
+gotack:
+ DELAY(10);
+ while ((inb(KB_STAT) & KB_BUF_FULL) == 0) DELAY(10);
+ DELAY(10);
+ val = inb(KB_DATA);
+ if (val == KB_ACK)
+ goto gotack;
+ if (val != KB_RESET_DONE)
+ printf("scprobe: keyboard RESET failed %02x\n", val);
+ }
+ return (IO_KBDSIZE);
+}
+
+
+int
+pcattach(struct isa_device *dev)
+{
+ scr_stat *scp;
+ int start = -1, end = -1, i;
+
+ printf("sc%d: ", dev->id_unit);
+ if (crtc_vga)
+ if (crtc_addr == MONO_BASE)
+ printf("VGA mono");
+ else
+ printf("VGA color");
+ else
+ if (crtc_addr == MONO_BASE)
+ printf("MDA/hercules");
+ else
+ printf("CGA/EGA");
+
+ if (NCONS > 1)
+ printf(" <%d virtual consoles>\n", NCONS);
+ else
+ printf("\n");
+#if defined(FAT_CURSOR)
+ start = 0;
+ end = 18;
+ if (crtc_vga) {
+#else
+ if (crtc_vga) {
+ get_cursor_shape(&start, &end);
+#endif
+#if !defined(NO_HARDFONTS)
+ font_8 = font_8x8;
+ font_14 = font_8x14;
+ font_16 = font_8x16;
+ fonts_loaded = FONT_8_LOADED|FONT_14_LOADED|FONT_16_LOADED;
+ copy_font(LOAD, 1, 8, font_8);
+ copy_font(LOAD, 2, 14, font_14);
+ copy_font(LOAD, 0, 16, font_16);
+#else
+ font_8 = (char *)malloc(8*256, M_DEVBUF, M_NOWAIT);
+ font_14 = (char *)malloc(14*256, M_DEVBUF, M_NOWAIT);
+ font_16 = (char *)malloc(16*256, M_DEVBUF, M_NOWAIT);
+ copy_font(SAVE, 0, 16, font_16);
+ fonts_loaded = FONT_16_LOADED;
+#endif
+ save_palette();
+ }
+ current_default = &user_default;
+ for (i = 0; i < NCONS; i++) {
+ scp = &console[i];
+ scp->scr_buf = (u_short *)malloc(COL * ROW * 2,
+ M_DEVBUF, M_NOWAIT);
+ scp->mode = TEXT80x25;
+ scp->term.esc = 0;
+ scp->term.std_attr = current_default->std_attr;
+ scp->term.rev_attr = current_default->rev_attr;
+ scp->term.cur_attr = scp->term.std_attr;
+ scp->border = BG_BLACK;
+ scp->cursor_start = start;
+ scp->cursor_end = end;
+ scp->xsize = COL;
+ scp->ysize = ROW;
+ scp->bell_pitch = BELL_PITCH;
+ scp->bell_duration = BELL_DURATION;
+ scp->status = NLKED;
+ scp->pid = 0;
+ scp->proc = NULL;
+ scp->smode.mode = VT_AUTO;
+ if (i > 0) {
+ scp->crt_base = scp->crtat = scp->scr_buf;
+ fillw(scp->term.cur_attr|scr_map[0x20],
+ scp->scr_buf, COL*ROW);
+ }
+ }
+ /* get cursor going */
+#if defined(FAT_CURSOR)
+ cursor_shape(console[0].cursor_start,
+ console[0].cursor_end);
+#endif
+ cursor_pos(1);
+ update_leds(console[0].status);
+ return 0;
+}
+
+
+static struct tty
+*get_tty_ptr(dev_t dev)
+{
+ int unit = minor(dev);
+
+ if (unit > NCONS)
+ return(NULL);
+ if (unit == NCONS)
+ return(CONSOLE_TTY);
+ return(VIRTUAL_TTY(unit));
+}
+
+
+static scr_stat
+*get_scr_stat(dev_t dev)
+{
+ int unit = minor(dev);
+
+ if (unit > NCONS)
+ return(NULL);
+ if (unit == NCONS)
+ return(&console[0]);
+ return(&console[unit]);
+}
+
+
+static int
+get_scr_num()
+{
+ int i = 0;
+
+ while ((i < NCONS) && (cur_console != &console[i])) i++;
+ return i < NCONS ? i : 0;
+}
+
+
+int
+pcopen(dev_t dev, int flag, int mode, struct proc *p)
+{
+ struct tty *tp = get_tty_ptr(dev);
+
+ if (!tp)
+ return(ENXIO);
+
+ tp->t_oproc = pcstart;
+ tp->t_param = pcparam;
+ tp->t_dev = dev;
+ if (!(tp->t_state & TS_ISOPEN)) {
+ 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;
+ tp->t_cflag |= CLOCAL;
+ return((*linesw[tp->t_line].l_open)(dev, tp));
+}
+
+
+int
+pcclose(dev_t dev, int flag, int mode, struct proc *p)
+{
+ struct tty *tp = get_tty_ptr(dev);
+ struct scr_stat *scp;
+
+ if (!tp)
+ return(ENXIO);
+ if (minor(dev) < NCONS) {
+ scp = get_scr_stat(tp->t_dev);
+ if (scp->status & SWITCH_WAIT_ACQ)
+ wakeup((caddr_t)&scp->smode);
+ scp->pid = 0;
+ scp->proc = NULL;
+ scp->smode.mode = VT_AUTO;
+ }
+ (*linesw[tp->t_line].l_close)(tp, flag);
+ ttyclose(tp);
+ return(0);
+}
+
+
+int
+pcread(dev_t dev, struct uio *uio, int flag)
+{
+ struct tty *tp = get_tty_ptr(dev);
+
+ if (!tp)
+ return(ENXIO);
+ return((*linesw[tp->t_line].l_read)(tp, uio, flag));
+}
+
+
+int
+pcwrite(dev_t dev, struct uio *uio, int flag)
+{
+ struct tty *tp = get_tty_ptr(dev);
+
+ if (!tp)
+ return(ENXIO);
+ return((*linesw[tp->t_line].l_write)(tp, uio, flag));
+}
+
+
+void
+scintr(int unit)
+{
+ static struct tty *cur_tty;
+ int c, len;
+ u_char *cp;
+
+ /* make screensaver happy */
+ scrn_time_stamp = time.tv_sec;
+ if (scrn_blanked)
+ SCRN_SAVER(0);
+
+ c = scgetc(1);
+
+ cur_tty = VIRTUAL_TTY(get_scr_num());
+ if (!(cur_tty->t_state & TS_ISOPEN))
+ cur_tty = CONSOLE_TTY;
+
+ if (!(cur_tty->t_state & TS_ISOPEN) || polling)
+ return;
+
+ switch (c & 0xff00) {
+ case 0x0000: /* normal key */
+ (*linesw[cur_tty->t_line].l_rint)(c & 0xFF, cur_tty);
+ break;
+ case NOKEY: /* nothing there */
+ break;
+ case FKEY: /* function key, return string */
+ if (cp = get_fstr((u_int)c, (u_int *)&len)) {
+ while (len-- > 0)
+ (*linesw[cur_tty->t_line].l_rint)
+ (*cp++ & 0xFF, cur_tty);
+ }
+ break;
+ case MKEY: /* meta is active, prepend ESC */
+ (*linesw[cur_tty->t_line].l_rint)(0x1b, cur_tty);
+ (*linesw[cur_tty->t_line].l_rint)(c & 0xFF, cur_tty);
+ break;
+ }
+}
+
+
+int
+pcparam(struct tty *tp, struct termios *t)
+{
+ int cflag = t->c_cflag;
+
+ /* and copy to tty */
+ tp->t_ispeed = t->c_ispeed;
+ tp->t_ospeed = t->c_ospeed;
+ tp->t_cflag = cflag;
+ return 0;
+}
+
+
+int
+pcioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
+{
+ int i, error;
+ struct tty *tp;
+ struct trapframe *fp;
+ scr_stat *scp;
+
+ tp = get_tty_ptr(dev);
+ if (!tp)
+ return ENXIO;
+ scp = get_scr_stat(tp->t_dev);
+
+ switch (cmd) { /* process console hardware related ioctl's */
+
+ case CONS_BLANKTIME: /* set screen saver timeout (0 = no saver) */
+ scrn_blank_time = *(int*)data;
+ return 0;
+ case CONS_SSAVER: /* set screen saver */
+ {
+ register ssaver_t *sav = (ssaver_t *)data;
+ if (sav->num < 0 || sav->num >= NUM_SCRN_SAVERS)
+ return EIO;
+ SCRN_SAVER(0);
+ scrn_saver = sav->num;
+ scrn_blank_time = sav->time;
+ return 0;
+ }
+ case CONS_GSAVER: /* get screen saver info */
+ {
+ register ssaver_t *sav = (ssaver_t *)data;
+ if (sav->num < 0)
+ sav->num = scrn_saver;
+ else if (sav->num >= NUM_SCRN_SAVERS)
+ return EIO;
+ sav->time = scrn_blank_time;
+ strcpy(sav->name, screen_savers[sav->num].name);
+ return 0;
+ }
+ case CONS_80x25TEXT: /* set 80x25 text mode */
+ if (!crtc_vga)
+ return ENXIO;
+ scp->mode = TEXT80x25;
+ scp->ysize = 25;
+ free(scp->scr_buf, M_DEVBUF);
+ scp->scr_buf = (u_short *)malloc(scp->xsize*scp->ysize*2,
+ M_DEVBUF, M_NOWAIT);
+ if (scp != cur_console)
+ scp->crt_base = scp->scr_buf;
+ set_mode(scp);
+ clear_screen(scp);
+ change_winsize(tp, scp->xsize, scp->ysize);
+ return 0;
+
+ case CONS_80x50TEXT: /* set 80x50 text mode */
+ if (!crtc_vga)
+ return ENXIO;
+ /* is there a 8x8 font loaded ? */
+ if (fonts_loaded & FONT_8_LOADED) {
+ scp->mode = TEXT80x50;
+ scp->ysize = 50;
+ free(scp->scr_buf, M_DEVBUF);
+ scp->scr_buf =
+ (u_short *)malloc(scp->xsize * scp->ysize * 2,
+ M_DEVBUF, M_NOWAIT);
+ if (scp != cur_console)
+ scp->crt_base = scp->scr_buf;
+ set_mode(scp);
+ clear_screen(scp);
+ change_winsize(tp, scp->xsize, scp->ysize);
+ return 0;
+ }
+ else
+ return EINVAL;
+
+ case CONS_GETVERS: /* get version number */
+ *(int*)data = 0x103; /* version 1.3 */
+ return 0;
+
+ case CONS_GETINFO: /* get current (virtual) console info */
+ {
+ vid_info_t *ptr = (vid_info_t*)data;
+ if (ptr->size == sizeof(struct vid_info)) {
+ ptr->m_num = get_scr_num();
+ ptr->mv_col = scp->xpos;
+ ptr->mv_row = scp->ypos;
+ ptr->mv_csz = scp->xsize;
+ ptr->mv_rsz = scp->ysize;
+ ptr->mv_norm.fore = (scp->term.std_attr & 0x0f00)>>8;
+ ptr->mv_norm.back = (scp->term.std_attr & 0xf000)>>12;
+ ptr->mv_rev.fore = (scp->term.rev_attr & 0x0f00)>>8;
+ ptr->mv_rev.back = (scp->term.rev_attr & 0xf000)>>12;
+ ptr->mv_grfc.fore = 0; /* not supported */
+ ptr->mv_grfc.back = 0; /* not supported */
+ ptr->mv_ovscan = scp->border;
+ ptr->mk_keylock = scp->status & LOCK_KEY_MASK;
+ return 0;
+ }
+ return EINVAL;
+ }
+
+ case VT_SETMODE: /* set screen switcher mode */
+ bcopy(data, &scp->smode, sizeof(struct vt_mode));
+ if (scp->smode.mode == VT_PROCESS) {
+ scp->proc = p;
+ scp->pid = scp->proc->p_pid;
+ }
+ return 0;
+
+ case VT_GETMODE: /* get screen switcher mode */
+ bcopy(&scp->smode, data, sizeof(struct vt_mode));
+ return 0;
+
+ case VT_RELDISP: /* screen switcher ioctl */
+ switch(*data) {
+ case VT_FALSE: /* user refuses to release screen, abort */
+ if (scp == old_scp && (scp->status & SWITCH_WAIT_REL)) {
+ old_scp->status &= ~SWITCH_WAIT_REL;
+ switch_in_progress = 0;
+ return 0;
+ }
+ return EINVAL;
+
+ case VT_TRUE: /* user has released screen, go on */
+ if (scp == old_scp && (scp->status & SWITCH_WAIT_REL)) {
+ scp->status &= ~SWITCH_WAIT_REL;
+ exchange_scr();
+ if (new_scp->smode.mode == VT_PROCESS) {
+ new_scp->status |= SWITCH_WAIT_ACQ;
+ psignal(new_scp->proc,
+ new_scp->smode.acqsig);
+ }
+ else
+ switch_in_progress = 0;
+ return 0;
+ }
+ return EINVAL;
+
+ case VT_ACKACQ: /* acquire acknowledged, switch completed */
+ if (scp == new_scp && (scp->status & SWITCH_WAIT_ACQ)) {
+ scp->status &= ~SWITCH_WAIT_ACQ;
+ switch_in_progress = 0;
+ return 0;
+ }
+ return EINVAL;
+
+ default:
+ return EINVAL;
+ }
+ /* NOT REACHED */
+
+ case VT_OPENQRY: /* return free virtual console */
+ for (i = 0; i < NCONS; i++) {
+ tp = VIRTUAL_TTY(i);
+ if (!(tp->t_state & TS_ISOPEN)) {
+ *data = i + 1;
+ return 0;
+ }
+ }
+ return EINVAL;
+
+ case VT_ACTIVATE: /* switch to screen *data */
+ return switch_scr((*data) - 1);
+
+ case VT_WAITACTIVE: /* wait for switch to occur */
+ if (*data > NCONS)
+ return EINVAL;
+ if (minor(dev) == (*data) - 1)
+ return 0;
+ if (*data == 0) {
+ if (scp == cur_console)
+ return 0;
+ while ((error=tsleep((caddr_t)&scp->smode,
+ PZERO|PCATCH, "waitvt", 0)) == ERESTART) ;
+ }
+ else
+ while ((error=tsleep(
+ (caddr_t)&console[*(data-1)].smode,
+ PZERO|PCATCH, "waitvt", 0)) == ERESTART) ;
+ return error;
+
+ case VT_GETACTIVE:
+ *data = get_scr_num()+1;
+ return 0;
+
+ case KDENABIO: /* allow io operations */
+ fp = (struct trapframe *)p->p_md.md_regs;
+ fp->tf_eflags |= PSL_IOPL;
+ return 0;
+
+ case KDDISABIO: /* disallow io operations (default) */
+ fp = (struct trapframe *)p->p_md.md_regs;
+ fp->tf_eflags &= ~PSL_IOPL;
+ return 0;
+
+ case KDSETMODE: /* set current mode of this (virtual) console */
+ switch (*data) {
+ case KD_TEXT: /* switch to TEXT (known) mode */
+ /* restore fonts & palette ! */
+ if (crtc_vga) {
+ copy_font(LOAD, 0, 16, font_16);
+ copy_font(LOAD, 1, 8, font_8);
+ copy_font(LOAD, 2, 14, font_14);
+ load_palette();
+ }
+ /* FALL THROUGH */
+
+ case KD_TEXT1: /* switch to TEXT (known) mode */
+ /* no restore fonts & palette */
+ scp->status &= ~UNKNOWN_MODE;
+ set_mode(scp);
+ clear_screen(scp);
+ return 0;
+
+ case KD_GRAPHICS:/* switch to GRAPHICS (unknown) mode */
+ scp->status |= UNKNOWN_MODE;
+ return 0;
+ default:
+ return EINVAL;
+ }
+ /* NOT REACHED */
+
+ case KDGETMODE: /* get current mode of this (virtual) console */
+ *data = (scp->status & UNKNOWN_MODE) ? KD_GRAPHICS : KD_TEXT;
+ return 0;
+
+ case KDSBORDER: /* set border color of this (virtual) console */
+ if (!crtc_vga)
+ return ENXIO;
+ scp->border = *data;
+ if (scp == cur_console)
+ set_border(scp->border);
+ return 0;
+
+ case KDSKBSTATE: /* set keyboard state (locks) */
+ if (*data >= 0 && *data <= LOCK_KEY_MASK) {
+ scp->status &= ~LOCK_KEY_MASK;
+ scp->status |= *data;
+ if (scp == cur_console)
+ update_leds(scp->status);
+ return 0;
+ }
+ return EINVAL;
+
+ case KDGKBSTATE: /* get keyboard state (locks) */
+ *data = scp->status & LOCK_KEY_MASK;
+ return 0;
+
+ case KDSETRAD: /* set keyboard repeat & delay rates */
+ if (*data & 0x80)
+ return EINVAL;
+ i = spltty();
+ kbd_cmd(KB_SETRAD);
+ kbd_cmd(*data);
+ splx(i);
+ return 0;
+
+ case KDSKBMODE: /* set keyboard mode */
+ switch (*data) {
+ case K_RAW: /* switch to RAW scancode mode */
+ scp->status |= KBD_RAW_MODE;
+ return 0;
+
+ case K_XLATE: /* switch to XLT ascii mode */
+ if (scp == cur_console && scp->status == KBD_RAW_MODE)
+ shfts = ctls = alts = agrs = metas = 0;
+ scp->status &= ~KBD_RAW_MODE;
+ return 0;
+ default:
+ return EINVAL;
+ }
+ /* NOT REACHED */
+
+ case KDGKBMODE: /* get keyboard mode */
+ *data = (scp->status & KBD_RAW_MODE) ? K_RAW : K_XLATE;
+ return 0;
+
+ case KDMKTONE: /* sound the bell */
+ if (scp == cur_console)
+ sysbeep(scp->bell_pitch, scp->bell_duration);
+ return 0;
+
+ case KIOCSOUND: /* make tone (*data) hz */
+ if (scp == cur_console) {
+ if (*(int*)data) {
+ int pitch = TIMER_FREQ/(*(int*)data);
+ /* set command for counter 2, 2 byte write */
+ if (acquire_timer2(TIMER_16BIT|TIMER_SQWAVE)) {
+ return EBUSY;
+ }
+ /* set pitch */
+ outb(TIMER_CNTR2, pitch);
+ outb(TIMER_CNTR2, (pitch>>8));
+ /* enable counter 2 output to speaker */
+ outb(IO_PPI, inb(IO_PPI) | 3);
+ }
+ else {
+ /* disable counter 2 output to speaker */
+ outb(IO_PPI, inb(IO_PPI) & 0xFC);
+ release_timer2();
+ }
+ }
+ return 0;
+
+ case KDGKBTYPE: /* get keyboard type */
+ *data = 0; /* type not known (yet) */
+ return 0;
+
+ case KDSETLED: /* set keyboard LED status */
+ if (*data >= 0 && *data <= LED_MASK) {
+ scp->status &= ~LED_MASK;
+ scp->status |= *data;
+ if (scp == cur_console)
+ update_leds(scp->status);
+ return 0;
+ }
+ return EINVAL;
+
+ case KDGETLED: /* get keyboard LED status */
+ *data = scp->status & LED_MASK;
+ return 0;
+
+ case GETFKEY: /* get functionkey string */
+ if (*(u_short*)data < n_fkey_tab) {
+ fkeyarg_t *ptr = (fkeyarg_t*)data;
+ bcopy(&fkey_tab[ptr->keynum].str,
+ ptr->keydef,
+ fkey_tab[ptr->keynum].len);
+ ptr->flen = fkey_tab[ptr->keynum].len;
+ return 0;
+ }
+ else
+ return EINVAL;
+
+ case SETFKEY: /* set functionkey string */
+ if (*(u_short*)data < n_fkey_tab) {
+ fkeyarg_t *ptr = (fkeyarg_t*)data;
+ bcopy(ptr->keydef,
+ &fkey_tab[ptr->keynum].str,
+ min(ptr->flen, MAXFK));
+ fkey_tab[ptr->keynum].len = min(ptr->flen, MAXFK);
+ return 0;
+ }
+ else
+ return EINVAL;
+
+ case GIO_SCRNMAP: /* get output translation table */
+ bcopy(&scr_map, data, sizeof(scr_map));
+ return 0;
+
+ case PIO_SCRNMAP: /* set output translation table */
+ bcopy(data, &scr_map, sizeof(scr_map));
+ return 0;
+
+ case GIO_KEYMAP: /* get keyboard translation table */
+ bcopy(&key_map, data, sizeof(key_map));
+ return 0;
+
+ case PIO_KEYMAP: /* set keyboard translation table */
+ bcopy(data, &key_map, sizeof(key_map));
+ return 0;
+
+ case PIO_FONT8x8: /* set 8x8 dot font */
+ if (!crtc_vga)
+ return ENXIO;
+ bcopy(data, font_8, 8*256);
+ fonts_loaded |= FONT_8_LOADED;
+ copy_font(LOAD, 1, 8, font_8);
+ return 0;
+
+ case GIO_FONT8x8: /* get 8x8 dot font */
+ if (!crtc_vga)
+ return ENXIO;
+ if (fonts_loaded & FONT_8_LOADED) {
+ bcopy(font_8, data, 8*256);
+ return 0;
+ }
+ else
+ return ENXIO;
+
+ case PIO_FONT8x14: /* set 8x14 dot font */
+ if (!crtc_vga)
+ return ENXIO;
+ bcopy(data, font_14, 14*256);
+ fonts_loaded |= FONT_14_LOADED;
+ copy_font(LOAD, 2, 14, font_14);
+ return 0;
+
+ case GIO_FONT8x14: /* get 8x14 dot font */
+ if (!crtc_vga)
+ return ENXIO;
+ if (fonts_loaded & FONT_14_LOADED) {
+ bcopy(font_14, data, 14*256);
+ return 0;
+ }
+ else
+ return ENXIO;
+
+ case PIO_FONT8x16: /* set 8x16 dot font */
+ if (!crtc_vga)
+ return ENXIO;
+ bcopy(data, font_16, 16*256);
+ fonts_loaded |= FONT_16_LOADED;
+ copy_font(LOAD, 0, 16, font_16);
+ return 0;
+
+ case GIO_FONT8x16: /* get 8x16 dot font */
+ if (!crtc_vga)
+ return ENXIO;
+ if (fonts_loaded & FONT_16_LOADED) {
+ bcopy(font_16, data, 16*256);
+ return 0;
+ }
+ else
+ return ENXIO;
+
+ case CONSOLE_X_MODE_ON: /* just to be compatible */
+ if (saved_console < 0) {
+ saved_console = get_scr_num();
+ switch_scr(minor(dev));
+ fp = (struct trapframe *)p->p_md.md_regs;
+ fp->tf_eflags |= PSL_IOPL;
+ scp->status |= UNKNOWN_MODE;
+ scp->status |= KBD_RAW_MODE;
+ return 0;
+ }
+ return EAGAIN;
+
+ case CONSOLE_X_MODE_OFF:/* just to be compatible */
+ fp = (struct trapframe *)p->p_md.md_regs;
+ fp->tf_eflags &= ~PSL_IOPL;
+ if (crtc_vga) {
+ copy_font(LOAD, 0, 16, font_16);
+ copy_font(LOAD, 1, 8, font_8);
+ copy_font(LOAD, 2, 14, font_14);
+ load_palette();
+ }
+ scp->status &= ~UNKNOWN_MODE;
+ set_mode(scp);
+ clear_screen(scp);
+ scp->status &= ~KBD_RAW_MODE;
+ switch_scr(saved_console);
+ saved_console = -1;
+ return 0;
+
+ case CONSOLE_X_BELL: /* more compatibility */
+ /*
+ * 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(TIMER_FREQ/((int*)data)[0],
+ ((int*)data)[1]*hz/1000);
+ else
+ sysbeep(scp->bell_pitch, scp->bell_duration);
+ return 0;
+
+ default:
+ break;
+ }
+
+ error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
+ if (error >= 0)
+ return(error);
+ error = ttioctl(tp, cmd, data, flag);
+ if (error >= 0)
+ return(error);
+ return(ENOTTY);
+}
+
+
+void
+pcxint(dev_t dev)
+{
+ struct tty *tp = get_tty_ptr(dev);
+
+ if (!tp)
+ return;
+ tp->t_state &= ~TS_BUSY;
+ if (tp->t_line)
+ (*linesw[tp->t_line].l_start)(tp);
+ else
+ pcstart(tp);
+}
+
+
+void
+pcstart(struct tty *tp)
+{
+ struct clist *rbp;
+ int i, s, len;
+ u_char buf[PCBURST];
+ scr_stat *scp = get_scr_stat(tp->t_dev);
+
+ if (scp->status & SLKED)
+ return;
+ s = spltty();
+ if (!(tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))) {
+ tp->t_state |= TS_BUSY;
+ splx(s);
+ rbp = &tp->t_outq;
+ while (rbp->c_cc) {
+ len = q_to_b(rbp, buf, PCBURST);
+ for (i=0; i<len; i++)
+ if (buf[i]) ansi_put(scp, buf[i]);
+ }
+ s = spltty();
+ tp->t_state &= ~TS_BUSY;
+#if 0
+ if (rbp->c_cc) {
+ tp->t_state |= TS_TIMEOUT;
+ timeout((timeout_t)ttrstrt, (caddr_t)tp, 1);
+ }
+#endif
+ if (rbp->c_cc <= tp->t_lowat) {
+ if (tp->t_state & TS_ASLEEP) {
+ tp->t_state &= ~TS_ASLEEP;
+ wakeup((caddr_t)rbp);
+ }
+ selwakeup(&tp->t_wsel);
+ }
+ }
+ splx(s);
+}
+
+
+void
+pccnprobe(struct consdev *cp)
+{
+ int maj;
+
+ /* locate the major number */
+ for (maj = 0; maj < nchrdev; maj++)
+ if ((void*)cdevsw[maj].d_open == (void*)pcopen)
+ break;
+
+ /* initialize required fields */
+ cp->cn_dev = makedev(maj, NCONS);
+ cp->cn_pri = CN_INTERNAL;
+}
+
+
+void
+pccninit(struct consdev *cp)
+{
+ scinit();
+}
+
+
+void
+pccnputc(dev_t dev, char c)
+{
+ if (c == '\n')
+ scput('\r');
+ scput(c);
+ if (cur_console == &console[0]) {
+ int pos = cur_console->crtat - cur_console->crt_base;
+ if (pos != cur_cursor_pos) {
+ cur_cursor_pos = pos;
+ outb(crtc_addr,14);
+ outb(crtc_addr+1,pos >> 8);
+ outb(crtc_addr,15);
+ outb(crtc_addr+1,pos&0xff);
+ }
+ }
+}
+
+
+int
+pccngetc(dev_t dev)
+{
+ int s = spltty(); /* block scintr while we poll */
+ int c = scgetc(0);
+ splx(s);
+ if (c == '\r') c = '\n';
+ return(c);
+}
+
+
+static void
+none_saver(int test)
+{
+}
+
+
+static void
+fade_saver(int test)
+{
+ static int count = 0;
+ int i;
+
+ if (test) {
+ scrn_blanked = 1;
+ if (count < 64) {
+ outb(PIXMASK, 0xFF); /* no pixelmask */
+ outb(PALWADR, 0x00);
+ outb(PALDATA, 0);
+ outb(PALDATA, 0);
+ outb(PALDATA, 0);
+ for (i = 3; i < 768; i++) {
+ if (palette[i] - count > 15)
+ outb(PALDATA, palette[i]-count);
+ else
+ outb(PALDATA, 15);
+ }
+ inb(crtc_addr+6); /* reset flip/flop */
+ outb(ATC, 0x20); /* enable palette */
+ count++;
+ }
+ }
+ else {
+ count = scrn_blanked = 0;
+ load_palette();
+ }
+}
+
+
+static void
+blank_saver(int test)
+{
+ u_char val;
+ if (test) {
+ scrn_blanked = 1;
+ outb(TSIDX, 0x01); val = inb(TSREG);
+ outb(TSIDX, 0x01); outb(TSREG, val | 0x20);
+ }
+ else {
+ scrn_blanked = 0;
+ outb(TSIDX, 0x01); val = inb(TSREG);
+ outb(TSIDX, 0x01); outb(TSREG, val & 0xDF);
+ }
+}
+
+#define NUM_STARS 50
+
+/*
+ * Alternate saver that got its inspiration from a well known utility
+ * package for an inferior^H^H^H^H^H^Hfamous OS.
+ */
+static void
+star_saver(int test)
+{
+ scr_stat *scp = cur_console;
+ int cell, i;
+ char pattern[] = {"...........++++*** "};
+ char colors[] = {FG_DARKGREY, FG_LIGHTGREY,
+ FG_WHITE, FG_LIGHTCYAN};
+ static u_short stars[NUM_STARS][2];
+
+ if (test) {
+ if (!scrn_blanked) {
+ bcopy(Crtat, scp->scr_buf,
+ scp->xsize * scp->ysize * 2);
+ fillw((FG_LIGHTGREY|BG_BLACK)<<8 | scr_map[0x20], Crtat,
+ scp->xsize * scp->ysize);
+ set_border(0);
+ i = scp->ysize * scp->xsize + 5;
+ outb(crtc_addr, 14);
+ outb(crtc_addr+1, i >> 8);
+ outb(crtc_addr, 15);
+ outb(crtc_addr+1, i & 0xff);
+ scrn_blanked = 1;
+ for(i=0; i<NUM_STARS; i++) {
+ stars[i][0] =
+ random() % (scp->xsize*scp->ysize);
+ stars[i][1] = 0;
+ }
+ }
+ cell = random() % NUM_STARS;
+ *((u_short*)(Crtat + stars[cell][0])) =
+ scr_map[pattern[stars[cell][1]]] |
+ colors[random()%sizeof(colors)] << 8;
+ if ((stars[cell][1]+=(random()%4)) >= sizeof(pattern)-1) {
+ stars[cell][0] = random() % (scp->xsize*scp->ysize);
+ stars[cell][1] = 0;
+ }
+ }
+ else {
+ if (scrn_blanked) {
+ bcopy(scp->scr_buf, Crtat, scp->xsize*scp->ysize*2);
+ cur_cursor_pos = -1;
+ set_border(scp->border);
+ scrn_blanked = 0;
+ }
+ }
+}
+
+
+static void
+snake_saver(int test)
+{
+ const char saves[] = {"FreeBSD-2.0"};
+ static u_char *savs[sizeof(saves)-1];
+ static int dirx, diry;
+ int f;
+ scr_stat *scp = cur_console;
+
+ if (test) {
+ if (!scrn_blanked) {
+ bcopy(Crtat, scp->scr_buf,
+ scp->xsize * scp->ysize * 2);
+ fillw((FG_LIGHTGREY|BG_BLACK)<<8 | scr_map[0x20],
+ Crtat, scp->xsize * scp->ysize);
+ set_border(0);
+ dirx = (scp->xpos ? 1 : -1);
+ diry = (scp->ypos ?
+ scp->xsize : -scp->xsize);
+ for (f=0; f< sizeof(saves)-1; f++)
+ savs[f] = (u_char *)Crtat + 2 *
+ (scp->xpos+scp->ypos*scp->xsize);
+ *(savs[0]) = scr_map[*saves];
+ f = scp->ysize * scp->xsize + 5;
+ outb(crtc_addr, 14);
+ outb(crtc_addr+1, f >> 8);
+ outb(crtc_addr, 15);
+ outb(crtc_addr+1, f & 0xff);
+ scrn_blanked = 1;
+ }
+ if (scrn_blanked++ < 4)
+ return;
+ scrn_blanked = 1;
+ *(savs[sizeof(saves)-2]) = scr_map[0x20];
+ for (f=sizeof(saves)-2; f > 0; f--)
+ savs[f] = savs[f-1];
+ f = (savs[0] - (u_char *)Crtat) / 2;
+ if ((f % scp->xsize) == 0 ||
+ (f % scp->xsize) == scp->xsize - 1 ||
+ (random() % 50) == 0)
+ dirx = -dirx;
+ if ((f / scp->xsize) == 0 ||
+ (f / scp->xsize) == scp->ysize - 1 ||
+ (random() % 20) == 0)
+ diry = -diry;
+ savs[0] += 2*dirx + 2*diry;
+ for (f=sizeof(saves)-2; f>=0; f--)
+ *(savs[f]) = scr_map[saves[f]];
+ }
+ else {
+ if (scrn_blanked) {
+ bcopy(scp->scr_buf, Crtat,
+ scp->xsize * scp->ysize * 2);
+ cur_cursor_pos = -1;
+ set_border(scp->border);
+ scrn_blanked = 0;
+ }
+ }
+}
+
+
+static void
+cursor_shape(int start, int end)
+{
+ outb(crtc_addr, 10);
+ outb(crtc_addr+1, start & 0xFF);
+ outb(crtc_addr, 11);
+ outb(crtc_addr+1, end & 0xFF);
+}
+
+
+#if !defined(FAT_CURSOR)
+static void
+get_cursor_shape(int *start, int *end)
+{
+ outb(crtc_addr, 10);
+ *start = inb(crtc_addr+1) & 0x1F;
+ outb(crtc_addr, 11);
+ *end = inb(crtc_addr+1) & 0x1F;
+}
+#endif
+
+
+static void
+cursor_pos(int force)
+{
+ int pos;
+
+ if (cur_console->status & UNKNOWN_MODE)
+ return;
+ if (scrn_blank_time && (time.tv_sec > scrn_time_stamp+scrn_blank_time))
+ SCRN_SAVER(1);
+ pos = cur_console->crtat - cur_console->crt_base;
+ if (force || (!scrn_blanked && pos != cur_cursor_pos)) {
+ cur_cursor_pos = pos;
+ outb(crtc_addr, 14);
+ outb(crtc_addr+1, pos>>8);
+ outb(crtc_addr, 15);
+ outb(crtc_addr+1, pos&0xff);
+ }
+ timeout((timeout_t)cursor_pos, 0, hz/20);
+}
+
+
+static void
+clear_screen(scr_stat *scp)
+{
+ move_crsr(scp, 0, 0);
+ fillw(scp->term.cur_attr | scr_map[0x20], scp->crt_base,
+ scp->xsize * scp->ysize);
+}
+
+
+static int
+switch_scr(u_int next_scr)
+{
+ if (switch_in_progress &&
+ (cur_console->proc != pfind(cur_console->pid)))
+ switch_in_progress = 0;
+
+ if (next_scr >= NCONS || switch_in_progress) {
+ sysbeep(BELL_PITCH, BELL_DURATION);
+ return EINVAL;
+ }
+
+ /* is the wanted virtual console open ? */
+ if (next_scr) {
+ struct tty *tp = VIRTUAL_TTY(next_scr);
+ if (!(tp->t_state & TS_ISOPEN)) {
+ sysbeep(BELL_PITCH, BELL_DURATION);
+ return EINVAL;
+ }
+ }
+ if (in_putc) { /* delay switch if in putc */
+ delayed_next_scr = next_scr+1;
+ return 0;
+ }
+ switch_in_progress = 1;
+ old_scp = cur_console;
+ new_scp = &console[next_scr];
+ wakeup((caddr_t)&new_scp->smode);
+ if (new_scp == old_scp) {
+ switch_in_progress = 0;
+ return 0;
+ }
+
+ /* has controlling process died? */
+ if (old_scp->proc && (old_scp->proc != pfind(old_scp->pid)))
+ old_scp->smode.mode = VT_AUTO;
+ if (new_scp->proc && (new_scp->proc != pfind(new_scp->pid)))
+ new_scp->smode.mode = VT_AUTO;
+
+ /* check the modes and switch approbiatly */
+ if (old_scp->smode.mode == VT_PROCESS) {
+ old_scp->status |= SWITCH_WAIT_REL;
+ psignal(old_scp->proc, old_scp->smode.relsig);
+ }
+ else {
+ exchange_scr();
+ if (new_scp->smode.mode == VT_PROCESS) {
+ new_scp->status |= SWITCH_WAIT_ACQ;
+ psignal(new_scp->proc, new_scp->smode.acqsig);
+ }
+ else
+ switch_in_progress = 0;
+ }
+ return 0;
+}
+
+
+static void
+exchange_scr(void)
+{
+ struct tty *tp;
+
+ bcopy(Crtat, old_scp->scr_buf, old_scp->xsize * old_scp->ysize * 2);
+ old_scp->crt_base = old_scp->scr_buf;
+ move_crsr(old_scp, old_scp->xpos, old_scp->ypos);
+ cur_console = new_scp;
+ set_mode(new_scp);
+ new_scp->crt_base = Crtat;
+ move_crsr(new_scp, new_scp->xpos, new_scp->ypos);
+ bcopy(new_scp->scr_buf, Crtat, new_scp->xsize * new_scp->ysize * 2);
+ update_leds(new_scp->status);
+ if ((old_scp->status & UNKNOWN_MODE) && crtc_vga) {
+ copy_font(LOAD, 0, 16, font_16);
+ copy_font(LOAD, 1, 8, font_8);
+ copy_font(LOAD, 2, 14, font_14);
+ load_palette();
+ }
+ if (old_scp->status & KBD_RAW_MODE || new_scp->status & KBD_RAW_MODE)
+ shfts = ctls = alts = agrs = metas = 0;
+ delayed_next_scr = 0;
+}
+
+
+static void
+move_crsr(scr_stat *scp, int x, int y)
+{
+ if (x < 0 || y < 0 || x >= scp->xsize || y >= scp->ysize)
+ return;
+ scp->xpos = x;
+ scp->ypos = y;
+ scp->crtat = scp->crt_base + scp->ypos * scp->xsize + scp->xpos;
+}
+
+
+static void
+move_up(u_short *s, u_short *d, u_int len)
+{
+ s += len;
+ d += len;
+ while (len-- > 0)
+ *--d = *--s;
+}
+
+
+static void
+move_down(u_short *s, u_short *d, u_int len)
+{
+ while (len-- > 0)
+ *d++ = *s++;
+}
+
+
+static void
+scan_esc(scr_stat *scp, u_char c)
+{
+ static u_char ansi_col[16] =
+ {0, 4, 2, 6, 1, 5, 3, 7, 8, 12, 10, 14, 9, 13, 11, 15};
+ int i, n;
+ u_short *src, *dst, count;
+
+ if (scp->term.esc == 1) {
+ switch (c) {
+
+ case '[': /* Start ESC [ sequence */
+ scp->term.esc = 2;
+ scp->term.last_param = -1;
+ for (i = scp->term.num_param; i < MAX_ESC_PAR; i++)
+ scp->term.param[i] = 1;
+ scp->term.num_param = 0;
+ return;
+
+ case 'M': /* Move cursor up 1 line, scroll if at top */
+ if (scp->ypos > 0)
+ move_crsr(scp, scp->xpos, scp->ypos - 1);
+ else {
+ move_up(scp->crt_base,
+ scp->crt_base + scp->xsize,
+ (scp->ysize - 1) * scp->xsize);
+ fillw(scp->term.cur_attr | scr_map[0x20],
+ scp->crt_base, scp->xsize);
+ }
+ break;
+#if notyet
+ case 'Q':
+ scp->term.esc = 4;
+ break;
+#endif
+ case 'c': /* Clear screen & home */
+ clear_screen(scp);
+ break;
+ }
+ }
+ else if (scp->term.esc == 2) {
+ if (c >= '0' && c <= '9') {
+ if (scp->term.num_param < MAX_ESC_PAR) {
+ if (scp->term.last_param != scp->term.num_param) {
+ scp->term.last_param = scp->term.num_param;
+ scp->term.param[scp->term.num_param] = 0;
+ }
+ else
+ scp->term.param[scp->term.num_param] *= 10;
+ scp->term.param[scp->term.num_param] += c - '0';
+ return;
+ }
+ }
+ scp->term.num_param = scp->term.last_param + 1;
+ switch (c) {
+
+ case ';':
+ if (scp->term.num_param < MAX_ESC_PAR)
+ return;
+ break;
+
+ case '=':
+ scp->term.esc = 3;
+ scp->term.last_param = -1;
+ for (i = scp->term.num_param; i < MAX_ESC_PAR; i++)
+ scp->term.param[i] = 1;
+ scp->term.num_param = 0;
+ return;
+
+ case 'A': /* up n rows */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ move_crsr(scp, scp->xpos, scp->ypos - n);
+ break;
+
+ case 'B': /* down n rows */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ move_crsr(scp, scp->xpos, scp->ypos + n);
+ break;
+
+ case 'C': /* right n columns */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ move_crsr(scp, scp->xpos + n, scp->ypos);
+ break;
+
+ case 'D': /* left n columns */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ move_crsr(scp, scp->xpos - n, scp->ypos);
+ break;
+
+ case 'E': /* cursor to start of line n lines down */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ move_crsr(scp, 0, scp->ypos + n);
+ break;
+
+ case 'F': /* cursor to start of line n lines up */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ move_crsr(scp, 0, scp->ypos - n);
+ break;
+
+ case 'f': /* System V consoles .. */
+ case 'H': /* Cursor move */
+ if (scp->term.num_param == 0)
+ move_crsr(scp, 0, 0);
+ else if (scp->term.num_param == 2)
+ move_crsr(scp, scp->term.param[1] - 1,
+ scp->term.param[0] - 1);
+ break;
+
+ case 'J': /* Clear all or part of display */
+ if (scp->term.num_param == 0)
+ n = 0;
+ else
+ n = scp->term.param[0];
+ switch (n) {
+ case 0: /* clear form cursor to end of display */
+ fillw(scp->term.cur_attr | scr_map[0x20],
+ scp->crtat, scp->crt_base +
+ scp->xsize * scp->ysize -
+ scp->crtat);
+ break;
+ case 1: /* clear from beginning of display to cursor */
+ fillw(scp->term.cur_attr | scr_map[0x20],
+ scp->crt_base,
+ scp->crtat - scp->crt_base);
+ break;
+ case 2: /* clear entire display */
+ clear_screen(scp);
+ break;
+ }
+ break;
+
+ case 'K': /* Clear all or part of line */
+ if (scp->term.num_param == 0)
+ n = 0;
+ else
+ n = scp->term.param[0];
+ switch (n) {
+ case 0: /* clear form cursor to end of line */
+ fillw(scp->term.cur_attr | scr_map[0x20],
+ scp->crtat, scp->xsize - scp->xpos);
+ break;
+ case 1: /* clear from beginning of line to cursor */
+ fillw(scp->term.cur_attr|scr_map[0x20],
+ scp->crtat - (scp->xsize - scp->xpos),
+ (scp->xsize - scp->xpos) + 1);
+ break;
+ case 2: /* clear entire line */
+ fillw(scp->term.cur_attr|scr_map[0x20],
+ scp->crtat - (scp->xsize - scp->xpos),
+ scp->xsize);
+ break;
+ }
+ break;
+
+ case 'L': /* Insert n lines */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ if (n > scp->ysize - scp->ypos)
+ n = scp->ysize - scp->ypos;
+ src = scp->crt_base + scp->ypos * scp->xsize;
+ dst = src + n * scp->xsize;
+ count = scp->ysize - (scp->ypos + n);
+ move_up(src, dst, count * scp->xsize);
+ fillw(scp->term.cur_attr | scr_map[0x20], src,
+ n * scp->xsize);
+ break;
+
+ case 'M': /* Delete n lines */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ if (n > scp->ysize - scp->ypos)
+ n = scp->ysize - scp->ypos;
+ dst = scp->crt_base + scp->ypos * scp->xsize;
+ src = dst + n * scp->xsize;
+ count = scp->ysize - (scp->ypos + n);
+ move_down(src, dst, count * scp->xsize);
+ src = dst + count * scp->xsize;
+ fillw(scp->term.cur_attr | scr_map[0x20], src,
+ n * scp->xsize);
+ break;
+
+ case 'P': /* Delete n chars */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ if (n > scp->xsize - scp->xpos)
+ n = scp->xsize - scp->xpos;
+ dst = scp->crtat;
+ src = dst + n;
+ count = scp->xsize - (scp->xpos + n);
+ move_down(src, dst, count);
+ src = dst + count;
+ fillw(scp->term.cur_attr | scr_map[0x20], src, n);
+ break;
+
+ case '@': /* Insert n chars */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ if (n > scp->xsize - scp->xpos)
+ n = scp->xsize - scp->xpos;
+ src = scp->crtat;
+ dst = src + n;
+ count = scp->xsize - (scp->xpos + n);
+ move_up(src, dst, count);
+ fillw(scp->term.cur_attr | scr_map[0x20], src, n);
+ break;
+
+ case 'S': /* scroll up n lines */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ if (n > scp->ypos)
+ n = scp->ypos;
+ bcopy(scp->crt_base + (scp->xsize * n),
+ scp->crt_base,
+ scp->xsize * (scp->ysize - n) *
+ sizeof(u_short));
+ fillw(scp->term.cur_attr | scr_map[0x20],
+ scp->crt_base + scp->xsize *
+ (scp->ysize - 1),
+ scp->xsize);
+ break;
+
+ case 'T': /* scroll down n lines */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ if (n > scp->ysize - scp->ypos)
+ n = scp->ysize - scp->ypos;
+ bcopy(scp->crt_base,
+ scp->crt_base + (scp->xsize * n),
+ scp->xsize * (scp->ysize - n) *
+ sizeof(u_short));
+ fillw(scp->term.cur_attr | scr_map[0x20],
+ scp->crt_base, scp->xsize);
+ break;
+
+ case 'X': /* delete n characters in line */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ if (n > scp->xsize - scp->xpos)
+ n = scp->xsize - scp->xpos;
+ fillw(scp->term.cur_attr | scr_map[0x20],
+ scp->crt_base + scp->xpos +
+ ((scp->xsize*scp->ypos) * sizeof(u_short)), n);
+ break;
+
+ case 'Z': /* move n tabs backwards */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ if ((i = scp->xpos & 0xf8) == scp->xpos)
+ i -= 8*n;
+ else
+ i -= 8*(n-1);
+ if (i < 0)
+ i = 0;
+ move_crsr(scp, i, scp->ypos);
+ break;
+
+ case '`': /* move cursor to column n */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ move_crsr(scp, n, scp->ypos);
+ break;
+
+ case 'a': /* move cursor n columns to the right */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ move_crsr(scp, scp->xpos + n, scp->ypos);
+ break;
+
+ case 'd': /* move cursor to row n */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ move_crsr(scp, scp->xpos, n);
+ break;
+
+ case 'e': /* move cursor n rows down */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ move_crsr(scp, scp->xpos, scp->ypos + n);
+ break;
+
+ case 'm': /* change attribute */
+ if (scp->term.num_param == 0) {
+ scp->term.cur_attr = scp->term.std_attr;
+ break;
+ }
+ for (i = 0; i < scp->term.num_param; i++) {
+ switch (n = scp->term.param[i]) {
+ case 0: /* back to normal */
+ scp->term.cur_attr = scp->term.std_attr;
+ break;
+ case 1: /* highlight (bold) */
+ scp->term.cur_attr &= 0xFF00;
+ scp->term.cur_attr |= 0x0800;
+ break;
+ case 4: /* highlight (underline) */
+ scp->term.cur_attr &= 0xFF00;
+ scp->term.cur_attr |= 0x0800;
+ break;
+ case 5: /* blink */
+ scp->term.cur_attr &= 0xFF00;
+ scp->term.cur_attr |= 0x8000;
+ break;
+ case 7: /* reverse video */
+ scp->term.cur_attr = scp->term.rev_attr;
+ break;
+ case 30: case 31: /* set fg color */
+ case 32: case 33: case 34:
+ case 35: case 36: case 37:
+ scp->term.cur_attr =
+ (scp->term.cur_attr & 0xF8FF)
+ | (ansi_col[(n-30) & 7] << 8);
+ break;
+ case 40: case 41: /* set bg color */
+ case 42: case 43: case 44:
+ case 45: case 46: case 47:
+ scp->term.cur_attr =
+ (scp->term.cur_attr & 0x8FFF)
+ | (ansi_col[(n-40) & 7] << 12);
+ break;
+ }
+ }
+ break;
+
+ case 'x':
+ if (scp->term.num_param == 0)
+ n = 0;
+ else
+ n = scp->term.param[0];
+ switch (n) {
+ case 0: /* reset attributes */
+ scp->term.cur_attr = scp->term.std_attr =
+ current_default->std_attr;
+ scp->term.rev_attr = current_default->rev_attr;
+ break;
+ case 1: /* set ansi background */
+ scp->term.cur_attr = scp->term.std_attr =
+ (scp->term.std_attr & 0x0F00) |
+ (ansi_col[(scp->term.param[1])&0x0F]<<12);
+ break;
+ case 2: /* set ansi foreground */
+ scp->term.cur_attr = scp->term.std_attr =
+ (scp->term.std_attr & 0xF000) |
+ (ansi_col[(scp->term.param[1])&0x0F]<<8);
+ break;
+ case 3: /* set ansi attribute directly */
+ scp->term.cur_attr = scp->term.std_attr =
+ (scp->term.param[1]&0xFF)<<8;
+ break;
+ case 5: /* set ansi reverse video background */
+ scp->term.rev_attr =
+ (scp->term.rev_attr & 0x0F00) |
+ (ansi_col[(scp->term.param[1])&0x0F]<<12);
+ break;
+ case 6: /* set ansi reverse video foreground */
+ scp->term.rev_attr =
+ (scp->term.rev_attr & 0xF000) |
+ (ansi_col[(scp->term.param[1])&0x0F]<<8);
+ break;
+ case 7: /* set ansi reverse video directly */
+ scp->term.rev_attr = (scp->term.param[1]&0xFF)<<8;
+ break;
+ }
+ break;
+
+ case 'z': /* switch to (virtual) console n */
+ if (scp->term.num_param == 1)
+ switch_scr(scp->term.param[0]);
+ break;
+ }
+ }
+ else if (scp->term.esc == 3) {
+ if (c >= '0' && c <= '9') {
+ if (scp->term.num_param < MAX_ESC_PAR) {
+ if (scp->term.last_param != scp->term.num_param) {
+ scp->term.last_param = scp->term.num_param;
+ scp->term.param[scp->term.num_param] = 0;
+ }
+ else
+ scp->term.param[scp->term.num_param] *= 10;
+ scp->term.param[scp->term.num_param] += c - '0';
+ return;
+ }
+ }
+ scp->term.num_param = scp->term.last_param + 1;
+ switch (c) {
+
+ case ';':
+ if (scp->term.num_param < MAX_ESC_PAR)
+ return;
+ break;
+
+ case 'A': /* set display border color */
+ if (scp->term.num_param == 1)
+ scp->border=scp->term.param[0] & 0xff;
+ if (scp == cur_console)
+ set_border(scp->border);
+ break;
+
+ case 'B': /* set bell pitch and duration */
+ if (scp->term.num_param == 2) {
+ scp->bell_pitch = scp->term.param[0];
+ scp->bell_duration = scp->term.param[1]*10;
+ }
+ break;
+
+ case 'C': /* set cursor shape (start & end line) */
+ if (scp->term.num_param == 2) {
+ scp->cursor_start = scp->term.param[0] & 0x1F;
+ scp->cursor_end = scp->term.param[1] & 0x1F;
+ if (scp == cur_console)
+ cursor_shape(scp->cursor_start,
+ scp->cursor_end);
+ }
+ break;
+
+ case 'F': /* set ansi foreground */
+ if (scp->term.num_param == 1)
+ scp->term.cur_attr = scp->term.std_attr =
+ (scp->term.std_attr & 0xF000)
+ | ((scp->term.param[0] & 0x0F) << 8);
+ break;
+
+ case 'G': /* set ansi background */
+ if (scp->term.num_param == 1)
+ scp->term.cur_attr = scp->term.std_attr =
+ (scp->term.std_attr & 0x0F00)
+ | ((scp->term.param[0] & 0x0F) << 12);
+ break;
+
+ case 'H': /* set ansi reverse video foreground */
+ if (scp->term.num_param == 1)
+ scp->term.rev_attr =
+ (scp->term.rev_attr & 0xF000)
+ | ((scp->term.param[0] & 0x0F) << 8);
+ break;
+
+ case 'I': /* set ansi reverse video background */
+ if (scp->term.num_param == 1)
+ scp->term.rev_attr =
+ (scp->term.rev_attr & 0x0F00)
+ | ((scp->term.param[0] & 0x0F) << 12);
+ break;
+ }
+ }
+ scp->term.esc = 0;
+}
+
+
+static void
+ansi_put(scr_stat *scp, u_char c)
+{
+ if (scp->status & UNKNOWN_MODE)
+ return;
+
+ /* make screensaver happy */
+ if (scp == cur_console) {
+ scrn_time_stamp = time.tv_sec;
+ if (scrn_blanked)
+ SCRN_SAVER(0);
+ }
+ in_putc++;
+ if (scp->term.esc)
+ scan_esc(scp, c);
+ else switch(c) {
+ case 0x1B: /* start escape sequence */
+ scp->term.esc = 1;
+ scp->term.num_param = 0;
+ break;
+ case 0x07:
+ if (scp == cur_console)
+ sysbeep(scp->bell_pitch, scp->bell_duration);
+ break;
+ case '\t': /* non-destructive tab */
+ scp->crtat += (8 - scp->xpos % 8);
+ scp->xpos += (8 - scp->xpos % 8);
+ break;
+ case '\b': /* non-destructive backspace */
+ if (scp->crtat > scp->crt_base) {
+ scp->crtat--;
+ if (scp->xpos > 0)
+ scp->xpos--;
+ else {
+ scp->xpos += scp->xsize - 1;
+ scp->ypos--;
+ }
+ }
+ break;
+ case '\r': /* return to pos 0 */
+ move_crsr(scp, 0, scp->ypos);
+ break;
+ case '\n': /* newline, same pos */
+ scp->crtat += scp->xsize;
+ scp->ypos++;
+ break;
+ case '\f': /* form feed, clears screen */
+ clear_screen(scp);
+ break;
+ default:
+ /* Print only printables */
+ *scp->crtat = (scp->term.cur_attr | scr_map[c]);
+ scp->crtat++;
+ if (++scp->xpos >= scp->xsize) {
+ scp->xpos = 0;
+ scp->ypos++;
+ }
+ break;
+ }
+ if (scp->crtat >= scp->crt_base + scp->ysize * scp->xsize) {
+ bcopy(scp->crt_base + scp->xsize, scp->crt_base,
+ scp->xsize * (scp->ysize - 1) * sizeof(u_short));
+ fillw(scp->term.cur_attr | scr_map[0x20],
+ scp->crt_base + scp->xsize * (scp->ysize - 1),
+ scp->xsize);
+ scp->crtat -= scp->xsize;
+ scp->ypos--;
+ }
+ in_putc--;
+ if (delayed_next_scr)
+ switch_scr(delayed_next_scr - 1);
+}
+
+
+static void
+scinit(void)
+{
+ u_short volatile *cp = Crtat + (CGA_BUF-MONO_BUF)/sizeof(u_short), was;
+ unsigned cursorat;
+ int i;
+
+ /*
+ * catch that once in a blue moon occurence when scinit is called
+ * TWICE, adding the CGA_BUF offset again -> poooff
+ */
+ if (crtat != 0)
+ return;
+ /*
+ * Crtat initialized to point to MONO buffer, if not present change
+ * to CGA_BUF offset. ONLY ADD the difference since locore.s adds
+ * in the remapped offset at the "right" time
+ */
+ was = *cp;
+ *cp = (u_short) 0xA55A;
+ if (*cp != 0xA55A) {
+ crtc_addr = MONO_BASE;
+ } else {
+ *cp = was;
+ crtc_addr = COLOR_BASE;
+ Crtat = Crtat + (CGA_BUF-MONO_BUF)/sizeof(u_short);
+ }
+
+ /* Extract cursor location */
+ outb(crtc_addr,14);
+ cursorat = inb(crtc_addr+1)<<8 ;
+ outb(crtc_addr,15);
+ cursorat |= inb(crtc_addr+1);
+ crtat = Crtat + cursorat;
+
+ /* is this a VGA or higher ? */
+ outb(crtc_addr, 7);
+ if (inb(crtc_addr) == 7)
+ crtc_vga = 1;
+
+ current_default = &user_default;
+ console[0].crtat = crtat;
+ console[0].crt_base = Crtat;
+ console[0].term.esc = 0;
+ console[0].term.std_attr = current_default->std_attr;
+ console[0].term.rev_attr = current_default->rev_attr;
+ console[0].term.cur_attr = current_default->std_attr;
+ console[0].xpos = cursorat % COL;
+ console[0].ypos = cursorat / COL;
+ console[0].border = BG_BLACK;;
+ console[0].xsize = COL;
+ console[0].ysize = ROW;
+ console[0].status = NLKED;
+ console[0].pid = 0;
+ console[0].proc = NULL;
+ console[0].smode.mode = VT_AUTO;
+ console[0].bell_pitch = BELL_PITCH;
+ console[0].bell_duration = BELL_DURATION;
+ kernel_console.esc = 0;
+ kernel_console.std_attr = kernel_default.std_attr;
+ kernel_console.rev_attr = kernel_default.rev_attr;
+ kernel_console.cur_attr = kernel_default.std_attr;
+ /* initialize mapscrn array to a one to one map */
+ for (i=0; i<sizeof(scr_map); i++)
+ scr_map[i] = i;
+ clear_screen(&console[0]);
+}
+
+
+static void
+scput(u_char c)
+{
+ scr_stat *scp = &console[0];
+ term_stat save;
+
+ if (crtat == 0)
+ scinit();
+ if( in_putc == 0) {
+ ++in_putc;
+ save = scp->term;
+ scp->term = kernel_console;
+ current_default = &kernel_default;
+ ansi_put(scp, c);
+ kernel_console = scp->term;
+ current_default = &user_default;
+ scp->term = save;
+ --in_putc;
+ } else {
+ if( console_buffer_count < CONSOLE_BUFSIZE)
+ console_buffer[console_buffer_count++] = c;
+ }
+}
+
+
+static u_char
+*get_fstr(u_int c, u_int *len)
+{
+ u_int i;
+
+ if (!(c & FKEY))
+ return(NULL);
+ i = (c & 0xFF) - F_FN;
+ if (i > n_fkey_tab)
+ return(NULL);
+ *len = fkey_tab[i].len;
+ return(fkey_tab[i].str);
+}
+
+
+static void
+update_leds(int which)
+{
+ int s;
+ static u_char xlate_leds[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
+
+ /* replace CAPS led with ALTGR led for ALTGR keyboards */
+ if (key_map.n_keys > ALTGR_OFFSET) {
+ if (which & ALKED)
+ which |= CLKED;
+ else
+ which &= ~CLKED;
+ }
+ s = spltty();
+ kbd_cmd(KB_SETLEDS);
+ kbd_cmd(xlate_leds[which & LED_MASK]);
+ splx(s);
+}
+
+
+/*
+ * scgetc(noblock) - get character from keyboard.
+ * If noblock = 0 wait until a key is pressed.
+ * Else return NOKEY.
+ */
+u_int
+scgetc(int noblock)
+{
+ u_char scancode, keycode;
+ u_int state, action;
+ struct key_t *key;
+ static u_char esc_flag = 0, compose = 0;
+ static u_int chr = 0;
+
+next_code:
+ kbd_wait();
+ /* First see if there is something in the keyboard port */
+ if (inb(KB_STAT) & KB_BUF_FULL)
+ scancode = inb(KB_DATA);
+ else if (noblock)
+ return(NOKEY);
+ else
+ goto next_code;
+
+ if (cur_console->status & KBD_RAW_MODE)
+ return scancode;
+#if ASYNCH
+ if (scancode == KB_ACK || scancode == KB_RESEND) {
+ kbd_reply = scancode;
+ if (noblock)
+ return(NOKEY);
+ goto next_code;
+ }
+#endif
+ keycode = scancode & 0x7F;
+ switch (esc_flag) {
+ case 0x00: /* normal scancode */
+ switch(scancode) {
+ case 0xB8: /* left alt (compose key) */
+ if (compose) {
+ compose = 0;
+ if (chr > 255) {
+ sysbeep(BELL_PITCH, BELL_DURATION);
+ chr = 0;
+ }
+ }
+ break;
+ case 0x38:
+ if (!compose) {
+ compose = 1;
+ chr = 0;
+ }
+ break;
+ case 0xE0:
+ case 0xE1:
+ esc_flag = scancode;
+ goto next_code;
+ }
+ break;
+ case 0xE0: /* 0xE0 prefix */
+ esc_flag = 0;
+ switch (keycode) {
+ case 0x1C: /* right enter key */
+ keycode = 0x59;
+ break;
+ case 0x1D: /* right ctrl key */
+ keycode = 0x5A;
+ break;
+ case 0x35: /* keypad divide key */
+ keycode = 0x5B;
+ break;
+ case 0x37: /* print scrn key */
+ keycode = 0x5C;
+ break;
+ case 0x38: /* right alt key (alt gr) */
+ keycode = 0x5D;
+ break;
+ case 0x47: /* grey home key */
+ keycode = 0x5E;
+ break;
+ case 0x48: /* grey up arrow key */
+ keycode = 0x5F;
+ break;
+ case 0x49: /* grey page up key */
+ keycode = 0x60;
+ break;
+ case 0x4B: /* grey left arrow key */
+ keycode = 0x61;
+ break;
+ case 0x4D: /* grey right arrow key */
+ keycode = 0x62;
+ break;
+ case 0x4F: /* grey end key */
+ keycode = 0x63;
+ break;
+ case 0x50: /* grey down arrow key */
+ keycode = 0x64;
+ break;
+ case 0x51: /* grey page down key */
+ keycode = 0x65;
+ break;
+ case 0x52: /* grey insert key */
+ keycode = 0x66;
+ break;
+ case 0x53: /* grey delete key */
+ keycode = 0x67;
+ break;
+ default: /* ignore everything else */
+ goto next_code;
+ }
+ break;
+ case 0xE1: /* 0xE1 prefix */
+ esc_flag = 0;
+ if (keycode == 0x1D)
+ esc_flag = 0x1D;
+ goto next_code;
+ /* NOT REACHED */
+ case 0x1D: /* pause / break */
+ esc_flag = 0;
+ if (keycode != 0x45)
+ goto next_code;
+ keycode = 0x68;
+ break;
+ }
+
+ if (compose) {
+ switch (scancode) {
+ /* key pressed process it */
+ case 0x47: case 0x48: case 0x49: /* keypad 7,8,9 */
+ chr = (scancode - 0x40) + chr*10;
+ goto next_code;
+ case 0x4B: case 0x4C: case 0x4D: /* keypad 4,5,6 */
+ chr = (scancode - 0x47) + chr*10;
+ goto next_code;
+ case 0x4F: case 0x50: case 0x51: /* keypad 1,2,3 */
+ chr = (scancode - 0x4E) + chr*10;
+ goto next_code;
+ case 0x52: /* keypad 0 */
+ chr *= 10;
+ goto next_code;
+
+ /* key release, no interest here */
+ case 0xC7: case 0xC8: case 0xC9: /* keypad 7,8,9 */
+ case 0xCB: case 0xCC: case 0xCD: /* keypad 4,5,6 */
+ case 0xCF: case 0xD0: case 0xD1: /* keypad 1,2,3 */
+ case 0xD2: /* keypad 0 */
+ goto next_code;
+
+ case 0x38: /* left alt key */
+ break;
+ default:
+ if (chr) {
+ compose = chr = 0;
+ sysbeep(BELL_PITCH, BELL_DURATION);
+ goto next_code;
+ }
+ break;
+ }
+ }
+
+ state = (shfts ? 1 : 0 ) | (2 * (ctls ? 1 : 0)) | (4 * (alts ? 1 : 0));
+ if ((!agrs && (cur_console->status & ALKED))
+ || (agrs && !(cur_console->status & ALKED)))
+ keycode += ALTGR_OFFSET;
+ key = &key_map.key[keycode];
+ if ( ((key->flgs & FLAG_LOCK_C) && (cur_console->status & CLKED))
+ || ((key->flgs & FLAG_LOCK_N) && (cur_console->status & NLKED)) )
+ state ^= 1;
+
+ /* Check for make/break */
+ action = key->map[state];
+ if (scancode & 0x80) { /* key released */
+ if (key->spcl & 0x80) {
+ switch (action) {
+ case LSH:
+ shfts &= ~1;
+ break;
+ case RSH:
+ shfts &= ~2;
+ break;
+ case LCTR:
+ ctls &= ~1;
+ break;
+ case RCTR:
+ ctls &= ~2;
+ break;
+ case LALT:
+ alts &= ~1;
+ break;
+ case RALT:
+ alts &= ~2;
+ break;
+ case NLK:
+ nlkcnt = 0;
+ break;
+ case CLK:
+ clkcnt = 0;
+ break;
+ case SLK:
+ slkcnt = 0;
+ break;
+ case ASH:
+ agrs = 0;
+ break;
+ case ALK:
+ alkcnt = 0;
+ break;
+ case META:
+ metas = 0;
+ break;
+ }
+ }
+ if (chr && !compose) {
+ action = chr;
+ chr = 0;
+ return(action);
+ }
+ } else {
+ /* key pressed */
+ if (key->spcl & (0x80>>state)) {
+ switch (action) {
+ /* LOCKING KEYS */
+ case NLK:
+ if (!nlkcnt) {
+ nlkcnt++;
+ if (cur_console->status & NLKED)
+ cur_console->status &= ~NLKED;
+ else
+ cur_console->status |= NLKED;
+ update_leds(cur_console->status);
+ }
+ break;
+ case CLK:
+ if (!clkcnt) {
+ clkcnt++;
+ if (cur_console->status & CLKED)
+ cur_console->status &= ~CLKED;
+ else
+ cur_console->status |= CLKED;
+ update_leds(cur_console->status);
+ }
+ break;
+ case SLK:
+ if (!slkcnt) {
+ slkcnt++;
+ if (cur_console->status & SLKED) {
+ cur_console->status &= ~SLKED;
+ pcstart(VIRTUAL_TTY(get_scr_num()));
+ }
+ else
+ cur_console->status |= SLKED;
+ update_leds(cur_console->status);
+ }
+ break;
+ case ALK:
+ if (!alkcnt) {
+ alkcnt++;
+ if (cur_console->status & ALKED)
+ cur_console->status &= ~ALKED;
+ else
+ cur_console->status |= ALKED;
+ update_leds(cur_console->status);
+ }
+ break;
+
+ /* NON-LOCKING KEYS */
+ case NOP:
+ break;
+ case RBT:
+ shutdown_nice();
+ break;
+ case DBG:
+#if DDB > 0 /* try to switch to console 0 */
+ if (cur_console->smode.mode == VT_AUTO &&
+ console[0].smode.mode == VT_AUTO)
+ switch_scr(0);
+ Debugger("manual escape to debugger");
+ return(NOKEY);
+#else
+ printf("No debugger in kernel\n");
+#endif
+ break;
+ case LSH:
+ shfts |= 1;
+ break;
+ case RSH:
+ shfts |= 2;
+ break;
+ case LCTR:
+ ctls |= 1;
+ break;
+ case RCTR:
+ ctls |= 2;
+ break;
+ case LALT:
+ alts |= 1;
+ break;
+ case RALT:
+ alts |= 2;
+ break;
+ case ASH:
+ agrs = 1;
+ break;
+ case META:
+ metas = 1;
+ break;
+ case NEXT:
+ switch_scr((get_scr_num()+1)%NCONS);
+ break;
+ default:
+ if (action >= F_SCR && action <= L_SCR) {
+ switch_scr(action - F_SCR);
+ break;
+ }
+ if (action >= F_FN && action <= L_FN)
+ action |= FKEY;
+ return(action);
+ }
+ }
+ else {
+ if (metas)
+ action |= MKEY;
+ return(action);
+ }
+ }
+ goto next_code;
+}
+
+
+int
+getchar(void)
+{
+ u_char thechar;
+ int s;
+
+ polling = 1;
+ s = splhigh();
+ scput('>');
+ thechar = (u_char) scgetc(0);
+ polling = 0;
+ splx(s);
+ switch (thechar) {
+ default:
+ if (thechar >= scr_map[0x20])
+ scput(thechar);
+ return(thechar);
+ case cr:
+ case lf:
+ scput(cr); scput(lf);
+ return(lf);
+ case bs:
+ case del:
+ scput(bs); scput(scr_map[0x20]); scput(bs);
+ return(thechar);
+ case cntld:
+ scput('^'); scput('D'); scput('\r'); scput('\n');
+ return(0);
+ }
+}
+
+
+u_int
+sgetc(int noblock)
+{
+ return (scgetc(noblock) & 0xff);
+}
+
+
+int
+pcmmap(dev_t dev, int offset, int nprot)
+{
+ if (offset > 0x20000)
+ return EINVAL;
+ return i386_btop((VIDEOMEM + offset));
+}
+
+
+static void
+kbd_wait(void)
+{
+ int i = 1000;
+
+ while (i--) {
+ if ((inb(KB_STAT) & KB_READY) == 0)
+ break;
+ DELAY (10);
+ }
+}
+
+
+static void
+kbd_cmd(u_char command)
+{
+ int retry = 5;
+ do {
+ int i = 100000;
+
+ kbd_wait();
+#if ASYNCH
+ kbd_reply = 0;
+ outb(KB_DATA, command);
+ while (i--) {
+ if (kbd_reply == KB_ACK)
+ return;
+ if (kbd_reply == KB_RESEND)
+ break;
+ }
+#else
+ outb(KB_DATA, command);
+ while (i--) {
+ if (inb(KB_STAT) & KB_BUF_FULL) {
+ int val;
+ DELAY(10);
+ val = inb(KB_DATA);
+ if (val == KB_ACK)
+ return;
+ if (val == KB_RESEND)
+ break;
+ }
+ }
+#endif
+ } while (retry--);
+}
+
+
+static void
+set_mode(scr_stat *scp)
+{
+ u_char byte;
+ int s;
+
+ if (scp != cur_console)
+ return;
+
+ /* (re)activate cursor */
+ untimeout((timeout_t)cursor_pos, 0);
+ cursor_pos(1);
+
+ /* change cursor type if set */
+ if (scp->cursor_start != -1 && scp->cursor_end != -1)
+ cursor_shape(scp->cursor_start, scp->cursor_end);
+
+ /* mode change only on VGA's */
+ if (!crtc_vga)
+ return;
+
+ /* setup video hardware for the given mode */
+ s = splhigh();
+ switch(scp->mode) {
+ case TEXT80x25:
+ outb(crtc_addr, 9); byte = inb(crtc_addr+1);
+ outb(crtc_addr, 9); outb(crtc_addr+1, byte | 0x0F);
+ outb(TSIDX, 0x03); outb(TSREG, 0x00); /* select font 0 */
+ break;
+ case TEXT80x50:
+ outb(crtc_addr, 9); byte = inb(crtc_addr+1);
+ outb(crtc_addr, 9); outb(crtc_addr+1, (byte & 0xF0) | 0x07);
+ outb(TSIDX, 0x03); outb(TSREG, 0x05); /* select font 1 */
+ break;
+ default:
+ break;
+ }
+ splx(s);
+
+ /* set border color for this (virtual) console */
+ set_border(scp->border);
+ return;
+}
+
+
+static void
+set_border(int color)
+{
+ inb(crtc_addr+6); /* reset flip-flop */
+ outb(ATC, 0x11); outb(ATC, color);
+ inb(crtc_addr+6); /* reset flip-flop */
+ outb(ATC, 0x20); /* enable Palette */
+}
+
+
+static void
+copy_font(int direction, int segment, int size, char* font)
+{
+ int ch, line, s;
+ u_char val;
+
+ outb(TSIDX, 0x01); val = inb(TSREG); /* blank screen */
+ outb(TSIDX, 0x01); outb(TSREG, val | 0x20);
+
+ /* setup vga for loading fonts (graphics plane mode) */
+ s = splhigh();
+ inb(crtc_addr+6); /* reset flip/flop */
+ outb(ATC, 0x30); outb(ATC, 0x01);
+ outb(TSIDX, 0x02); outb(TSREG, 0x04);
+ outb(TSIDX, 0x04); outb(TSREG, 0x06);
+ outb(GDCIDX, 0x04); outb(GDCREG, 0x02);
+ outb(GDCIDX, 0x05); outb(GDCREG, 0x00);
+ outb(GDCIDX, 0x06); outb(GDCREG, 0x05); /* addr = a0000, 64kb */
+ splx(s);
+ for (ch=0; ch < 256; ch++)
+ for (line=0; line < size; line++)
+ if (direction)
+ *((char *)atdevbase+(segment*0x4000)+(ch*32)+line) =
+ font[(ch*size)+line];
+ else
+ font[(ch*size)+line] =
+ *((char *)atdevbase+(segment*0x4000)+(ch*32)+line);
+
+ /* setup vga for text mode again */
+ s = splhigh();
+ inb(crtc_addr+6); /* reset flip/flop */
+ outb(ATC, 0x30); outb(ATC, 0x0C);
+ outb(TSIDX, 0x02); outb(TSREG, 0x03);
+ outb(TSIDX, 0x04); outb(TSREG, 0x02);
+ outb(GDCIDX, 0x04); outb(GDCREG, 0x00);
+ outb(GDCIDX, 0x05); outb(GDCREG, 0x10);
+ if (crtc_addr == MONO_BASE) {
+ outb(GDCIDX, 0x06); outb(GDCREG, 0x0A); /* addr = b0000, 32kb */
+ }
+ else {
+ outb(GDCIDX, 0x06); outb(GDCREG, 0x0E); /* addr = b8000, 32kb */
+ }
+ splx(s);
+ outb(TSIDX, 0x01); val = inb(TSREG); /* unblank screen */
+ outb(TSIDX, 0x01); outb(TSREG, val & 0xDF);
+}
+
+
+static void
+load_palette(void)
+{
+ int i;
+
+ outb(PIXMASK, 0xFF); /* no pixelmask */
+ outb(PALWADR, 0x00);
+ for (i=0x00; i<0x300; i++)
+ outb(PALDATA, palette[i]);
+ inb(crtc_addr+6); /* reset flip/flop */
+ outb(ATC, 0x20); /* enable palette */
+}
+
+
+static void
+save_palette(void)
+{
+ int i;
+
+ outb(PALRADR, 0x00);
+ for (i=0x00; i<0x300; i++)
+ palette[i] = inb(PALDATA);
+ inb(crtc_addr+6); /* reset flip/flop */
+}
+
+
+static void
+change_winsize(struct tty *tp, int x, int y)
+{
+ if (tp->t_winsize.ws_col != x || tp->t_winsize.ws_row != y) {
+ tp->t_winsize.ws_col = x;
+ tp->t_winsize.ws_row = y;
+ pgsignal(tp->t_pgrp, SIGWINCH, 1);
+ }
+}
+
+#endif /* NSC */
diff --git a/sys/isa/timerreg.h b/sys/isa/timerreg.h
new file mode 100644
index 0000000..5742f66
--- /dev/null
+++ b/sys/isa/timerreg.h
@@ -0,0 +1,93 @@
+/*-
+ * Copyright (c) 1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 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.
+ *
+ * from: Header: timerreg.h,v 1.2 93/02/28 15:08:58 mccanne Exp
+ * $Id$
+ */
+
+/*
+ *
+ * Register definitions for the Intel 8253 Programmable Interval Timer.
+ *
+ * This chip has three independent 16-bit down counters that can be
+ * read on the fly. There are three mode registers and three countdown
+ * registers. The countdown registers are addressed directly, via the
+ * first three I/O ports. The three mode registers are accessed via
+ * the fourth I/O port, with two bits in the mode byte indicating the
+ * register. (Why are hardware interfaces always so braindead?).
+ *
+ * To write a value into the countdown register, the mode register
+ * is first programmed with a command indicating the which byte of
+ * the two byte register is to be modified. The three possibilities
+ * are load msb (TMR_MR_MSB), load lsb (TMR_MR_LSB), or load lsb then
+ * msb (TMR_MR_BOTH).
+ *
+ * To read the current value ("on the fly") from the countdown register,
+ * you write a "latch" command into the mode register, then read the stable
+ * value from the corresponding I/O port. For example, you write
+ * TMR_MR_LATCH into the corresponding mode register. Presumably,
+ * after doing this, a write operation to the I/O port would result
+ * in undefined behavior (but hopefully not fry the chip).
+ * Reading in this manner has no side effects.
+ *
+ * The outputs of the three timers are connected as follows:
+ *
+ * timer 0 -> irq 0
+ * timer 1 -> dma chan 0 (for dram refresh)
+ * timer 2 -> speaker (via keyboard controller)
+ *
+ * Timer 0 is used to call hardclock.
+ * Timer 2 is used to generate console beeps.
+ */
+
+/*
+ * Macros for specifying values to be written into a mode register.
+ */
+#define TIMER_CNTR0 (IO_TIMER1 + 0) /* timer 0 counter port */
+#define TIMER_CNTR1 (IO_TIMER1 + 1) /* timer 1 counter port */
+#define TIMER_CNTR2 (IO_TIMER1 + 2) /* timer 2 counter port */
+#define TIMER_MODE (IO_TIMER1 + 3) /* timer mode port */
+#define TIMER_SEL0 0x00 /* select counter 0 */
+#define TIMER_SEL1 0x40 /* select counter 1 */
+#define TIMER_SEL2 0x80 /* select counter 2 */
+#define TIMER_INTTC 0x00 /* mode 0, intr on terminal cnt */
+#define TIMER_ONESHOT 0x02 /* mode 1, one shot */
+#define TIMER_RATEGEN 0x04 /* mode 2, rate generator */
+#define TIMER_SQWAVE 0x06 /* mode 3, square wave */
+#define TIMER_SWSTROBE 0x08 /* mode 4, s/w triggered strobe */
+#define TIMER_HWSTROBE 0x0a /* mode 5, h/w triggered strobe */
+#define TIMER_LATCH 0x00 /* latch counter for reading */
+#define TIMER_LSB 0x10 /* r/w counter LSB */
+#define TIMER_MSB 0x20 /* r/w counter MSB */
+#define TIMER_16BIT 0x30 /* r/w counter 16 bits, LSB first */
+#define TIMER_BCD 0x01 /* count in BCD */
+
OpenPOWER on IntegriCloud