diff options
Diffstat (limited to 'sys/isa')
-rw-r--r-- | sys/isa/atrtc.c | 539 | ||||
-rw-r--r-- | sys/isa/fd.c | 1255 | ||||
-rw-r--r-- | sys/isa/fdc.h | 75 | ||||
-rw-r--r-- | sys/isa/fdreg.h | 65 | ||||
-rw-r--r-- | sys/isa/ic/nec765.h | 72 | ||||
-rw-r--r-- | sys/isa/ic/ns16550.h | 51 | ||||
-rw-r--r-- | sys/isa/kbdtables.h | 859 | ||||
-rw-r--r-- | sys/isa/rtc.h | 109 | ||||
-rw-r--r-- | sys/isa/sio.c | 1957 | ||||
-rw-r--r-- | sys/isa/sioreg.h | 114 | ||||
-rw-r--r-- | sys/isa/syscons.c | 2707 | ||||
-rw-r--r-- | sys/isa/timerreg.h | 93 |
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 */ + |