Index: head/sys/amd64/amd64/tsc.c =================================================================== --- head/sys/amd64/amd64/tsc.c (revision 618) +++ head/sys/amd64/amd64/tsc.c (revision 619) @@ -1,271 +1,252 @@ /*- * 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. * - * @(#)clock.c 7.2 (Berkeley) 5/12/91 - * - * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE - * -------------------- ----- ---------------------- - * CURRENT PATCH LEVEL: 5 00158 - * -------------------- ----- ---------------------- - * - * 14 Aug 92 Arne Henrik Juul Added code in the kernel to - * allow for DST in the BIOS. - * 17 Jan 93 Bruce Evans Fixed leap year and second - * calculations - * 01 Feb 93 Julian Elischer Added code to for the cpu - * speed independent spinwait() - * function, (used by scsi and others) - * 25 Mar 93 Sean Eric Fagan Add microtimer support using timer 1 - * 08 Apr 93 Poul-Henning Kamp/P-HK Fixes, and support for dcfclock - * 26 Apr 93 Bruce Evans Eliminate findspeed, new spinwait - * 26 Apr 93 Rodney W. Grimes I merged in Bruce changes and hope I - * still kept the other fixes... Had to - * add back in findcpuspeed that Bruce - * had removed. + * from: @(#)clock.c 7.2 (Berkeley) 5/12/91 + * $Id$ */ /* * Primitive clock interrupt routines. */ #include "param.h" #include "systm.h" #include "time.h" #include "kernel.h" #include "machine/segments.h" #include "i386/isa/icu.h" #include "i386/isa/isa.h" #include "i386/isa/rtc.h" #include "i386/isa/timerreg.h" #define DAYST 119 #define DAYEN 303 /* 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 startrtclock() { int s; findcpuspeed(); /* use the clock (while it's free) to find the cpu speed */ /* 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_FREQ+hz/2)/hz); outb (IO_TIMER1, ((TIMER_FREQ+hz/2)/hz)/256); /* initialize brain-dead battery powered clock */ outb (IO_RTC, RTC_STATUSA); outb (IO_RTC+1, 0x26); outb (IO_RTC, RTC_STATUSB); outb (IO_RTC+1, 2); outb (IO_RTC, RTC_DIAG); if (s = inb (IO_RTC+1)) printf("RTC BIOS diagnostic error %b\n", s, RTCDG_BITS); outb (IO_RTC, RTC_DIAG); outb (IO_RTC+1, 0); } unsigned int delaycount; /* calibrated loop variable (1 millisecond) */ #define FIRST_GUESS 0x2000 findcpuspeed() { unsigned char low; unsigned int remainder; /* Put counter in count down mode */ outb(IO_TIMER1+3, 0x34); outb(IO_TIMER1, 0xff); outb(IO_TIMER1, 0xff); delaycount = FIRST_GUESS; spinwait(1); /* Read the value left in the counter */ low = inb(IO_TIMER1); /* least siginifcant */ remainder = inb(IO_TIMER1); /* most significant */ remainder = (remainder<<8) + low ; /* Formula for delaycount is : * (loopcount * timer clock speed)/ (counter ticks * 1000) */ delaycount = (FIRST_GUESS * (TIMER_FREQ/1000)) / (0xffff-remainder); } /* convert 2 digit BCD number */ bcd(i) int i; { return ((i/16)*10 + (i%16)); } /* convert years to seconds (from 1970) */ unsigned long ytos(y) 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(m,leap) int m,leap; { int i; unsigned long ret; ret = 0; for(i=1;i= DAYST) && ( yd <= DAYEN)) { sec -= 60*60; } 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(base) 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 /* * Restart the clock. */ resettodr() { } /* * Wire clock interrupt in. */ #define V(s) __CONCAT(V, s) extern V(clk)(); enablertclock() { setidt(ICU_OFFSET+0, &V(clk), SDT_SYS386IGT, SEL_KPL); INTREN(IRQ0); } /* * Delay for some number of milliseconds. */ void spinwait(millisecs) int millisecs; { DELAY(1000 * millisecs); } Index: head/sys/amd64/isa/clock.c =================================================================== --- head/sys/amd64/isa/clock.c (revision 618) +++ head/sys/amd64/isa/clock.c (revision 619) @@ -1,271 +1,252 @@ /*- * 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. * - * @(#)clock.c 7.2 (Berkeley) 5/12/91 - * - * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE - * -------------------- ----- ---------------------- - * CURRENT PATCH LEVEL: 5 00158 - * -------------------- ----- ---------------------- - * - * 14 Aug 92 Arne Henrik Juul Added code in the kernel to - * allow for DST in the BIOS. - * 17 Jan 93 Bruce Evans Fixed leap year and second - * calculations - * 01 Feb 93 Julian Elischer Added code to for the cpu - * speed independent spinwait() - * function, (used by scsi and others) - * 25 Mar 93 Sean Eric Fagan Add microtimer support using timer 1 - * 08 Apr 93 Poul-Henning Kamp/P-HK Fixes, and support for dcfclock - * 26 Apr 93 Bruce Evans Eliminate findspeed, new spinwait - * 26 Apr 93 Rodney W. Grimes I merged in Bruce changes and hope I - * still kept the other fixes... Had to - * add back in findcpuspeed that Bruce - * had removed. + * from: @(#)clock.c 7.2 (Berkeley) 5/12/91 + * $Id$ */ /* * Primitive clock interrupt routines. */ #include "param.h" #include "systm.h" #include "time.h" #include "kernel.h" #include "machine/segments.h" #include "i386/isa/icu.h" #include "i386/isa/isa.h" #include "i386/isa/rtc.h" #include "i386/isa/timerreg.h" #define DAYST 119 #define DAYEN 303 /* 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 startrtclock() { int s; findcpuspeed(); /* use the clock (while it's free) to find the cpu speed */ /* 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_FREQ+hz/2)/hz); outb (IO_TIMER1, ((TIMER_FREQ+hz/2)/hz)/256); /* initialize brain-dead battery powered clock */ outb (IO_RTC, RTC_STATUSA); outb (IO_RTC+1, 0x26); outb (IO_RTC, RTC_STATUSB); outb (IO_RTC+1, 2); outb (IO_RTC, RTC_DIAG); if (s = inb (IO_RTC+1)) printf("RTC BIOS diagnostic error %b\n", s, RTCDG_BITS); outb (IO_RTC, RTC_DIAG); outb (IO_RTC+1, 0); } unsigned int delaycount; /* calibrated loop variable (1 millisecond) */ #define FIRST_GUESS 0x2000 findcpuspeed() { unsigned char low; unsigned int remainder; /* Put counter in count down mode */ outb(IO_TIMER1+3, 0x34); outb(IO_TIMER1, 0xff); outb(IO_TIMER1, 0xff); delaycount = FIRST_GUESS; spinwait(1); /* Read the value left in the counter */ low = inb(IO_TIMER1); /* least siginifcant */ remainder = inb(IO_TIMER1); /* most significant */ remainder = (remainder<<8) + low ; /* Formula for delaycount is : * (loopcount * timer clock speed)/ (counter ticks * 1000) */ delaycount = (FIRST_GUESS * (TIMER_FREQ/1000)) / (0xffff-remainder); } /* convert 2 digit BCD number */ bcd(i) int i; { return ((i/16)*10 + (i%16)); } /* convert years to seconds (from 1970) */ unsigned long ytos(y) 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(m,leap) int m,leap; { int i; unsigned long ret; ret = 0; for(i=1;i= DAYST) && ( yd <= DAYEN)) { sec -= 60*60; } 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(base) 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 /* * Restart the clock. */ resettodr() { } /* * Wire clock interrupt in. */ #define V(s) __CONCAT(V, s) extern V(clk)(); enablertclock() { setidt(ICU_OFFSET+0, &V(clk), SDT_SYS386IGT, SEL_KPL); INTREN(IRQ0); } /* * Delay for some number of milliseconds. */ void spinwait(millisecs) int millisecs; { DELAY(1000 * millisecs); } Index: head/sys/amd64/isa/icu.h =================================================================== --- head/sys/amd64/isa/icu.h (revision 618) +++ head/sys/amd64/isa/icu.h (revision 619) @@ -1,109 +1,103 @@ /*- * 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. * - * @(#)icu.h 5.6 (Berkeley) 5/9/91 - * - * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE - * -------------------- ----- ---------------------- - * CURRENT PATCH LEVEL: 1 00158 - * -------------------- ----- ---------------------- - * - * 25 Apr 93 Bruce Evans New fast interrupt code (intr-0.1) + * from: @(#)icu.h 5.6 (Berkeley) 5/9/91 + * $Id$ */ /* * AT/386 Interrupt Control constants * W. Jolitz 8/89 */ #ifndef __ICU__ #define __ICU__ #ifndef LOCORE /* * Interrupt "level" mechanism variables, masks, and macros */ extern unsigned imen; /* interrupt mask enable */ extern unsigned cpl; /* current priority level mask */ extern unsigned highmask; /* group of interrupts masked with splhigh() */ extern unsigned ttymask; /* group of interrupts masked with spltty() */ extern unsigned biomask; /* group of interrupts masked with splbio() */ extern unsigned netmask; /* group of interrupts masked with splimp() */ #define INTREN(s) (imen &= ~(s), SET_ICUS()) #define INTRDIS(s) (imen |= (s), SET_ICUS()) #define INTRMASK(msk,s) (msk |= (s)) #if 0 #define SET_ICUS() (outb(IO_ICU1 + 1, imen), outb(IU_ICU2 + 1, imen >> 8)) #else /* * XXX - IO_ICU* are defined in isa.h, not icu.h, and nothing much bothers to * include isa.h, while too many things include icu.h. */ #define SET_ICUS() (outb(0x21, imen), outb(0xa1, imen >> 8)) #endif #endif /* * Interrupt enable bits -- in order of priority */ #define IRQ0 0x0001 /* highest priority - timer */ #define IRQ1 0x0002 #define IRQ_SLAVE 0x0004 #define IRQ8 0x0100 #define IRQ9 0x0200 #define IRQ2 IRQ9 #define IRQ10 0x0400 #define IRQ11 0x0800 #define IRQ12 0x1000 #define IRQ13 0x2000 #define IRQ14 0x4000 #define IRQ15 0x8000 #define IRQ3 0x0008 #define IRQ4 0x0010 #define IRQ5 0x0020 #define IRQ6 0x0040 #define IRQ7 0x0080 /* lowest - parallel printer */ /* * Interrupt Control offset into Interrupt descriptor table (IDT) */ #define ICU_OFFSET 32 /* 0-31 are processor exceptions */ #define ICU_LEN 16 /* 32-47 are ISA interrupts */ #endif __ICU__ Index: head/sys/amd64/isa/isa.h =================================================================== --- head/sys/amd64/isa/isa.h (revision 618) +++ head/sys/amd64/isa/isa.h (revision 619) @@ -1,188 +1,180 @@ /*- * 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. * - * @(#)isa.h 5.7 (Berkeley) 5/9/91 - * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE - * -------------------- ----- ---------------------- - * CURRENT PATCH LEVEL: 3 00158 - * -------------------- ----- ---------------------- - * - * 15 Feb 93 Julian Elischer Added entries for some scsi adapters - * 06 Apr 93 Rodney W. Grimes Added com3 and com4, added IO_ISASIZES - * section - * 26 Apr 93 Bruce Evans Support for intr-0.1 + * from: @(#)isa.h 5.7 (Berkeley) 5/9/91 + * $Id$ */ /* * ISA Bus conventions */ #ifndef LOCORE #include unsigned char rtcin __P((int)); extern unsigned int atdevbase; /* offset in virtual memory of ISA io mem */ void sysbeep __P((int, int)); unsigned kbd_8042cmd __P((int)); struct isa_device; int isa_irq_pending __P((struct isa_device *dvp)); #endif /* * Input / Output Port Assignments */ #ifndef IO_BEGIN #define IO_ISABEGIN 0x000 /* 0x000 - Beginning of I/O Registers */ /* CPU Board */ #define IO_DMA1 0x000 /* 8237A DMA Controller #1 */ #define IO_ICU1 0x020 /* 8259A Interrupt Controller #1 */ #define IO_TIMER1 0x040 /* 8252 Timer #1 */ #define IO_TIMER2 0x048 /* 8252 Timer #2 */ #define IO_KBD 0x060 /* 8042 Keyboard */ #define IO_RTC 0x070 /* RTC */ #define IO_NMI IO_RTC /* NMI Control */ #define IO_DMAPG 0x080 /* DMA Page Registers */ #define IO_ICU2 0x0A0 /* 8259A Interrupt Controller #2 */ #define IO_DMA2 0x0C0 /* 8237A DMA Controller #2 */ #define IO_NPX 0x0F0 /* Numeric Coprocessor */ /* Cards */ /* 0x100 - 0x16F Open */ #define IO_WD2 0x170 /* Secondary Fixed Disk Controller */ /* 0x178 - 0x1EF Open */ #define IO_WD1 0x1f0 /* Primary Fixed Disk Controller */ #define IO_GAME 0x200 /* Game Controller */ /* 0x208 - 0x277 Open */ #define IO_LPT2 0x278 /* Parallel Port #2 */ /* 0x280 - 0x2E7 Open */ #define IO_COM4 0x2e8 /* COM4 i/o address */ /* 0x2F0 - 0x2F7 Open */ #define IO_COM2 0x2f8 /* COM2 i/o address */ /* 0x300 - 0x32F Open */ #define IO_BT0 0x330 /* bustek 742a default addr. */ #define IO_AHA0 0x330 /* adaptec 1542 default addr. */ #define IO_UHA0 0x330 /* ultrastore 14f default addr. */ #define IO_BT1 0x334 /* bustek 742a default addr. */ #define IO_AHA1 0x334 /* adaptec 1542 default addr. */ /* 0x338 - 0x36F Open */ #define IO_FD2 0x370 /* secondary base i/o address */ #define IO_LPT1 0x378 /* Parallel Port #1 */ /* 0x380 - 0x3AF Open */ #define IO_MDA 0x3B0 /* Monochome Adapter */ #define IO_LPT3 0x3BC /* Monochome Adapter Printer Port */ #define IO_VGA 0x3C0 /* E/VGA Ports */ #define IO_CGA 0x3D0 /* CGA Ports */ /* 0x3E0 - 0x3E7 Open */ #define IO_COM3 0x3e8 /* COM3 i/o address */ #define IO_FD1 0x3f0 /* primary base i/o address */ #define IO_COM1 0x3f8 /* COM1 i/o address */ #define IO_ISAEND 0x3FF /* - 0x3FF End of I/O Registers */ #endif IO_ISABEGIN /* * Input / Output Port Sizes - these are from several sources, and tend * to be the larger of what was found, ie COM ports can be 4, but some * boards do not fully decode the address, thus 8 ports are used. */ #ifndef IO_ISASIZES #define IO_ISASIZES #define IO_COMSIZE 8 /* 8250, 16X50 com controllers (4?) */ #define IO_CGASIZE 16 /* CGA controllers */ #define IO_DMASIZE 16 /* 8237 DMA controllers */ #define IO_DPGSIZE 32 /* 74LS612 DMA page reisters */ #define IO_FDCSIZE 8 /* Nec765 floppy controllers */ #define IO_WDCSIZE 8 /* WD compatible disk controllers */ #define IO_GAMSIZE 16 /* AT compatible game controllers */ #define IO_ICUSIZE 16 /* 8259A interrupt controllers */ #define IO_KBDSIZE 16 /* 8042 Keyboard controllers */ #define IO_LPTSIZE 8 /* LPT controllers, some use only 4 */ #define IO_MDASIZE 16 /* Monochrome display controllers */ #define IO_RTCSIZE 16 /* CMOS real time clock, NMI control */ #define IO_TMRSIZE 16 /* 8253 programmable timers */ #define IO_NPXSIZE 16 /* 80387/80487 NPX registers */ #define IO_VGASIZE 16 /* VGA controllers */ #endif /* IO_ISASIZES */ /* * Input / Output Memory Physical Addresses */ #ifndef IOM_BEGIN #define IOM_BEGIN 0x0a0000 /* Start of I/O Memory "hole" */ #define IOM_END 0x100000 /* End of I/O Memory "hole" */ #define IOM_SIZE (IOM_END - IOM_BEGIN) #endif IOM_BEGIN /* * RAM Physical Address Space (ignoring the above mentioned "hole") */ #ifndef RAM_BEGIN #define RAM_BEGIN 0x0000000 /* Start of RAM Memory */ #define RAM_END 0x1000000 /* End of RAM Memory */ #define RAM_SIZE (RAM_END - RAM_BEGIN) #endif RAM_BEGIN /* * Oddball Physical Memory Addresses */ #ifndef COMPAQ_RAMRELOC #define COMPAQ_RAMRELOC 0x80c00000 /* Compaq RAM relocation/diag */ #define COMPAQ_RAMSETUP 0x80c00002 /* Compaq RAM setup */ #define WEITEK_FPU 0xC0000000 /* WTL 2167 */ #define CYRIX_EMC 0xC0000000 /* Cyrix EMC */ #endif COMPAQ_RAMRELOC Index: head/sys/amd64/isa/timerreg.h =================================================================== --- head/sys/amd64/isa/timerreg.h (revision 618) +++ head/sys/amd64/isa/timerreg.h (revision 619) @@ -1,89 +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. * - * $Header: timerreg.h,v 1.2 93/02/28 15:08:58 mccanne Exp $ + * 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 */ Index: head/sys/amd64/isa/vector.S =================================================================== --- head/sys/amd64/isa/vector.S (revision 618) +++ head/sys/amd64/isa/vector.S (revision 619) @@ -1,376 +1,368 @@ -/* vector.s */ /* - * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE - * -------------------- ----- ---------------------- - * CURRENT PATCH LEVEL: 1 00167 - * -------------------- ----- ---------------------- - * - * 04 Jun 93 Bruce Evans Fixed irq_num vs id_num for multiple - * devices configed on the same irq with - * respect to ipending. - * + * from: vector.s, 386BSD 0.1 unknown origin + * $Id$ */ #include "i386/isa/icu.h" #include "i386/isa/isa.h" #include "vector.h" #define ICU_EOI 0x20 /* XXX - define elsewhere */ #define IRQ_BIT(irq_num) (1 << ((irq_num) % 8)) #define IRQ_BYTE(irq_num) ((irq_num) / 8) #define ENABLE_ICU1 \ movb $ICU_EOI,%al ; /* as soon as possible send EOI ... */ \ FASTER_NOP ; /* ... ASAP ... */ \ outb %al,$IO_ICU1 /* ... to clear in service bit */ #ifdef AUTO_EOI_1 #undef ENABLE_ICU1 /* we now use auto-EOI to reduce i/o */ #define ENABLE_ICU1 #endif #define ENABLE_ICU1_AND_2 \ movb $ICU_EOI,%al ; /* as above */ \ FASTER_NOP ; \ outb %al,$IO_ICU2 ; /* but do second icu first */ \ FASTER_NOP ; \ outb %al,$IO_ICU1 /* then first icu */ #ifdef AUTO_EOI_2 #undef ENABLE_ICU1_AND_2 /* data sheet says no auto-EOI on slave ... */ #define ENABLE_ICU1_AND_2 /* ... but it works */ #endif /* * Macros for interrupt interrupt entry, call to handler, and exit. * * XXX - the interrupt frame is set up to look like a trap frame. This is * usually a waste of time. The only interrupt handlers that want a frame * are the clock handler (it wants a clock frame), the npx handler (it's * easier to do right all in assembler). The interrupt return routine * needs a trap frame for rare AST's (it could easily convert the frame). * The direct costs of setting up a trap frame are two pushl's (error * code and trap number), an addl to get rid of these, and pushing and * popping the call-saved regs %esi, %edi and %ebp twice, The indirect * costs are making the driver interface nonuniform so unpending of * interrupts is more complicated and slower (call_driver(unit) would * be easier than ensuring an interrupt frame for all handlers. Finally, * there are some struct copies in the npx handler and maybe in the clock * handler that could be avoided by working more with pointers to frames * instead of frames. * * XXX - should we do a cld on every system entry to avoid the requirement * for scattered cld's? * * Coding notes for *.s: * * If possible, avoid operations that involve an operand size override. * Word-sized operations might be smaller, but the operand size override * makes them slower on on 486's and no faster on 386's unless perhaps * the instruction pipeline is depleted. E.g., * * Use movl to seg regs instead of the equivalent but more descriptive * movw - gas generates an irelevant (slower) operand size override. * * Use movl to ordinary regs in preference to movw and especially * in preference to movz[bw]l. Use unsigned (long) variables with the * top bits clear instead of unsigned short variables to provide more * opportunities for movl. * * If possible, use byte-sized operations. They are smaller and no slower. * * Use (%reg) instead of 0(%reg) - gas generates larger code for the latter. * * If the interrupt frame is made more flexible, INTR can push %eax first * and decide the ipending case with less overhead, e.g., by avoiding * loading segregs. */ #define FAST_INTR(unit, irq_num, id_num, handler, enable_icus) \ pushl %eax ; /* save only call-used registers */ \ pushl %ecx ; \ pushl %edx ; \ pushl %ds ; \ /* pushl %es ; know compiler doesn't do string insns */ \ movl $KDSEL,%eax ; \ movl %ax,%ds ; \ /* movl %ax,%es ; */ \ SHOW_CLI ; /* although it interferes with "ASAP" */ \ pushl $unit ; \ call handler ; /* do the work ASAP */ \ enable_icus ; /* (re)enable ASAP (helps edge trigger?) */ \ addl $4,%esp ; \ incl _cnt+V_INTR ; /* book-keeping can wait */ \ COUNT_EVENT(_intrcnt_actv, id_num) ; \ SHOW_STI ; \ /* popl %es ; */ \ popl %ds ; \ popl %edx; \ popl %ecx; \ popl %eax; \ iret #define INTR(unit, irq_num, id_num, mask, handler, icu, enable_icus, reg, stray) \ pushl $0 ; /* dummy error code */ \ pushl $T_ASTFLT ; \ pushal ; \ pushl %ds ; /* save our data and extra segments ... */ \ pushl %es ; \ movl $KDSEL,%eax ; /* ... and reload with kernel's own ... */ \ movl %ax,%ds ; /* ... early in case SHOW_A_LOT is on */ \ movl %ax,%es ; \ SHOW_CLI ; /* interrupt did an implicit cli */ \ movb _imen + IRQ_BYTE(irq_num),%al ; \ orb $IRQ_BIT(irq_num),%al ; \ movb %al,_imen + IRQ_BYTE(irq_num) ; \ SHOW_IMEN ; \ FASTER_NOP ; \ outb %al,$icu+1 ; \ enable_icus ; \ incl _cnt+V_INTR ; /* tally interrupts */ \ movl _cpl,%eax ; \ testb $IRQ_BIT(irq_num),%reg ; \ jne 2f ; \ 1: ; \ COUNT_EVENT(_intrcnt_actv, id_num) ; \ movl _cpl,%eax ; \ pushl %eax ; \ pushl $unit ; \ orl mask,%eax ; \ movl %eax,_cpl ; \ SHOW_CPL ; \ SHOW_STI ; \ sti ; \ call handler ; \ movb _imen + IRQ_BYTE(irq_num),%al ; \ andb $~IRQ_BIT(irq_num),%al ; \ movb %al,_imen + IRQ_BYTE(irq_num) ; \ SHOW_IMEN ; \ FASTER_NOP ; \ outb %al,$icu+1 ; \ jmp doreti ; \ ; \ ALIGN_TEXT ; \ 2: ; \ COUNT_EVENT(_intrcnt_pend, id_num) ; \ movl $1b,%eax ; /* register resume address */ \ /* XXX - someday do it at attach time */ \ movl %eax,Vresume + (irq_num) * 4 ; \ orb $IRQ_BIT(irq_num),_ipending + IRQ_BYTE(irq_num) ; \ SHOW_IPENDING ; \ popl %es ; \ popl %ds ; \ popal ; \ addl $4+4,%esp ; \ iret /* * vector.h has defined a macro 'BUILD_VECTORS' containing a big list of info * about vectors, including a submacro 'BUILD_VECTOR' that operates on the * info about each vector. We redefine 'BUILD_VECTOR' to expand the info * in different ways. Here we expand it to a list of interrupt handlers. * This order is of course unimportant. Elsewhere we expand it to inline * linear search code for which the order is a little more important and * concatenating the code with no holes is very important. * * XXX - now there is BUILD_FAST_VECTOR as well as BUILD_VECTOR. * * The info consists of the following items for each vector: * * name (identifier): name of the vector; used to build labels * unit (expression): unit number to call the device driver with * irq_num (number): number of the IRQ to handled (0-15) * id_num (number): uniq numeric id for handler (assigned by config) * mask (blank-ident): priority mask used * handler (blank-ident): interrupt handler to call * icu_num (number): (1 + irq_num / 8) converted for label building * icu_enables (number): 1 for icu_num == 1, 1_AND_2 for icu_num == 2 * reg (blank-ident): al for icu_num == 1, ah for icu_num == 2 * * 'irq_num' is converted in several ways at config time to get around * limitations in cpp. The macros have blanks after commas iff they would * not mess up identifiers and numbers. */ #undef BUILD_FAST_VECTOR #define BUILD_FAST_VECTOR(name, unit, irq_num, id_num, mask, handler, \ icu_num, icu_enables, reg) \ .globl handler ; \ .text ; \ .globl _V/**/name ; \ SUPERALIGN_TEXT ; \ _V/**/name: ; \ FAST_INTR(unit, irq_num, id_num, handler, ENABLE_ICU/**/icu_enables) #undef BUILD_VECTOR #define BUILD_VECTOR(name, unit, irq_num, id_num, mask, handler, \ icu_num, icu_enables, reg) \ .globl handler ; \ .text ; \ .globl _V/**/name ; \ SUPERALIGN_TEXT ; \ _V/**/name: ; \ INTR(unit,irq_num,id_num, mask, handler, IO_ICU/**/icu_num, \ ENABLE_ICU/**/icu_enables, reg,) BUILD_VECTORS /* hardware interrupt catcher (IDT 32 - 47) */ .globl _isa_strayintr #define STRAYINTR(irq_num, icu_num, icu_enables, reg) \ IDTVEC(intr/**/irq_num) ; \ INTR(irq_num,irq_num,irq_num, _highmask, _isa_strayintr, \ IO_ICU/**/icu_num, ENABLE_ICU/**/icu_enables, reg,stray) /* * XXX - the mask (1 << 2) == IRQ_SLAVE will be generated for IRQ 2, instead * of the mask IRQ2 (defined as IRQ9 == (1 << 9)). But IRQ 2 "can't happen". * In fact, all stray interrupts "can't happen" except for bugs. The * "stray" IRQ 7 is documented behaviour of the 8259. It happens when there * is a glitch on any of its interrupt inputs. Does it really interrupt when * IRQ 7 is masked? * * XXX - unpend doesn't work for these, it sends them to the real handler. * * XXX - the race bug during initialization may be because I changed the * order of switching from the stray to the real interrupt handler to before * enabling interrupts. The old order looked unsafe but maybe it is OK with * the stray interrupt handler installed. But these handlers only reduce * the window of vulnerability - it is still open at the end of * isa_configure(). * * XXX - many comments are stale. */ STRAYINTR(0,1,1, al) STRAYINTR(1,1,1, al) STRAYINTR(2,1,1, al) STRAYINTR(3,1,1, al) STRAYINTR(4,1,1, al) STRAYINTR(5,1,1, al) STRAYINTR(6,1,1, al) STRAYINTR(8,2,1_AND_2, ah) STRAYINTR(9,2,1_AND_2, ah) STRAYINTR(10,2,1_AND_2, ah) STRAYINTR(11,2,1_AND_2, ah) STRAYINTR(12,2,1_AND_2, ah) STRAYINTR(13,2,1_AND_2, ah) STRAYINTR(14,2,1_AND_2, ah) STRAYINTR(15,2,1_AND_2, ah) IDTVEC(intrdefault) STRAYINTR(7,1,1, al) /* XXX */ #if 0 INTRSTRAY(255, _highmask, 255) ; call _isa_strayintr ; INTREXIT2 #endif /* * These are the interrupt counters, I moved them here from icu.s so that * they are with the name table. rgrimes * * There are now lots of counters, this has been redone to work with * Bruce Evans intr-0.1 code, which I modified some more to make it all * work with vmstat. */ .data Vresume: .space 16 * 4 /* where to resume intr handler after unpend */ .globl _intrcnt _intrcnt: /* used by vmstat to calc size of table */ .globl _intrcnt_bad7 _intrcnt_bad7: .space 4 /* glitches on irq 7 */ .globl _intrcnt_bad15 _intrcnt_bad15: .space 4 /* glitches on irq 15 */ .globl _intrcnt_stray _intrcnt_stray: .space 4 /* total count of stray interrupts */ .globl _intrcnt_actv _intrcnt_actv: .space NR_REAL_INT_HANDLERS * 4 /* active interrupts */ .globl _intrcnt_pend _intrcnt_pend: .space NR_REAL_INT_HANDLERS * 4 /* pending interrupts */ .globl _eintrcnt _eintrcnt: /* used by vmstat to calc size of table */ .globl _intrcnt_spl _intrcnt_spl: .space 32 * 4 /* XXX 32 should not be hard coded ? */ .globl _intrcnt_show _intrcnt_show: .space 8 * 4 /* XXX 16 should not be hard coded ? */ /* * Build the interrupt name table for vmstat */ #undef BUILD_FAST_VECTOR #define BUILD_FAST_VECTOR BUILD_VECTOR #undef BUILD_VECTOR #define BUILD_VECTOR(name, unit, irq_num, id_num, mask, handler, \ icu_num, icu_enables, reg) \ .ascii "name irq" ; \ .asciz "irq_num" /* * XXX - use the STRING and CONCAT macros from to stringize * and concatenate names above and elsewhere. */ .text .globl _intrnames, _eintrnames _intrnames: BUILD_VECTOR(bad,,7,,,,,,) BUILD_VECTOR(bad,,15,,,,,,) BUILD_VECTOR(stray,,,,,,,,) BUILD_VECTORS #undef BUILD_FAST_VECTOR #define BUILD_FAST_VECTOR BUILD_VECTOR #undef BUILD_VECTOR #define BUILD_VECTOR(name, unit, irq_num, id_num, mask, handler, \ icu_num, icu_enables, reg) \ .asciz "name pend" BUILD_VECTORS _eintrnames: /* * now the spl names */ .asciz "unpend_v" .asciz "doreti" .asciz "p0!ni" .asciz "!p0!ni" .asciz "p0ni" .asciz "netisr_raw" .asciz "netisr_ip" .asciz "netisr_imp" .asciz "netisr_ns" .asciz "netisr_iso" .asciz "softclock" /* 10 */ .asciz "trap" .asciz "doreti_exit2" .asciz "splbio" .asciz "splclock" .asciz "splhigh" .asciz "splimp" .asciz "splnet" .asciz "splsoftclock" .asciz "spltty" .asciz "spl0" /* 20 */ .asciz "netisr_raw2" .asciz "netisr_ip2" .asciz "netisr_imp2" .asciz "netisr_ns2" .asciz "netisr_iso2" .asciz "splx" .asciz "splx!0" .asciz "unpend_V" .asciz "spl29" /* spl29-spl31 are spares */ .asciz "spl30" .asciz "spl31" /* * now the mask names */ .asciz "cli" .asciz "cpl" .asciz "imen" .asciz "ipending" .asciz "sti" .asciz "mask5" /* mask5-mask7 are spares */ .asciz "mask6" .asciz "mask7" Index: head/sys/amd64/isa/vector.s =================================================================== --- head/sys/amd64/isa/vector.s (revision 618) +++ head/sys/amd64/isa/vector.s (revision 619) @@ -1,376 +1,368 @@ -/* vector.s */ /* - * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE - * -------------------- ----- ---------------------- - * CURRENT PATCH LEVEL: 1 00167 - * -------------------- ----- ---------------------- - * - * 04 Jun 93 Bruce Evans Fixed irq_num vs id_num for multiple - * devices configed on the same irq with - * respect to ipending. - * + * from: vector.s, 386BSD 0.1 unknown origin + * $Id$ */ #include "i386/isa/icu.h" #include "i386/isa/isa.h" #include "vector.h" #define ICU_EOI 0x20 /* XXX - define elsewhere */ #define IRQ_BIT(irq_num) (1 << ((irq_num) % 8)) #define IRQ_BYTE(irq_num) ((irq_num) / 8) #define ENABLE_ICU1 \ movb $ICU_EOI,%al ; /* as soon as possible send EOI ... */ \ FASTER_NOP ; /* ... ASAP ... */ \ outb %al,$IO_ICU1 /* ... to clear in service bit */ #ifdef AUTO_EOI_1 #undef ENABLE_ICU1 /* we now use auto-EOI to reduce i/o */ #define ENABLE_ICU1 #endif #define ENABLE_ICU1_AND_2 \ movb $ICU_EOI,%al ; /* as above */ \ FASTER_NOP ; \ outb %al,$IO_ICU2 ; /* but do second icu first */ \ FASTER_NOP ; \ outb %al,$IO_ICU1 /* then first icu */ #ifdef AUTO_EOI_2 #undef ENABLE_ICU1_AND_2 /* data sheet says no auto-EOI on slave ... */ #define ENABLE_ICU1_AND_2 /* ... but it works */ #endif /* * Macros for interrupt interrupt entry, call to handler, and exit. * * XXX - the interrupt frame is set up to look like a trap frame. This is * usually a waste of time. The only interrupt handlers that want a frame * are the clock handler (it wants a clock frame), the npx handler (it's * easier to do right all in assembler). The interrupt return routine * needs a trap frame for rare AST's (it could easily convert the frame). * The direct costs of setting up a trap frame are two pushl's (error * code and trap number), an addl to get rid of these, and pushing and * popping the call-saved regs %esi, %edi and %ebp twice, The indirect * costs are making the driver interface nonuniform so unpending of * interrupts is more complicated and slower (call_driver(unit) would * be easier than ensuring an interrupt frame for all handlers. Finally, * there are some struct copies in the npx handler and maybe in the clock * handler that could be avoided by working more with pointers to frames * instead of frames. * * XXX - should we do a cld on every system entry to avoid the requirement * for scattered cld's? * * Coding notes for *.s: * * If possible, avoid operations that involve an operand size override. * Word-sized operations might be smaller, but the operand size override * makes them slower on on 486's and no faster on 386's unless perhaps * the instruction pipeline is depleted. E.g., * * Use movl to seg regs instead of the equivalent but more descriptive * movw - gas generates an irelevant (slower) operand size override. * * Use movl to ordinary regs in preference to movw and especially * in preference to movz[bw]l. Use unsigned (long) variables with the * top bits clear instead of unsigned short variables to provide more * opportunities for movl. * * If possible, use byte-sized operations. They are smaller and no slower. * * Use (%reg) instead of 0(%reg) - gas generates larger code for the latter. * * If the interrupt frame is made more flexible, INTR can push %eax first * and decide the ipending case with less overhead, e.g., by avoiding * loading segregs. */ #define FAST_INTR(unit, irq_num, id_num, handler, enable_icus) \ pushl %eax ; /* save only call-used registers */ \ pushl %ecx ; \ pushl %edx ; \ pushl %ds ; \ /* pushl %es ; know compiler doesn't do string insns */ \ movl $KDSEL,%eax ; \ movl %ax,%ds ; \ /* movl %ax,%es ; */ \ SHOW_CLI ; /* although it interferes with "ASAP" */ \ pushl $unit ; \ call handler ; /* do the work ASAP */ \ enable_icus ; /* (re)enable ASAP (helps edge trigger?) */ \ addl $4,%esp ; \ incl _cnt+V_INTR ; /* book-keeping can wait */ \ COUNT_EVENT(_intrcnt_actv, id_num) ; \ SHOW_STI ; \ /* popl %es ; */ \ popl %ds ; \ popl %edx; \ popl %ecx; \ popl %eax; \ iret #define INTR(unit, irq_num, id_num, mask, handler, icu, enable_icus, reg, stray) \ pushl $0 ; /* dummy error code */ \ pushl $T_ASTFLT ; \ pushal ; \ pushl %ds ; /* save our data and extra segments ... */ \ pushl %es ; \ movl $KDSEL,%eax ; /* ... and reload with kernel's own ... */ \ movl %ax,%ds ; /* ... early in case SHOW_A_LOT is on */ \ movl %ax,%es ; \ SHOW_CLI ; /* interrupt did an implicit cli */ \ movb _imen + IRQ_BYTE(irq_num),%al ; \ orb $IRQ_BIT(irq_num),%al ; \ movb %al,_imen + IRQ_BYTE(irq_num) ; \ SHOW_IMEN ; \ FASTER_NOP ; \ outb %al,$icu+1 ; \ enable_icus ; \ incl _cnt+V_INTR ; /* tally interrupts */ \ movl _cpl,%eax ; \ testb $IRQ_BIT(irq_num),%reg ; \ jne 2f ; \ 1: ; \ COUNT_EVENT(_intrcnt_actv, id_num) ; \ movl _cpl,%eax ; \ pushl %eax ; \ pushl $unit ; \ orl mask,%eax ; \ movl %eax,_cpl ; \ SHOW_CPL ; \ SHOW_STI ; \ sti ; \ call handler ; \ movb _imen + IRQ_BYTE(irq_num),%al ; \ andb $~IRQ_BIT(irq_num),%al ; \ movb %al,_imen + IRQ_BYTE(irq_num) ; \ SHOW_IMEN ; \ FASTER_NOP ; \ outb %al,$icu+1 ; \ jmp doreti ; \ ; \ ALIGN_TEXT ; \ 2: ; \ COUNT_EVENT(_intrcnt_pend, id_num) ; \ movl $1b,%eax ; /* register resume address */ \ /* XXX - someday do it at attach time */ \ movl %eax,Vresume + (irq_num) * 4 ; \ orb $IRQ_BIT(irq_num),_ipending + IRQ_BYTE(irq_num) ; \ SHOW_IPENDING ; \ popl %es ; \ popl %ds ; \ popal ; \ addl $4+4,%esp ; \ iret /* * vector.h has defined a macro 'BUILD_VECTORS' containing a big list of info * about vectors, including a submacro 'BUILD_VECTOR' that operates on the * info about each vector. We redefine 'BUILD_VECTOR' to expand the info * in different ways. Here we expand it to a list of interrupt handlers. * This order is of course unimportant. Elsewhere we expand it to inline * linear search code for which the order is a little more important and * concatenating the code with no holes is very important. * * XXX - now there is BUILD_FAST_VECTOR as well as BUILD_VECTOR. * * The info consists of the following items for each vector: * * name (identifier): name of the vector; used to build labels * unit (expression): unit number to call the device driver with * irq_num (number): number of the IRQ to handled (0-15) * id_num (number): uniq numeric id for handler (assigned by config) * mask (blank-ident): priority mask used * handler (blank-ident): interrupt handler to call * icu_num (number): (1 + irq_num / 8) converted for label building * icu_enables (number): 1 for icu_num == 1, 1_AND_2 for icu_num == 2 * reg (blank-ident): al for icu_num == 1, ah for icu_num == 2 * * 'irq_num' is converted in several ways at config time to get around * limitations in cpp. The macros have blanks after commas iff they would * not mess up identifiers and numbers. */ #undef BUILD_FAST_VECTOR #define BUILD_FAST_VECTOR(name, unit, irq_num, id_num, mask, handler, \ icu_num, icu_enables, reg) \ .globl handler ; \ .text ; \ .globl _V/**/name ; \ SUPERALIGN_TEXT ; \ _V/**/name: ; \ FAST_INTR(unit, irq_num, id_num, handler, ENABLE_ICU/**/icu_enables) #undef BUILD_VECTOR #define BUILD_VECTOR(name, unit, irq_num, id_num, mask, handler, \ icu_num, icu_enables, reg) \ .globl handler ; \ .text ; \ .globl _V/**/name ; \ SUPERALIGN_TEXT ; \ _V/**/name: ; \ INTR(unit,irq_num,id_num, mask, handler, IO_ICU/**/icu_num, \ ENABLE_ICU/**/icu_enables, reg,) BUILD_VECTORS /* hardware interrupt catcher (IDT 32 - 47) */ .globl _isa_strayintr #define STRAYINTR(irq_num, icu_num, icu_enables, reg) \ IDTVEC(intr/**/irq_num) ; \ INTR(irq_num,irq_num,irq_num, _highmask, _isa_strayintr, \ IO_ICU/**/icu_num, ENABLE_ICU/**/icu_enables, reg,stray) /* * XXX - the mask (1 << 2) == IRQ_SLAVE will be generated for IRQ 2, instead * of the mask IRQ2 (defined as IRQ9 == (1 << 9)). But IRQ 2 "can't happen". * In fact, all stray interrupts "can't happen" except for bugs. The * "stray" IRQ 7 is documented behaviour of the 8259. It happens when there * is a glitch on any of its interrupt inputs. Does it really interrupt when * IRQ 7 is masked? * * XXX - unpend doesn't work for these, it sends them to the real handler. * * XXX - the race bug during initialization may be because I changed the * order of switching from the stray to the real interrupt handler to before * enabling interrupts. The old order looked unsafe but maybe it is OK with * the stray interrupt handler installed. But these handlers only reduce * the window of vulnerability - it is still open at the end of * isa_configure(). * * XXX - many comments are stale. */ STRAYINTR(0,1,1, al) STRAYINTR(1,1,1, al) STRAYINTR(2,1,1, al) STRAYINTR(3,1,1, al) STRAYINTR(4,1,1, al) STRAYINTR(5,1,1, al) STRAYINTR(6,1,1, al) STRAYINTR(8,2,1_AND_2, ah) STRAYINTR(9,2,1_AND_2, ah) STRAYINTR(10,2,1_AND_2, ah) STRAYINTR(11,2,1_AND_2, ah) STRAYINTR(12,2,1_AND_2, ah) STRAYINTR(13,2,1_AND_2, ah) STRAYINTR(14,2,1_AND_2, ah) STRAYINTR(15,2,1_AND_2, ah) IDTVEC(intrdefault) STRAYINTR(7,1,1, al) /* XXX */ #if 0 INTRSTRAY(255, _highmask, 255) ; call _isa_strayintr ; INTREXIT2 #endif /* * These are the interrupt counters, I moved them here from icu.s so that * they are with the name table. rgrimes * * There are now lots of counters, this has been redone to work with * Bruce Evans intr-0.1 code, which I modified some more to make it all * work with vmstat. */ .data Vresume: .space 16 * 4 /* where to resume intr handler after unpend */ .globl _intrcnt _intrcnt: /* used by vmstat to calc size of table */ .globl _intrcnt_bad7 _intrcnt_bad7: .space 4 /* glitches on irq 7 */ .globl _intrcnt_bad15 _intrcnt_bad15: .space 4 /* glitches on irq 15 */ .globl _intrcnt_stray _intrcnt_stray: .space 4 /* total count of stray interrupts */ .globl _intrcnt_actv _intrcnt_actv: .space NR_REAL_INT_HANDLERS * 4 /* active interrupts */ .globl _intrcnt_pend _intrcnt_pend: .space NR_REAL_INT_HANDLERS * 4 /* pending interrupts */ .globl _eintrcnt _eintrcnt: /* used by vmstat to calc size of table */ .globl _intrcnt_spl _intrcnt_spl: .space 32 * 4 /* XXX 32 should not be hard coded ? */ .globl _intrcnt_show _intrcnt_show: .space 8 * 4 /* XXX 16 should not be hard coded ? */ /* * Build the interrupt name table for vmstat */ #undef BUILD_FAST_VECTOR #define BUILD_FAST_VECTOR BUILD_VECTOR #undef BUILD_VECTOR #define BUILD_VECTOR(name, unit, irq_num, id_num, mask, handler, \ icu_num, icu_enables, reg) \ .ascii "name irq" ; \ .asciz "irq_num" /* * XXX - use the STRING and CONCAT macros from to stringize * and concatenate names above and elsewhere. */ .text .globl _intrnames, _eintrnames _intrnames: BUILD_VECTOR(bad,,7,,,,,,) BUILD_VECTOR(bad,,15,,,,,,) BUILD_VECTOR(stray,,,,,,,,) BUILD_VECTORS #undef BUILD_FAST_VECTOR #define BUILD_FAST_VECTOR BUILD_VECTOR #undef BUILD_VECTOR #define BUILD_VECTOR(name, unit, irq_num, id_num, mask, handler, \ icu_num, icu_enables, reg) \ .asciz "name pend" BUILD_VECTORS _eintrnames: /* * now the spl names */ .asciz "unpend_v" .asciz "doreti" .asciz "p0!ni" .asciz "!p0!ni" .asciz "p0ni" .asciz "netisr_raw" .asciz "netisr_ip" .asciz "netisr_imp" .asciz "netisr_ns" .asciz "netisr_iso" .asciz "softclock" /* 10 */ .asciz "trap" .asciz "doreti_exit2" .asciz "splbio" .asciz "splclock" .asciz "splhigh" .asciz "splimp" .asciz "splnet" .asciz "splsoftclock" .asciz "spltty" .asciz "spl0" /* 20 */ .asciz "netisr_raw2" .asciz "netisr_ip2" .asciz "netisr_imp2" .asciz "netisr_ns2" .asciz "netisr_iso2" .asciz "splx" .asciz "splx!0" .asciz "unpend_V" .asciz "spl29" /* spl29-spl31 are spares */ .asciz "spl30" .asciz "spl31" /* * now the mask names */ .asciz "cli" .asciz "cpl" .asciz "imen" .asciz "ipending" .asciz "sti" .asciz "mask5" /* mask5-mask7 are spares */ .asciz "mask6" .asciz "mask7" Index: head/sys/dev/fdc/fdcreg.h =================================================================== --- head/sys/dev/fdc/fdcreg.h (revision 618) +++ head/sys/dev/fdc/fdcreg.h (revision 619) @@ -1,72 +1,66 @@ /*- * 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. * - * @(#)fdreg.h 7.1 (Berkeley) 5/9/91 - * - * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE - * -------------------- ----- ---------------------- - * CURRENT PATCH LEVEL: 1 00153 - * -------------------- ----- ---------------------- - * - * 20 Apr 93 Julian Elischer Heavily re worked, see notes below + * from: @(#)fdreg.h 7.1 (Berkeley) 5/9/91 + * $Id$ */ /* * 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 */ Index: head/sys/dev/ic/i8237.h =================================================================== --- head/sys/dev/ic/i8237.h (revision 618) +++ head/sys/dev/ic/i8237.h (revision 619) @@ -1,9 +1,11 @@ /* * Intel 8237 DMA Controller + * + * $Id$ */ #define DMA37MD_SINGLE 0x40 /* single pass mode */ #define DMA37MD_CASCADE 0xc0 /* cascade mode */ #define DMA37MD_WRITE 0x04 /* read the device, write memory operation */ #define DMA37MD_READ 0x08 /* write the device, read memory operation */ Index: head/sys/dev/ic/nec765.h =================================================================== --- head/sys/dev/ic/nec765.h (revision 618) +++ head/sys/dev/ic/nec765.h (revision 619) @@ -1,71 +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. * - * @(#)nec765.h 7.1 (Berkeley) 5/9/91 + * 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 */ Index: head/sys/dev/ic/ns16550.h =================================================================== --- head/sys/dev/ic/ns16550.h (revision 618) +++ head/sys/dev/ic/ns16550.h (revision 619) @@ -1,50 +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. * - * @(#)ns16550.h 7.1 (Berkeley) 5/9/91 + * 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) */ Index: head/sys/dev/kbd/kbdtables.h =================================================================== --- head/sys/dev/kbd/kbdtables.h (revision 618) +++ head/sys/dev/kbd/kbdtables.h (revision 619) @@ -1,856 +1,858 @@ /* * Copyright (C) 1992, 1993 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@kmd-ac.dk * Tritonvej 36 UUCP: ...uunet!dkuug!kmd-ac!sos * DK9210 Aalborg SO Phone: +45 9814 8076 + * + * $Id$ */ #define META 0x80 /* eight bit for emacs META-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, NOP, NOP, 0x1B, 0x1B, NOP, NOP, 0x33, 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 */ '*', '*', '*', '*', '*', '*', '*', '*', 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, '.', '.', '.', '.', '.', '.', '.', 0x00, 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 */ '*', '*', '*', '*', '*', '*', '*', '*', 0x00, 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), F(54), 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, 0x1B, 0x1B, 0x00, 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, 0x7F, 0x7F, 0x00, 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 */ '\\', '|', 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 */ '*', '*', '*', '*', '*', '*', '*', '*', 0x00, 0x02, /* 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), F(54), 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, 0x1B, 0x1B, 0x00, 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, 0x7F, 0x7F, 0x00, 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 */ '*', '*', '*', '*', '*', '*', '*', '*', 0x00, 0x02, /* 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), F(54), 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, 0x1B, 0x1B, 0x00, 0x00, /* sc=02 */ '1', '!', NOP, NOP, NOP, NOP, NOP, NOP, 0x3F, 0x00, /* sc=03 */ '2', '"', NOP, NOP, NOP, '@', NOP, NOP, 0x3B, 0x00, /* sc=04 */ '3', 0xA3, NOP, NOP, NOP, '#', NOP, NOP, 0x3B, 0x00, /* sc=05 */ '4', '$', NOP, NOP, NOP, NOP, NOP, NOP, 0x3F, 0x00, /* sc=06 */ '5', '%', NOP, NOP, NOP, NOP, NOP, NOP, 0x3F, 0x00, /* sc=07 */ '6', '&', 0x1E, NOP, NOP, '^', 0x1E, NOP, 0x19, 0x00, /* sc=08 */ '7', '/', NOP, NOP, NOP, '&', NOP, NOP, 0x3B, 0x00, /* sc=09 */ '8', '(', NOP, NOP, NOP, '*', NOP, NOP, 0x3B, 0x00, /* sc=0a */ '9', ')', NOP, NOP, NOP, '(', NOP, NOP, 0x3B, 0x00, /* sc=0b */ '0', '=', NOP, NOP, NOP, ')', NOP, NOP, 0x3B, 0x00, /* sc=0c */ '+', '?', 0x1F, 0x1F, '-', '_', 0x1F, 0x1F, 0x00, 0x00, /* sc=0d */ 0xB4, '`', 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 */ 0xE5, 0xC5, NOP, NOP, '[', '{', 0x1B, NOP, 0x31, 0x01, /* sc=1b */ 0xA8, '^', NOP, NOP, ']', '}', 0x1D, NOP, 0x31, 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 */ 0xF8, 0xD8, NOP, NOP, ';', ':', NOP, NOP, 0x33, 0x01, /* sc=28 */ 0xE6, 0xC6, NOP, NOP, '\'', '"', NOP, NOP, 0x33, 0x01, /* sc=29 */ '<', '>', NOP, NOP, '\\', '|', 0x1C, NOP, 0x31, 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, 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, 0x7F, 0x7F, 0x00, 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 */ '*', '*', '*', '*', '*', '*', '*', '*', 0x00, 0x02, /* 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), F(54), 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, META|0x1B, META|0x1B, NOP, NOP, 0x33, 0x00, /* sc=02 */ '1', '!', NOP, NOP, META|'1', META|'!', NOP, NOP, 0x33, 0x00, /* sc=03 */ '2', '@', 0x00, 0x00, META|'2', META|'@', META|0x00, META|0x00, 0x00, 0x00, /* sc=04 */ '3', '#', NOP, NOP, META|'3', META|'#', NOP, NOP, 0x33, 0x00, /* sc=05 */ '4', '$', NOP, NOP, META|'4', META|'$', NOP, NOP, 0x33, 0x00, /* sc=06 */ '5', '%', NOP, NOP, META|'5', META|'%', NOP, NOP, 0x33, 0x00, /* sc=07 */ '6', '^', 0x1E, 0x1E, META|'6', META|'^', META|0x1E, META|0x1E, 0x00, 0x00, /* sc=08 */ '7', '&', NOP, NOP, META|'7', META|'&', NOP, NOP, 0x33, 0x00, /* sc=09 */ '8', '*', NOP, NOP, META|'8', META|'*', NOP, NOP, 0x33, 0x00, /* sc=0a */ '9', '(', NOP, NOP, META|'9', META|'(', NOP, NOP, 0x33, 0x00, /* sc=0b */ '0', ')', NOP, NOP, META|'0', META|')', NOP, NOP, 0x33, 0x00, /* sc=0c */ '-', '_', 0x1F, 0x1F, META|'-', META|'_', META|0x1F, META|0x1F, 0x00, 0x00, /* sc=0d */ '=', '+', NOP, NOP, META|'=', META|'+', NOP, NOP, 0x33, 0x00, /* sc=0e */ 0x08, 0x08, 0x7F, 0x7F, META|0x08, META|0x08, META|0x7F, META|0x7F, 0x00, 0x00, /* sc=0f */ 0x09, F(16), NOP, NOP, META|0x09, F(16), NOP, NOP, 0x77, 0x00, /* sc=10 */ 'q', 'Q', 0x11, 0x11, META|'q', META|'Q', META|0x11, META|0x11, 0x00, 0x01, /* sc=11 */ 'w', 'W', 0x17, 0x17, META|'w', META|'W', META|0x17, META|0x17, 0x00, 0x01, /* sc=12 */ 'e', 'E', 0x05, 0x05, META|'e', META|'E', META|0x05, META|0x05, 0x00, 0x01, /* sc=13 */ 'r', 'R', 0x12, 0x12, META|'r', META|'R', META|0x12, META|0x12, 0x00, 0x01, /* sc=14 */ 't', 'T', 0x14, 0x14, META|'t', META|'T', META|0x14, META|0x14, 0x00, 0x01, /* sc=15 */ 'y', 'Y', 0x19, 0x19, META|'y', META|'Y', META|0x19, META|0x19, 0x00, 0x01, /* sc=16 */ 'u', 'U', 0x15, 0x15, META|'u', META|'U', META|0x15, META|0x15, 0x00, 0x01, /* sc=17 */ 'i', 'I', 0x09, 0x09, META|'i', META|'I', META|0x09, META|0x09, 0x00, 0x01, /* sc=18 */ 'o', 'O', 0x0F, 0x0F, META|'o', META|'O', META|0x0F, META|0x0F, 0x00, 0x01, /* sc=19 */ 'p', 'P', 0x10, 0x10, META|'p', META|'P', META|0x10, META|0x10, 0x00, 0x01, /* sc=1a */ '[', '{', 0x1B, 0x1B, META|'[', META|'{', META|0x1B, META|0x1B, 0x00, 0x00, /* sc=1b */ ']', '}', 0x1D, 0x1D, META|']', META|'}', META|0x1D, META|0x1D, 0x00, 0x00, /* sc=1c */ 0x0D, 0x0D, 0x0A, 0x0A, META|0x0D, META|0x0D, META|0x0A, META|0x0A, 0x00, 0x00, /* sc=1d */ LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, 0xFF, 0x00, /* sc=1e */ 'a', 'A', 0x01, 0x01, META|'a', META|'A', META|0x01, META|0x01, 0x00, 0x01, /* sc=1f */ 's', 'S', 0x13, 0x13, META|'s', META|'S', META|0x13, META|0x13, 0x00, 0x01, /* sc=20 */ 'd', 'D', 0x04, 0x04, META|'d', META|'D', META|0x04, META|0x04, 0x00, 0x01, /* sc=21 */ 'f', 'F', 0x06, 0x06, META|'f', META|'F', META|0x06, META|0x06, 0x00, 0x01, /* sc=22 */ 'g', 'G', 0x07, 0x07, META|'g', META|'G', META|0x07, META|0x07, 0x00, 0x01, /* sc=23 */ 'h', 'H', 0x08, 0x08, META|'h', META|'H', META|0x08, META|0x08, 0x00, 0x01, /* sc=24 */ 'j', 'J', 0x0A, 0x0A, META|'j', META|'J', META|0x0A, META|0x0A, 0x00, 0x01, /* sc=25 */ 'k', 'K', 0x0B, 0x0B, META|'k', META|'K', META|0x0B, META|0x0B, 0x00, 0x01, /* sc=26 */ 'l', 'L', 0x0C, 0x0C, META|'l', META|'L', META|0x0C, META|0x0C, 0x00, 0x01, /* sc=27 */ ';', ':', NOP, NOP, META|';', META|':', NOP, NOP, 0x33, 0x00, /* sc=28 */ '\'', '"', NOP, NOP, META|'\'', META|'"', NOP, NOP, 0x33, 0x00, /* sc=29 */ '`', '~', NOP, NOP, META|'`', META|'~', NOP, NOP, 0x33, 0x00, /* sc=2a */ LSH, LSH, LSH, LSH, LSH, LSH, LSH, LSH, 0xFF, 0x00, /* sc=2b */ '\\', '|', 0x1C, 0x1C, META|'\\', META|'|', META|0x1C, META|0x1C, 0x00, 0x00, /* sc=2c */ 'z', 'Z', 0x1A, 0x1A, META|'z', META|'Z', META|0x1A, META|0x1A, 0x00, 0x01, /* sc=2d */ 'x', 'X', 0x18, 0x18, META|'x', META|'X', META|0x18, META|0x18, 0x00, 0x01, /* sc=2e */ 'c', 'C', 0x03, 0x03, META|'c', META|'C', META|0x03, META|0x03, 0x00, 0x01, /* sc=2f */ 'v', 'V', 0x16, 0x16, META|'v', META|'V', META|0x16, META|0x16, 0x00, 0x01, /* sc=30 */ 'b', 'B', 0x02, 0x02, META|'b', META|'B', META|0x02, META|0x02, 0x00, 0x01, /* sc=31 */ 'n', 'N', 0x0E, 0x0E, META|'n', META|'N', META|0x0E, META|0x0E, 0x00, 0x01, /* sc=32 */ 'm', 'M', 0x0D, 0x0D, META|'m', META|'M', META|0x0D, META|0x0D, 0x00, 0x01, /* sc=33 */ ',', '<', NOP, NOP, META|',', META|'<', NOP, NOP, 0x33, 0x00, /* sc=34 */ '.', '>', NOP, NOP, META|'.', META|'>', NOP, NOP, 0x33, 0x00, /* sc=35 */ '/', '?', NOP, NOP, META|'/', META|'?', NOP, NOP, 0x33, 0x00, /* sc=36 */ ASH, RSH, RSH, RSH, RSH, RSH, RSH, RSH, 0xFF, 0x00, /* sc=37 */ '*', '*', 0x0A, 0x0A, META|'*', META|'*', META|0x0A, META|0x0A, 0x00, 0x00, /* sc=38 */ LALT, LALT, LALT, LALT, LALT, LALT, LALT, LALT, 0xFF, 0x00, /* sc=39 */ ' ', ' ', ' ', ' ', META|' ', META|' ', META|' ', META|' ', 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', META|'7', META|'7', META|'7', META|'7', 0x80, 0x02, /* sc=48 */ F(50), '8', '8', '8', META|'8', META|'8', META|'8', META|'8', 0x80, 0x02, /* sc=49 */ F(51), '9', '9', '9', META|'9', META|'9', META|'9', META|'9', 0x80, 0x02, /* sc=4a */ F(52), '-', '-', '-', META|'-', META|'-', META|'-', META|'-', 0x80, 0x02, /* sc=4b */ F(53), '4', '4', '4', META|'4', META|'4', META|'4', META|'4', 0x80, 0x02, /* sc=4c */ F(48), '5', '5', '5', META|'5', META|'5', META|'5', META|'5', 0x80, 0x02, /* sc=4d */ F(55), '6', '6', '6', META|'6', META|'6', META|'6', META|'6', 0x80, 0x02, /* sc=4e */ F(56), '+', '+', '+', META|'+', META|'+', META|'+', META|'+', 0x80, 0x02, /* sc=4f */ F(57), '1', '1', '1', META|'1', META|'1', META|'1', META|'1', 0x80, 0x02, /* sc=50 */ F(58), '2', '2', '2', META|'2', META|'2', META|'2', META|'2', 0x80, 0x02, /* sc=51 */ F(59), '3', '3', '3', META|'3', META|'3', META|'3', META|'3', 0x80, 0x02, /* sc=52 */ F(60), '0', '0', '0', META|'0', META|'0', META|'0', META|'0', 0x80, 0x02, /* sc=53 */ F(54), '.', 0x7F, 0x7F, META|0x7F, META|0x7F, META|0x7F, META|0x7F, 0x80, 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, META|0x0D, META|0x0D, META|0x0A, META|0x0A, 0x00, 0x00, /* sc=5a */ RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, 0xFF, 0x00, /* sc=5b */ '/', '/', NOP, NOP, META|'/', META|'/', NOP, NOP, 0x33, 0x00, /* sc=5c */ CLK, ALK, ALK, ALK, ALK, ALK, ALK, ALK, 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, META|0x7F, META|0x7F, META|0x7F, META|0x7F, 0xC0, 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, META|0x1B, META|0x1B, NOP, NOP, 0x33, 0x00, /* sc=02 */ '!', '1', NOP, NOP, META|'1', META|'!', NOP, NOP, 0x33, 0x00, /* sc=03 */ '"', '2', 0x00, 0x00, META|'2', META|'@', META|0x00, META|0x00, 0x00, 0x00, /* sc=04 */ '\'', '3', NOP, NOP, META|'3', META|'#', NOP, NOP, 0x33, 0x00, /* sc=05 */ ';', '4', NOP, NOP, META|'4', META|'$', NOP, NOP, 0x33, 0x00, /* sc=06 */ ':', '5', NOP, NOP, META|'5', META|'%', NOP, NOP, 0x33, 0x00, /* sc=07 */ ',', '6', 0x1E, 0x1E, META|'6', META|'^', META|0x1E, META|0x1E, 0x00, 0x00, /* sc=08 */ '.', '7', NOP, NOP, META|'7', META|'&', NOP, NOP, 0x33, 0x00, /* sc=09 */ '*', '8', NOP, NOP, META|'8', META|'*', NOP, NOP, 0x33, 0x00, /* sc=0a */ '(', '9', NOP, NOP, META|'9', META|'(', NOP, NOP, 0x33, 0x00, /* sc=0b */ ')', '0', NOP, NOP, META|'0', META|')', NOP, NOP, 0x33, 0x00, /* sc=0c */ '_', '-', 0x1F, 0x1F, META|'-', META|'_', META|0x1F, META|0x1F, 0x00, 0x00, /* sc=0d */ '+', '=', NOP, NOP, META|'=', META|'+', NOP, NOP, 0x33, 0x00, /* sc=0e */ 0x08, 0x08, 0x7F, 0x7F, META|0x08, META|0x08, META|0x7F, META|0x7F, 0x00, 0x00, /* sc=0f */ 0x09, F(16), NOP, NOP, META|0x09, F(16), NOP, NOP, 0x77, 0x00, /* sc=10 */ 0xca, 0xea, 0x11, 0x11, META|'q', META|'Q', META|0x11, META|0x11, 0x00, 0x01, /* sc=11 */ 0xc3, 0xe3, 0x17, 0x17, META|'w', META|'W', META|0x17, META|0x17, 0x00, 0x01, /* sc=12 */ 0xd5, 0xf5, 0x05, 0x05, META|'e', META|'E', META|0x05, META|0x05, 0x00, 0x01, /* sc=13 */ 0xcb, 0xeb, 0x12, 0x12, META|'r', META|'R', META|0x12, META|0x12, 0x00, 0x01, /* sc=14 */ 0xc5, 0xe5, 0x14, 0x14, META|'t', META|'T', META|0x14, META|0x14, 0x00, 0x01, /* sc=15 */ 0xce, 0xee, 0x19, 0x19, META|'y', META|'Y', META|0x19, META|0x19, 0x00, 0x01, /* sc=16 */ 0xc7, 0xe7, 0x15, 0x15, META|'u', META|'U', META|0x15, META|0x15, 0x00, 0x01, /* sc=17 */ 0xdb, 0xfb, 0x09, 0x09, META|'i', META|'I', META|0x09, META|0x09, 0x00, 0x01, /* sc=18 */ 0xdd, 0xfd, 0x0F, 0x0F, META|'o', META|'O', META|0x0F, META|0x0F, 0x00, 0x01, /* sc=19 */ 0xda, 0xfa, 0x10, 0x10, META|'p', META|'P', META|0x10, META|0x10, 0x00, 0x01, /* sc=1a */ 0xc8, 0xe8, 0x1B, 0x1B, META|'[', META|'{', META|0x1B, META|0x1B, 0x00, 0x01, /* sc=1b */ 0xdf, 0xff, 0x1D, 0x1D, META|']', META|'}', META|0x1D, META|0x1D, 0x00, 0x01, /* sc=1c */ 0x0D, 0x0D, 0x0A, 0x0A, META|0x0D, META|0x0D, META|0x0A, META|0x0A, 0x00, 0x00, /* sc=1d */ LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, 0xFF, 0x00, /* sc=1e */ 0xc6, 0xe6, 0x01, 0x01, META|'a', META|'A', META|0x01, META|0x01, 0x00, 0x01, /* sc=1f */ 0xd9, 0xf9, 0x13, 0x13, META|'s', META|'S', META|0x13, META|0x13, 0x00, 0x01, /* sc=20 */ 0xd7, 0xf7, 0x04, 0x04, META|'d', META|'D', META|0x04, META|0x04, 0x00, 0x01, /* sc=21 */ 0xc1, 0xe1, 0x06, 0x06, META|'f', META|'F', META|0x06, META|0x06, 0x00, 0x01, /* sc=22 */ 0xd0, 0xf0, 0x07, 0x07, META|'g', META|'G', META|0x07, META|0x07, 0x00, 0x01, /* sc=23 */ 0xd2, 0xf2, 0x08, 0x08, META|'h', META|'H', META|0x08, META|0x08, 0x00, 0x01, /* sc=24 */ 0xcf, 0xef, 0x0A, 0x0A, META|'j', META|'J', META|0x0A, META|0x0A, 0x00, 0x01, /* sc=25 */ 0xcc, 0xec, 0x0B, 0x0B, META|'k', META|'K', META|0x0B, META|0x0B, 0x00, 0x01, /* sc=26 */ 0xc4, 0xe4, 0x0C, 0x0C, META|'l', META|'L', META|0x0C, META|0x0C, 0x00, 0x01, /* sc=27 */ 0xd6, 0xf6, NOP, NOP, META|';', META|':', NOP, NOP, 0x33, 0x01, /* sc=28 */ 0xdc, 0xfc, NOP, NOP, META|'\'', META|'"', NOP, NOP, 0x33, 0x01, /* sc=29 */ 0xa3, 0xb3, NOP, NOP, META|'`', META|'~', NOP, NOP, 0x33, 0x01, /* sc=2a */ LSH, LSH, LSH, LSH, LSH, LSH, LSH, LSH, 0xFF, 0x00, /* sc=2b */ '\\', '|', 0x1C, 0x1C, META|'\\', META|'|', META|0x1C, META|0x1C, 0x00, 0x00, /* sc=2c */ 0xd1, 0xf1, 0x1A, 0x1A, META|'z', META|'Z', META|0x1A, META|0x1A, 0x00, 0x01, /* sc=2d */ 0xde, 0xfe, 0x18, 0x18, META|'x', META|'X', META|0x18, META|0x18, 0x00, 0x01, /* sc=2e */ 0xd3, 0xf3, 0x03, 0x03, META|'c', META|'C', META|0x03, META|0x03, 0x00, 0x01, /* sc=2f */ 0xcd, 0xed, 0x16, 0x16, META|'v', META|'V', META|0x16, META|0x16, 0x00, 0x01, /* sc=30 */ 0xc9, 0xe9, 0x02, 0x02, META|'b', META|'B', META|0x02, META|0x02, 0x00, 0x01, /* sc=31 */ 0xd4, 0xf4, 0x0E, 0x0E, META|'n', META|'N', META|0x0E, META|0x0E, 0x00, 0x01, /* sc=32 */ 0xd8, 0xf8, 0x0D, 0x0D, META|'m', META|'M', META|0x0D, META|0x0D, 0x00, 0x01, /* sc=33 */ 0xc2, 0xe2, NOP, NOP, META|',', META|'<', NOP, NOP, 0x33, 0x01, /* sc=34 */ 0xc0, 0xe0, NOP, NOP, META|'.', META|'>', NOP, NOP, 0x33, 0x01, /* sc=35 */ '/', '?', NOP, NOP, META|'/', META|'?', NOP, NOP, 0x33, 0x00, /* sc=36 */ ASH, RSH, RSH, RSH, RSH, RSH, RSH, RSH, 0xFF, 0x00, /* sc=37 */ '*', '*', 0x0A, 0x0A, META|'*', META|'*', META|0x0A, META|0x0A, 0x00, 0x00, /* sc=38 */ LALT, LALT, LALT, LALT, LALT, LALT, LALT, LALT, 0xFF, 0x00, /* sc=39 */ ' ', ' ', ' ', ' ', META|' ', META|' ', META|' ', META|' ', 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', META|'7', META|'7', META|'7', META|'7', 0x80, 0x02, /* sc=48 */ F(50), '8', '8', '8', META|'8', META|'8', META|'8', META|'8', 0x80, 0x02, /* sc=49 */ F(51), '9', '9', '9', META|'9', META|'9', META|'9', META|'9', 0x80, 0x02, /* sc=4a */ F(52), '-', '-', '-', META|'-', META|'-', META|'-', META|'-', 0x80, 0x02, /* sc=4b */ F(53), '4', '4', '4', META|'4', META|'4', META|'4', META|'4', 0x80, 0x02, /* sc=4c */ F(48), '5', '5', '5', META|'5', META|'5', META|'5', META|'5', 0x80, 0x02, /* sc=4d */ F(55), '6', '6', '6', META|'6', META|'6', META|'6', META|'6', 0x80, 0x02, /* sc=4e */ F(56), '+', '+', '+', META|'+', META|'+', META|'+', META|'+', 0x80, 0x02, /* sc=4f */ F(57), '1', '1', '1', META|'1', META|'1', META|'1', META|'1', 0x80, 0x02, /* sc=50 */ F(58), '2', '2', '2', META|'2', META|'2', META|'2', META|'2', 0x80, 0x02, /* sc=51 */ F(59), '3', '3', '3', META|'3', META|'3', META|'3', META|'3', 0x80, 0x02, /* sc=52 */ F(60), '0', '0', '0', META|'0', META|'0', META|'0', META|'0', 0x80, 0x02, /* sc=53 */ F(54), '.', 0x7F, 0x7F, META|0x7F, META|0x7F, META|0x7F, META|0x7F, 0x80, 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, META|0x0D, META|0x0D, META|0x0A, META|0x0A, 0x00, 0x00, /* sc=5a */ RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, 0xFF, 0x00, /* sc=5b */ '/', '/', NOP, NOP, META|'/', META|'/', NOP, NOP, 0x33, 0x00, /* sc=5c */ CLK, ALK, ALK, ALK, ALK, ALK, ALK, ALK, 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, META|0x7F, META|0x7F, META|0x7F, META|0x7F, 0xC0, 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, NOP, NOP, 0x1B, 0x1B, NOP, NOP, 0x33, 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, 0x7F, 0x7F, 0x00, 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 */ '*', '*', '*', '*', '*', '*', '*', '*', 0x00, 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), F(54), 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} }; Index: head/sys/dev/mcd/mcd.c =================================================================== --- head/sys/dev/mcd/mcd.c (revision 618) +++ head/sys/dev/mcd/mcd.c (revision 619) @@ -1,1261 +1,1260 @@ /* * Copyright 1993 by Holger Veit (data part) * Copyright 1993 by Brian Moore (audio part) * 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 software was developed by Holger Veit and Brian Moore * for use with "386BSD" and similar operating systems. * "Similar operating systems" includes mainly non-profit oriented * systems for research and education, including but not restricted to * "NetBSD", "FreeBSD", "Mach" (by CMU). * 4. Neither the name of the developer(s) nor the name "386BSD" * may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER(S) ``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 DEVELOPER(S) 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$ + * $Id: mcd.c,v 1.1 1993/10/12 06:08:29 rgrimes Exp $ */ -/*static char rcsid[] = "from: /sys/i386/isa/RCS/mcd.c,v 2.1 1993/09/24 21:23:13 root Exp root";*/ static char COPYRIGHT[] = "mcd-driver (C)1993 by H.Veit & B.Moore"; #include "mcd.h" #if NMCD > 0 #include "types.h" #include "param.h" #include "systm.h" #include "conf.h" #include "file.h" #include "buf.h" #include "stat.h" #include "uio.h" #include "ioctl.h" #include "cdio.h" #include "errno.h" #include "dkbad.h" #include "disklabel.h" #include "i386/isa/isa.h" #include "i386/isa/isa_device.h" #include "mcdreg.h" /* user definable options */ /*#define MCD_TO_WARNING_ON*/ /* define to get timeout messages */ /*#define MCDMINI*/ /* define for a mini configuration for boot kernel */ #ifdef MCDMINI #define MCD_TRACE(fmt,a,b,c,d) #ifdef MCD_TO_WARNING_ON #undef MCD_TO_WARNING_ON #endif #else #define MCD_TRACE(fmt,a,b,c,d) {if (mcd_data[unit].debug) {printf("mcd%d st=%02x: ",unit,mcd_data[unit].status); printf(fmt,a,b,c,d);}} #endif #define mcd_part(dev) ((minor(dev)) & 7) #define mcd_unit(dev) (((minor(dev)) & 0x38) >> 3) #define mcd_phys(dev) (((minor(dev)) & 0x40) >> 6) #define RAW_PART 3 /* flags */ #define MCDOPEN 0x0001 /* device opened */ #define MCDVALID 0x0002 /* parameters loaded */ #define MCDINIT 0x0004 /* device is init'd */ #define MCDWAIT 0x0008 /* waiting for something */ #define MCDLABEL 0x0010 /* label is read */ #define MCDPROBING 0x0020 /* probing */ #define MCDREADRAW 0x0040 /* read raw mode (2352 bytes) */ #define MCDVOLINFO 0x0080 /* already read volinfo */ #define MCDTOC 0x0100 /* already read toc */ #define MCDMBXBSY 0x0200 /* local mbx is busy */ /* status */ #define MCDAUDIOBSY MCD_ST_AUDIOBSY /* playing audio */ #define MCDDSKCHNG MCD_ST_DSKCHNG /* sensed change of disk */ #define MCDDSKIN MCD_ST_DSKIN /* sensed disk in drive */ #define MCDDOOROPEN MCD_ST_DOOROPEN /* sensed door open */ /* toc */ #define MCD_MAXTOCS 104 /* from the Linux driver */ #define MCD_LASTPLUS1 170 /* special toc entry */ struct mcd_mbx { short unit; short port; short retry; short nblk; int sz; u_long skip; struct buf *bp; int p_offset; short count; }; struct mcd_data { short config; short flags; short status; int blksize; u_long disksize; int iobase; struct disklabel dlabel; int partflags[MAXPARTITIONS]; int openflags; struct mcd_volinfo volinfo; #ifndef MCDMINI struct mcd_qchninfo toc[MCD_MAXTOCS]; short audio_status; struct mcd_read2 lastpb; #endif short debug; struct buf head; /* head of buf queue */ struct mcd_mbx mbx; } mcd_data[NMCD]; /* reader state machine */ #define MCD_S_BEGIN 0 #define MCD_S_BEGIN1 1 #define MCD_S_WAITSTAT 2 #define MCD_S_WAITMODE 3 #define MCD_S_WAITREAD 4 /* prototypes */ int mcdopen(dev_t dev); int mcdclose(dev_t dev); int mcdstrategy(struct buf *bp); int mcdioctl(dev_t dev, int cmd, caddr_t addr, int flags); int mcdsize(dev_t dev); static void mcd_done(struct mcd_mbx *mbx); static void mcd_start(int unit); static int mcd_getdisklabel(int unit); static void mcd_configure(struct mcd_data *cd); static int mcd_get(int unit, char *buf, int nmax); static void mcd_setflags(int unit,struct mcd_data *cd); static int mcd_getstat(int unit,int sflg); static int mcd_send(int unit, int cmd,int nretrys); static int bcd2bin(bcd_t b); static bcd_t bin2bcd(int b); static void hsg2msf(int hsg, bcd_t *msf); static int msf2hsg(bcd_t *msf); static int mcd_volinfo(int unit); static int mcd_waitrdy(int port,int dly); static void mcd_doread(int state, struct mcd_mbx *mbxin); #ifndef MCDMINI static int mcd_setmode(int unit, int mode); static int mcd_getqchan(int unit, struct mcd_qchninfo *q); static int mcd_subchan(int unit, struct ioc_read_subchannel *sc); static int mcd_toc_header(int unit, struct ioc_toc_header *th); static int mcd_read_toc(int unit); static int mcd_toc_entry(int unit, struct ioc_read_toc_entry *te); static int mcd_stop(int unit); static int mcd_playtracks(int unit, struct ioc_play_track *pt); static int mcd_play(int unit, struct mcd_read2 *pb); static int mcd_pause(int unit); static int mcd_resume(int unit); #endif extern int hz; extern int mcd_probe(struct isa_device *dev); extern int mcd_attach(struct isa_device *dev); struct isa_driver mcddriver = { mcd_probe, mcd_attach, "mcd" }; #define mcd_put(port,byte) outb(port,byte) #define MCD_RETRYS 5 #define MCD_RDRETRYS 8 #define MCDBLK 2048 /* for cooked mode */ #define MCDRBLK 2352 /* for raw mode */ /* several delays */ #define RDELAY_WAITSTAT 300 #define RDELAY_WAITMODE 300 #define RDELAY_WAITREAD 800 #define DELAY_STATUS 10000l /* 10000 * 1us */ #define DELAY_GETREPLY 200000l /* 200000 * 2us */ #define DELAY_SEEKREAD 20000l /* 20000 * 1us */ #define mcd_delay DELAY int mcd_attach(struct isa_device *dev) { struct mcd_data *cd = mcd_data + dev->id_unit; int i; cd->iobase = dev->id_iobase; cd->flags |= MCDINIT; cd->openflags = 0; for (i=0; ipartflags[i] = 0; #ifdef NOTYET /* wire controller for interrupts and dma */ mcd_configure(cd); #endif return 1; } int mcdopen(dev_t dev) { int unit,part,phys; struct mcd_data *cd; unit = mcd_unit(dev); if (unit >= NMCD) return ENXIO; cd = mcd_data + unit; part = mcd_part(dev); phys = mcd_phys(dev); /* not initialized*/ if (!(cd->flags & MCDINIT)) return ENXIO; /* invalidated in the meantime? mark all open part's invalid */ if (!(cd->flags & MCDVALID) && cd->openflags) return ENXIO; if (mcd_getstat(unit,1) < 0) return ENXIO; /* XXX get a default disklabel */ mcd_getdisklabel(unit); if (mcdsize(dev) < 0) { printf("mcd%d: failed to get disk size\n",unit); return ENXIO; } else cd->flags |= MCDVALID; MCD_TRACE("open: partition=%d, disksize = %d, blksize=%d\n", part,cd->disksize,cd->blksize,0); if (part == RAW_PART || (part < cd->dlabel.d_npartitions && cd->dlabel.d_partitions[part].p_fstype != FS_UNUSED)) { cd->partflags[part] |= MCDOPEN; cd->openflags |= (1<partflags[part] |= MCDREADRAW; return 0; } return ENXIO; } int mcdclose(dev_t dev) { int unit,part,phys; struct mcd_data *cd; unit = mcd_unit(dev); if (unit >= NMCD) return ENXIO; cd = mcd_data + unit; part = mcd_part(dev); phys = mcd_phys(dev); if (!(cd->flags & MCDINIT)) return ENXIO; mcd_getstat(unit,1); /* get status */ /* close channel */ cd->partflags[part] &= ~(MCDOPEN|MCDREADRAW); cd->openflags &= ~(1<b_dev); cd = mcd_data + unit; /* test validity */ /*MCD_TRACE("strategy: buf=0x%lx, unit=%ld, block#=%ld bcount=%ld\n", bp,unit,bp->b_blkno,bp->b_bcount);*/ if (unit >= NMCD || bp->b_blkno < 0) { printf("mcdstrategy: unit = %d, blkno = %d, bcount = %d\n", unit, bp->b_blkno, bp->b_bcount); pg("mcd: mcdstratregy failure"); bp->b_error = EINVAL; bp->b_flags |= B_ERROR; goto bad; } /* if device invalidated (e.g. media change, door open), error */ if (!(cd->flags & MCDVALID)) { MCD_TRACE("strategy: drive not valid\n",0,0,0,0); bp->b_error = EIO; goto bad; } /* read only */ if (!(bp->b_flags & B_READ)) { bp->b_error = EROFS; goto bad; } /* no data to read */ if (bp->b_bcount == 0) goto done; /* for non raw access, check partition limits */ if (mcd_part(bp->b_dev) != RAW_PART) { if (!(cd->flags & MCDLABEL)) { bp->b_error = EIO; goto bad; } /* adjust transfer if necessary */ if (bounds_check_with_label(bp,&cd->dlabel,1) <= 0) { goto done; } } /* queue it */ qp = &cd->head; s = splbio(); disksort(qp,bp); splx(s); /* now check whether we can perform processing */ mcd_start(unit); return; bad: bp->b_flags |= B_ERROR; done: bp->b_resid = bp->b_bcount; biodone(bp); return; } static void mcd_start(int unit) { struct mcd_data *cd = mcd_data + unit; struct buf *bp, *qp = &cd->head; struct partition *p; int part; register s = splbio(); if (cd->flags & MCDMBXBSY) return; if ((bp = qp->b_actf) != 0) { /* block found to process, dequeue */ /*MCD_TRACE("mcd_start: found block bp=0x%x\n",bp,0,0,0);*/ qp->b_actf = bp->av_forw; splx(s); } else { /* nothing to do */ splx(s); return; } /* changed media? */ if (!(cd->flags & MCDVALID)) { MCD_TRACE("mcd_start: drive not valid\n",0,0,0,0); return; } p = cd->dlabel.d_partitions + mcd_part(bp->b_dev); cd->flags |= MCDMBXBSY; cd->mbx.unit = unit; cd->mbx.port = cd->iobase; cd->mbx.retry = MCD_RETRYS; cd->mbx.bp = bp; cd->mbx.p_offset = p->p_offset; /* calling the read routine */ mcd_doread(MCD_S_BEGIN,&(cd->mbx)); /* triggers mcd_start, when successful finished */ return; } int mcdioctl(dev_t dev, int cmd, caddr_t addr, int flags) { struct mcd_data *cd; int unit,part; unit = mcd_unit(dev); part = mcd_part(dev); cd = mcd_data + unit; #ifdef MCDMINI return ENOTTY; #else if (!(cd->flags & MCDVALID)) return EIO; MCD_TRACE("ioctl called 0x%x\n",cmd,0,0,0); switch (cmd) { case DIOCSBAD: return EINVAL; case DIOCGDINFO: case DIOCGPART: case DIOCWDINFO: case DIOCSDINFO: case DIOCWLABEL: return ENOTTY; case CDIOCPLAYTRACKS: return mcd_playtracks(unit, (struct ioc_play_track *) addr); case CDIOCPLAYBLOCKS: return mcd_play(unit, (struct mcd_read2 *) addr); case CDIOCREADSUBCHANNEL: return mcd_subchan(unit, (struct ioc_read_subchannel *) addr); case CDIOREADTOCHEADER: return mcd_toc_header(unit, (struct ioc_toc_header *) addr); case CDIOREADTOCENTRYS: return mcd_toc_entry(unit, (struct ioc_read_toc_entry *) addr); case CDIOCSETPATCH: case CDIOCGETVOL: case CDIOCSETVOL: case CDIOCSETMONO: case CDIOCSETSTERIO: case CDIOCSETMUTE: case CDIOCSETLEFT: case CDIOCSETRIGHT: return EINVAL; case CDIOCRESUME: return mcd_resume(unit); case CDIOCPAUSE: return mcd_pause(unit); case CDIOCSTART: return EINVAL; case CDIOCSTOP: return mcd_stop(unit); case CDIOCEJECT: return EINVAL; case CDIOCSETDEBUG: cd->debug = 1; return 0; case CDIOCCLRDEBUG: cd->debug = 0; return 0; case CDIOCRESET: return EINVAL; default: return ENOTTY; } /*NOTREACHED*/ #endif /*!MCDMINI*/ } /* this could have been taken from scsi/cd.c, but it is not clear * whether the scsi cd driver is linked in */ static int mcd_getdisklabel(int unit) { struct mcd_data *cd = mcd_data + unit; if (cd->flags & MCDLABEL) return -1; bzero(&cd->dlabel,sizeof(struct disklabel)); strncpy(cd->dlabel.d_typename,"Mitsumi CD ROM ",16); strncpy(cd->dlabel.d_packname,"unknown ",16); cd->dlabel.d_secsize = cd->blksize; cd->dlabel.d_nsectors = 100; cd->dlabel.d_ntracks = 1; cd->dlabel.d_ncylinders = (cd->disksize/100)+1; cd->dlabel.d_secpercyl = 100; cd->dlabel.d_secperunit = cd->disksize; cd->dlabel.d_rpm = 300; cd->dlabel.d_interleave = 1; cd->dlabel.d_flags = D_REMOVABLE; cd->dlabel.d_npartitions= 1; cd->dlabel.d_partitions[0].p_offset = 0; cd->dlabel.d_partitions[0].p_size = cd->disksize; cd->dlabel.d_partitions[0].p_fstype = 9; cd->dlabel.d_magic = DISKMAGIC; cd->dlabel.d_magic2 = DISKMAGIC; cd->dlabel.d_checksum = dkcksum(&cd->dlabel); cd->flags |= MCDLABEL; return 0; } int mcdsize(dev_t dev) { int size; int unit = mcd_unit(dev); struct mcd_data *cd = mcd_data + unit; if (mcd_volinfo(unit) >= 0) { cd->blksize = MCDBLK; size = msf2hsg(cd->volinfo.vol_msf); cd->disksize = size * (MCDBLK/DEV_BSIZE); return 0; } return -1; } /*************************************************************** * lower level of driver starts here **************************************************************/ #ifdef NOTDEF static char irqs[] = { 0x00,0x00,0x10,0x20,0x00,0x30,0x00,0x00, 0x00,0x10,0x40,0x50,0x00,0x00,0x00,0x00 }; static char drqs[] = { 0x00,0x01,0x00,0x03,0x00,0x05,0x06,0x07, }; #endif static void mcd_configure(struct mcd_data *cd) { outb(cd->iobase+mcd_config,cd->config); } /* check if there is a cdrom */ /* Heavly hacked by gclarkii@sugar.neosoft.com */ int mcd_probe(struct isa_device *dev) { int port = dev->id_iobase; int unit = dev->id_unit; int i; int st; int check; int junk; mcd_data[unit].flags = MCDPROBING; #ifdef NOTDEF /* get irq/drq configuration word */ mcd_data[unit].config = irqs[dev->id_irq]; /* | drqs[dev->id_drq];*/ #else mcd_data[unit].config = 0; #endif /* send a reset */ outb(port+MCD_FLAGS,0); DELAY(100000); /* get any pending status and throw away...*/ for (i=10; i != 0; i--) { inb(port+MCD_DATA); } DELAY(1000); outb(port+MCD_DATA,MCD_CMDGETSTAT); /* Send get status command */ /* Loop looking for avail of status */ /* XXX May have to increase for fast machinces */ for (i = 1000; i != 0; i--) { if ((inb(port+MCD_FLAGS) & 0xF ) == STATUS_AVAIL) { break; } DELAY(10); } /* get status */ if (i == 0) { #ifdef DEBUG printf ("Mitsumi drive NOT detected\n"); #endif return 0; } /* * The following code uses the 0xDC command, it returns a M from the * second byte and a number in the third. Does anyone know what the * number is for? Better yet, how about someone thats REAL good in * i80x86 asm looking at the Dos driver... Most of this info came * from a friend of mine spending a whole weekend..... */ DELAY (2000); outb(port+MCD_DATA,MCD_CMDCONTINFO); for (i = 0; i < 100000; i++) { if ((inb(port+MCD_FLAGS) & 0xF) == STATUS_AVAIL) break; } if (i > 100000) { #ifdef DEBUG printf ("Mitsumi drive error\n"); #endif return 0; } DELAY (40000); st = inb(port+MCD_DATA); DELAY (500); check = inb(port+MCD_DATA); DELAY (500); junk = inb(port+MCD_DATA); /* What is byte used for?!?!? */ if (check = 'M') { #ifdef DEBUG printf("Mitsumi drive detected\n"); #endif return 4; } else { printf("Mitsumi drive NOT detected\n"); printf("Mitsumi drive error\n"); return 0; } } static int mcd_waitrdy(int port,int dly) { int i; /* wait until xfer port senses data ready */ for (i=0; iiobase; /* wait data to become ready */ if (mcd_waitrdy(port,dly)<0) { #ifdef MCD_TO_WARNING_ON printf("mcd%d: timeout getreply\n",unit); #endif return -1; } /* get the data */ return inb(port+mcd_status) & 0xFF; } static int mcd_getstat(int unit,int sflg) { int i; struct mcd_data *cd = mcd_data + unit; int port = cd->iobase; /* get the status */ if (sflg) outb(port+mcd_command, MCD_CMDGETSTAT); i = mcd_getreply(unit,DELAY_GETREPLY); if (i<0) return -1; cd->status = i; mcd_setflags(unit,cd); return cd->status; } static void mcd_setflags(int unit, struct mcd_data *cd) { /* check flags */ if (cd->status & (MCDDSKCHNG|MCDDOOROPEN)) { MCD_TRACE("getstat: sensed DSKCHNG or DOOROPEN\n",0,0,0,0); cd->flags &= ~MCDVALID; } #ifndef MCDMINI if (cd->status & MCDAUDIOBSY) cd->audio_status = CD_AS_PLAY_IN_PROGRESS; else if (cd->audio_status == CD_AS_PLAY_IN_PROGRESS) cd->audio_status = CD_AS_PLAY_COMPLETED; #endif } static int mcd_get(int unit, char *buf, int nmax) { int port = mcd_data[unit].iobase; int i,k; for (i=0; i> 4) * 10 + (b & 15); } static bcd_t bin2bcd(int b) { return ((b / 10) << 4) | (b % 10); } static void hsg2msf(int hsg, bcd_t *msf) { hsg += 150; M_msf(msf) = bin2bcd(hsg / 4500); hsg %= 4500; S_msf(msf) = bin2bcd(hsg / 75); F_msf(msf) = bin2bcd(hsg % 75); } static int msf2hsg(bcd_t *msf) { return (bcd2bin(M_msf(msf)) * 60 + bcd2bin(S_msf(msf))) * 75 + bcd2bin(F_msf(msf)) - 150; } static int mcd_volinfo(int unit) { struct mcd_data *cd = mcd_data + unit; int i; /*MCD_TRACE("mcd_volinfo: enter\n",0,0,0,0);*/ /* Get the status, in case the disc has been changed */ if (mcd_getstat(unit, 1) < 0) return EIO; /* Just return if we already have it */ if (cd->flags & MCDVOLINFO) return 0; /* send volume info command */ if (mcd_send(unit,MCD_CMDGETVOLINFO,MCD_RETRYS) < 0) return -1; /* get data */ if (mcd_get(unit,(char*) &cd->volinfo,sizeof(struct mcd_volinfo)) < 0) { printf("mcd%d: mcd_volinfo: error read data\n",unit); return -1; } if (cd->volinfo.trk_low != 0 || cd->volinfo.trk_high != 0) { cd->flags |= MCDVOLINFO; /* volinfo is OK */ return 0; } return -1; } int mcdintr(unit) { int port = mcd_data[unit].iobase; u_int i; MCD_TRACE("stray interrupt xfer=0x%x\n",inb(port+mcd_xfer),0,0,0); /* just read out status and ignore the rest */ if ((inb(port+mcd_xfer)&0xFF) != 0xFF) { i = inb(port+mcd_status); } } /* state machine to process read requests * initialize with MCD_S_BEGIN: calculate sizes, and read status * MCD_S_WAITSTAT: wait for status reply, set mode * MCD_S_WAITMODE: waits for status reply from set mode, set read command * MCD_S_WAITREAD: wait for read ready, read data */ static struct mcd_mbx *mbxsave; static void mcd_doread(int state, struct mcd_mbx *mbxin) { struct mcd_mbx *mbx = (state!=MCD_S_BEGIN) ? mbxsave : mbxin; int unit = mbx->unit; int port = mbx->port; struct buf *bp = mbx->bp; struct mcd_data *cd = mcd_data + unit; int rm,i,k; struct mcd_read2 rbuf; int blknum; caddr_t addr; loop: switch (state) { case MCD_S_BEGIN: mbx = mbxsave = mbxin; case MCD_S_BEGIN1: /* get status */ outb(port+mcd_command, MCD_CMDGETSTAT); mbx->count = RDELAY_WAITSTAT; timeout(mcd_doread,MCD_S_WAITSTAT,hz/100); return; case MCD_S_WAITSTAT: untimeout(mcd_doread,MCD_S_WAITSTAT); if (mbx->count-- >= 0) { if (inb(port+mcd_xfer) & MCD_ST_BUSY) { timeout(mcd_doread,MCD_S_WAITSTAT,hz/100); return; } mcd_setflags(unit,cd); MCD_TRACE("got WAITSTAT delay=%d\n",RDELAY_WAITSTAT-mbx->count,0,0,0); /* reject, if audio active */ if (cd->status & MCDAUDIOBSY) { printf("mcd%d: audio is active\n",unit); goto readerr; } /* to check for raw/cooked mode */ if (cd->flags & MCDREADRAW) { rm = MCD_MD_RAW; mbx->sz = MCDRBLK; } else { rm = MCD_MD_COOKED; mbx->sz = cd->blksize; } mbx->count = RDELAY_WAITMODE; mcd_put(port+mcd_command, MCD_CMDSETMODE); mcd_put(port+mcd_command, rm); timeout(mcd_doread,MCD_S_WAITMODE,hz/100); return; } else { #ifdef MCD_TO_WARNING_ON printf("mcd%d: timeout getstatus\n",unit); #endif goto readerr; } case MCD_S_WAITMODE: untimeout(mcd_doread,MCD_S_WAITMODE); if (mbx->count-- < 0) { #ifdef MCD_TO_WARNING_ON printf("mcd%d: timeout set mode\n",unit); #endif goto readerr; } if (inb(port+mcd_xfer) & MCD_ST_BUSY) { timeout(mcd_doread,MCD_S_WAITMODE,hz/100); return; } mcd_setflags(unit,cd); MCD_TRACE("got WAITMODE delay=%d\n",RDELAY_WAITMODE-mbx->count,0,0,0); /* for first block */ mbx->nblk = (bp->b_bcount + (mbx->sz-1)) / mbx->sz; mbx->skip = 0; nextblock: blknum = (bp->b_blkno / (mbx->sz/DEV_BSIZE)) + mbx->p_offset + mbx->skip/mbx->sz; MCD_TRACE("mcd_doread: read blknum=%d for bp=0x%x\n",blknum,bp,0,0); /* build parameter block */ hsg2msf(blknum,rbuf.start_msf); /* send the read command */ mcd_put(port+mcd_command,MCD_CMDREAD2); mcd_put(port+mcd_command,rbuf.start_msf[0]); mcd_put(port+mcd_command,rbuf.start_msf[1]); mcd_put(port+mcd_command,rbuf.start_msf[2]); mcd_put(port+mcd_command,0); mcd_put(port+mcd_command,0); mcd_put(port+mcd_command,1); mbx->count = RDELAY_WAITREAD; timeout(mcd_doread,MCD_S_WAITREAD,hz/100); return; case MCD_S_WAITREAD: untimeout(mcd_doread,MCD_S_WAITREAD); if (mbx->count-- > 0) { k = inb(port+mcd_xfer); if ((k & 2)==0) { MCD_TRACE("got data delay=%d\n",RDELAY_WAITREAD-mbx->count,0,0,0); /* data is ready */ addr = bp->b_un.b_addr + mbx->skip; outb(port+mcd_ctl2,0x04); /* XXX */ for (i=0; isz; i++) *addr++ = inb(port+mcd_rdata); outb(port+mcd_ctl2,0x0c); /* XXX */ if (--mbx->nblk > 0) { mbx->skip += mbx->sz; goto nextblock; } /* return buffer */ bp->b_resid = 0; biodone(bp); cd->flags &= ~MCDMBXBSY; mcd_start(mbx->unit); return; } if ((k & 4)==0) mcd_getstat(unit,0); timeout(mcd_doread,MCD_S_WAITREAD,hz/100); return; } else { #ifdef MCD_TO_WARNING_ON printf("mcd%d: timeout read data\n",unit); #endif goto readerr; } } readerr: if (mbx->retry-- > 0) { #ifdef MCD_TO_WARNING_ON printf("mcd%d: retrying\n",unit); #endif state = MCD_S_BEGIN1; goto loop; } /* invalidate the buffer */ bp->b_flags |= B_ERROR; bp->b_resid = bp->b_bcount; biodone(bp); mcd_start(mbx->unit); return; #ifdef NOTDEF printf("mcd%d: unit timeout, resetting\n",mbx->unit); outb(mbx->port+mcd_reset,MCD_CMDRESET); DELAY(300000); (void)mcd_getstat(mbx->unit,1); (void)mcd_getstat(mbx->unit,1); /*cd->status &= ~MCDDSKCHNG; */ cd->debug = 1; /* preventive set debug mode */ #endif } #ifndef MCDMINI static int mcd_setmode(int unit, int mode) { struct mcd_data *cd = mcd_data + unit; int port = cd->iobase; int retry; printf("mcd%d: setting mode to %d\n", unit, mode); for(retry=0; retrylen = msf2hsg(cd->volinfo.vol_msf); th->starting_track = bcd2bin(cd->volinfo.trk_low); th->ending_track = bcd2bin(cd->volinfo.trk_high); return 0; } static int mcd_read_toc(int unit) { struct mcd_data *cd = mcd_data + unit; struct ioc_toc_header th; struct mcd_qchninfo q; int rc, trk, idx, retry; /* Only read TOC if needed */ if (cd->flags & MCDTOC) return 0; printf("mcd%d: reading toc header\n", unit); if (mcd_toc_header(unit, &th) != 0) return ENXIO; printf("mcd%d: stopping play\n", unit); if ((rc=mcd_stop(unit)) != 0) return rc; /* try setting the mode twice */ if (mcd_setmode(unit, MCD_MD_TOC) != 0) return EIO; if (mcd_setmode(unit, MCD_MD_TOC) != 0) return EIO; printf("mcd%d: get_toc reading qchannel info\n",unit); for(trk=th.starting_track; trk<=th.ending_track; trk++) cd->toc[trk].idx_no = 0; trk = th.ending_track - th.starting_track + 1; for(retry=0; retry<300 && trk>0; retry++) { if (mcd_getqchan(unit, &q) < 0) break; idx = bcd2bin(q.idx_no); if (idx>0 && idx < MCD_MAXTOCS && q.trk_no==0) if (cd->toc[idx].idx_no == 0) { cd->toc[idx] = q; trk--; } } if (mcd_setmode(unit, MCD_MD_COOKED) != 0) return EIO; if (trk != 0) return ENXIO; /* add a fake last+1 */ idx = th.ending_track + 1; cd->toc[idx].ctrl_adr = cd->toc[idx-1].ctrl_adr; cd->toc[idx].trk_no = 0; cd->toc[idx].idx_no = 0xAA; cd->toc[idx].hd_pos_msf[0] = cd->volinfo.vol_msf[0]; cd->toc[idx].hd_pos_msf[1] = cd->volinfo.vol_msf[1]; cd->toc[idx].hd_pos_msf[2] = cd->volinfo.vol_msf[2]; cd->flags |= MCDTOC; return 0; } static int mcd_toc_entry(int unit, struct ioc_read_toc_entry *te) { struct mcd_data *cd = mcd_data + unit; struct ret_toc { struct ioc_toc_header th; struct cd_toc_entry rt; } ret_toc; struct ioc_toc_header th; int rc, i; /* Make sure we have a valid toc */ if ((rc=mcd_read_toc(unit)) != 0) return rc; /* find the toc to copy*/ i = te->starting_track; if (i == MCD_LASTPLUS1) i = bcd2bin(cd->volinfo.trk_high) + 1; /* verify starting track */ if (i < bcd2bin(cd->volinfo.trk_low) || i > bcd2bin(cd->volinfo.trk_high)+1) return EINVAL; /* do we have room */ if (te->data_len < sizeof(struct ioc_toc_header) + sizeof(struct cd_toc_entry)) return EINVAL; /* Copy the toc header */ if (mcd_toc_header(unit, &th) < 0) return EIO; ret_toc.th = th; /* copy the toc data */ ret_toc.rt.control = cd->toc[i].ctrl_adr; ret_toc.rt.addr_type = te->address_format; ret_toc.rt.track = i; if (te->address_format == CD_MSF_FORMAT) { ret_toc.rt.addr[1] = cd->toc[i].hd_pos_msf[0]; ret_toc.rt.addr[2] = cd->toc[i].hd_pos_msf[1]; ret_toc.rt.addr[3] = cd->toc[i].hd_pos_msf[2]; } /* copy the data back */ copyout(&ret_toc, te->data, sizeof(struct cd_toc_entry) + sizeof(struct ioc_toc_header)); return 0; } static int mcd_stop(int unit) { struct mcd_data *cd = mcd_data + unit; if (mcd_send(unit, MCD_CMDSTOPAUDIO, MCD_RETRYS) < 0) return ENXIO; cd->audio_status = CD_AS_PLAY_COMPLETED; return 0; } static int mcd_getqchan(int unit, struct mcd_qchninfo *q) { struct mcd_data *cd = mcd_data + unit; if (mcd_send(unit, MCD_CMDGETQCHN, MCD_RETRYS) < 0) return -1; if (mcd_get(unit, (char *) q, sizeof(struct mcd_qchninfo)) < 0) return -1; if (cd->debug) printf("mcd%d: qchannel ctl=%d, t=%d, i=%d, ttm=%d:%d.%d dtm=%d:%d.%d\n", unit, q->ctrl_adr, q->trk_no, q->idx_no, q->trk_size_msf[0], q->trk_size_msf[1], q->trk_size_msf[2], q->trk_size_msf[0], q->trk_size_msf[1], q->trk_size_msf[2]); return 0; } static int mcd_subchan(int unit, struct ioc_read_subchannel *sc) { struct mcd_data *cd = mcd_data + unit; struct mcd_qchninfo q; struct cd_sub_channel_info data; printf("mcd%d: subchan af=%d, df=%d\n", unit, sc->address_format, sc->data_format); if (sc->address_format != CD_MSF_FORMAT) return EIO; if (sc->data_format != CD_CURRENT_POSITION) return EIO; if (mcd_getqchan(unit, &q) < 0) return EIO; data.header.audio_status = cd->audio_status; data.what.position.data_format = CD_MSF_FORMAT; data.what.position.track_number = bcd2bin(q.trk_no); if (copyout(&data, sc->data, sizeof(struct cd_sub_channel_info))!=0) return EFAULT; return 0; } static int mcd_playtracks(int unit, struct ioc_play_track *pt) { struct mcd_data *cd = mcd_data + unit; struct mcd_read2 pb; int a = pt->start_track; int z = pt->end_track; int rc; if ((rc = mcd_read_toc(unit)) != 0) return rc; printf("mcd%d: playtracks from %d:%d to %d:%d\n", unit, a, pt->start_index, z, pt->end_index); if (a < cd->volinfo.trk_low || a > cd->volinfo.trk_high || a > z || z < cd->volinfo.trk_low || z > cd->volinfo.trk_high) return EINVAL; pb.start_msf[0] = cd->toc[a].hd_pos_msf[0]; pb.start_msf[1] = cd->toc[a].hd_pos_msf[1]; pb.start_msf[2] = cd->toc[a].hd_pos_msf[2]; pb.end_msf[0] = cd->toc[z+1].hd_pos_msf[0]; pb.end_msf[1] = cd->toc[z+1].hd_pos_msf[1]; pb.end_msf[2] = cd->toc[z+1].hd_pos_msf[2]; return mcd_play(unit, &pb); } static int mcd_play(int unit, struct mcd_read2 *pb) { struct mcd_data *cd = mcd_data + unit; int port = cd->iobase; int retry, st; cd->lastpb = *pb; for(retry=0; retrystart_msf[0]); outb(port+mcd_command, pb->start_msf[1]); outb(port+mcd_command, pb->start_msf[2]); outb(port+mcd_command, pb->end_msf[0]); outb(port+mcd_command, pb->end_msf[1]); outb(port+mcd_command, pb->end_msf[2]); if ((st=mcd_getstat(unit, 0)) != -1) break; } if (cd->debug) printf("mcd%d: mcd_play retry=%d, status=%d\n", unit, retry, st); if (st == -1) return ENXIO; cd->audio_status = CD_AS_PLAY_IN_PROGRESS; return 0; } static int mcd_pause(int unit) { struct mcd_data *cd = mcd_data + unit; struct mcd_qchninfo q; int rc; /* Verify current status */ if (cd->audio_status != CD_AS_PLAY_IN_PROGRESS) { printf("mcd%d: pause attempted when not playing\n", unit); return EINVAL; } /* Get the current position */ if (mcd_getqchan(unit, &q) < 0) return EIO; /* Copy it into lastpb */ cd->lastpb.start_msf[0] = q.hd_pos_msf[0]; cd->lastpb.start_msf[1] = q.hd_pos_msf[1]; cd->lastpb.start_msf[2] = q.hd_pos_msf[2]; /* Stop playing */ if ((rc=mcd_stop(unit)) != 0) return rc; /* Set the proper status and exit */ cd->audio_status = CD_AS_PLAY_PAUSED; return 0; } static int mcd_resume(int unit) { struct mcd_data *cd = mcd_data + unit; if (cd->audio_status != CD_AS_PLAY_PAUSED) return EINVAL; return mcd_play(unit, &cd->lastpb); } #endif /*!MCDMINI*/ #endif /* NMCD > 0 */ Index: head/sys/dev/sio/sio.c =================================================================== --- head/sys/dev/sio/sio.c (revision 618) +++ head/sys/dev/sio/sio.c (revision 619) @@ -1,1749 +1,1740 @@ /*- * 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 - * - * 27 May 93 Bruce Evans From com-0.2 package, fast interrupt - * com port driver. - * 27 May 93 Guido van Rooij Ported in Chris Demetriou's BIDIR - * code, add multiport support. - * 27 May 93 Rodney W. Grimes I then renamed it to sio.c for putting - * into the patch kit. Added in sioselect - * from com.c. Added port 4 support. + * from: @(#)com.c 7.5 (Berkeley) 5/16/91 + * $Id$ */ -static char rcsid[] = "$Header: /a/cvs/386BSD/src/sys/i386/isa/sio.c,v 1.10 1993/10/12 06:32:28 davidg Exp $"; #include "sio.h" #if NSIO > 0 /* * COM driver, based on HP dca driver. * Mostly rewritten to use pseudo-DMA. * Works for National Semiconductor NS8250-NS16550AF UARTs. */ #include "param.h" #include "systm.h" #include "ioctl.h" #include "tty.h" #include "proc.h" #include "user.h" #include "conf.h" #include "file.h" #include "uio.h" #include "kernel.h" #include "syslog.h" #include "i386/isa/isa.h" #include "i386/isa/isa_device.h" #include "i386/isa/comreg.h" #include "i386/isa/ic/ns16550.h" #undef CRTS_IFLOW #define CRTS_IFLOW CRTSCTS /* XXX, CCTS_OFLOW = CRTSCTS already */ #define LOTS_OF_EVENTS 64 /* helps separate urgent events from input */ #define RB_I_HIGH_WATER (RBSZ - 2 * RS_IBUFSIZE) #define RB_I_LOW_WATER ((RBSZ - 2 * RS_IBUFSIZE) * 7 / 8) #define RS_IBUFSIZE 256 #define TS_RTSBLOCK TS_TBLOCK /* XXX */ #define TTY_BI TTY_FE /* XXX */ #define TTY_OE TTY_PE /* XXX */ #ifndef COM_BIDIR #define UNIT(x) (minor(x)) /* XXX */ #else /* COM_BIDIR */ #define COM_UNITMASK 0x7f #define COM_CALLOUTMASK 0x80 #define UNIT(x) (minor(x) & COM_UNITMASK) #define CALLOUT(x) (minor(x) & COM_CALLOUTMASK) #endif /* COM_BIDIR */ #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) #endif /* COM_MULTIPORT */ #define com_scr 7 /* scratch register for 16450-16550 (R/W) */ #define schedsoftcom() (ipending |= 1 << 4) /* XXX */ /* * 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. * Bug: I think TIOCSETA doesn't clear TS_TTSTOP when it clears IXON. */ #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_ODONE 4 /* output completed */ #define CS_RTS_IFLOW 8 /* use RTS input flow control */ static char *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 int Bool_t; /* promoted boolean */ typedef u_char bool_t; /* boolean */ /* com device structure */ struct com_s { u_char state; /* miscellaneous flag bits */ u_char cfcr_image; /* copy of value written to CFCR */ bool_t hasfifo; /* nonzero for 16550 UARTs */ u_char mcr_image; /* copy of value written to MCR */ bool_t softDCD; /* nonzero for faked carrier detect */ #ifdef COM_BIDIR bool_t bidir; /* is this unit bidirectional? */ bool_t active; /* is the port active _at all_? */ bool_t active_in; /* is the incoming port in use? */ bool_t active_out; /* is the outgoing port in use? */ #endif /* COM_BIDIR */ #ifdef COM_MULTIPORT bool_t multiport; /* is this unit part of a multiport device? */ #endif /* COM_MULTIPORT */ /* * 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 *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 */ int ocount; /* original count for current output */ 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 */ 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]; }; /* * These functions in the com module ought to be declared (with a prototype) * in a com-driver system header. The void ones may need to be int to match * ancient devswitch declarations, but they don't actually return anything. */ #define Dev_t int /* promoted dev_t */ struct consdev; int sioclose __P((Dev_t dev, int fflag, int devtype, struct proc *p)); void siointr __P((int unit)); #ifdef COM_MULTIPORT bool_t comintr1 __P((struct com_s *com)); #endif /* COM_MULTIPORT */ int sioioctl __P((Dev_t dev, int cmd, caddr_t data, int fflag, struct proc *p)); int siocngetc __P((Dev_t dev)); void siocninit __P((struct consdev *cp)); void siocnprobe __P((struct consdev *cp)); void siocnputc __P((Dev_t dev, int c)); int sioopen __P((Dev_t dev, int oflags, int devtype, struct proc *p)); /* * sioopen gets compared to the d_open entry in struct cdevsw. d_open and * other functions are declared in with short types like dev_t * in the prototype. Such declarations are broken because they vary with * __P (significantly in theory - the compiler is allowed to push a short * arg if it has seen the prototype; insignificantly in practice - gcc * doesn't push short args and it would be slower on 386's to do so). * * Also, most of the device switch functions are still declared old-style * so they take a Dev_t arg and shorten it to a dev_t. It would be simpler * and faster if dev_t's were always promoted (to ints or whatever) as * early as possible. * * Until is fixed, we cast sioopen to the following `wrong' type * when comparing it to the d_open entry just to avoid compiler warnings. */ typedef int (*bogus_open_t) __P((dev_t dev, int oflags, int devtype, struct proc *p)); int sioread __P((Dev_t dev, struct uio *uio, int ioflag)); void siostop __P((struct tty *tp, int rw)); int siowrite __P((Dev_t dev, struct uio *uio, int ioflag)); void softsio0 __P((void)); void softsio1 __P((void)); void softsio2 __P((void)); void softsio3 __P((void)); void softsio4 __P((void)); void softsio5 __P((void)); void softsio6 __P((void)); void softsio7 __P((void)); void softsio8 __P((void)); static int sioattach __P((struct isa_device *dev)); static void comflush __P((struct com_s *com)); static void comhardclose __P((struct com_s *com)); static void cominit __P((int unit, int rate)); static int 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 compoll __P((void)); static int comstart __P((struct tty *tp)); static void comwakeup __P((void)); static int tiocm2mcr __P((int)); /* 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]) static struct com_s com_structs[NSIO]; struct isa_driver siodriver = { sioprobe, sioattach, "sio" }; #ifdef COMCONSOLE static int comconsole = COMCONSOLE; #else static int comconsole = -1; #endif static bool_t comconsinit; static speed_t comdefaultrate = TTYDEF_SPEED; static u_int com_events; /* input chars + weighted output completions */ static int commajor; struct tty sio_tty[NSIO]; extern struct tty *constty; extern u_int ipending; /* XXX */ extern int tk_nin; /* XXX */ extern int tk_rawcc; /* 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; Port_t iobase; 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. */ 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; } iobase = dev->id_iobase; result = IO_COMSIZE; /* * 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(); /* * Enable output interrupts (only) and check the following: * 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. */ outb(iobase + com_cfcr, CFCR_8BITS); /* ensure IER is addressed */ outb(iobase + com_mcr, MCR_IENABLE); /* open gate early */ outb(iobase + com_ier, 0); /* ensure edge on next intr */ outb(iobase + com_ier, IER_ETXRDY); /* generate interrupt */ if ( inb(iobase + com_cfcr) != CFCR_8BITS || inb(iobase + com_ier) != IER_ETXRDY || inb(iobase + com_mcr) != MCR_IENABLE || (inb(iobase + com_iir) & IIR_IMASK) != IIR_TXRDY || isa_irq_pending(dev) || (inb(iobase + com_iir) & IIR_IMASK) != IIR_NOPEND) result = 0; /* * Turn off all device interrupts and check that they go off properly. * Leave MCR_IENABLE set. 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_mcr, MCR_IENABLE); /* dummy to avoid bus echo */ if ( inb(iobase + com_ier) != 0 || isa_irq_pending(dev) || (inb(iobase + com_iir) & IIR_IMASK) != IIR_NOPEND) result = 0; enable_intr(); return (result); } static int /* XXX - should be void */ sioattach(isdp) struct isa_device *isdp; { struct com_s *com; static bool_t comwakeup_started = FALSE; Port_t iobase; int s; u_char scr; u_char scr1; u_char scr2; int unit; iobase = isdp->id_iobase; unit = isdp->id_unit; if (unit == comconsole) DELAY(1000); /* XXX */ s = spltty(); /* * 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. * Keeping MCR_DTR and MCR_RTS off might stop the external * device from sending before we are ready. */ com = &com_structs[unit]; com->cfcr_image = CFCR_8BITS; com->mcr_image = MCR_IENABLE; #if 0 com->softDCD = TRUE; #endif 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->line_status_port = iobase + com_lsr; com->modem_status_port = iobase + com_msr; com->tp = &sio_tty[unit]; #ifdef COM_BIDIR /* * if bidirectional ports possible, clear the bidir port info; */ com->bidir = FALSE; com->active = FALSE; com->active_in = com->active_out = FALSE; #endif /* COM_BIDIR */ /* attempt to determine UART type */ 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); printf("sio%d: type", unit); #ifdef COM_MULTIPORT if (0); #else if (scr1 != 0xa5 || scr2 != 0x5a) printf(" <8250>"); #endif else { outb(iobase + com_fifo, FIFO_ENABLE | FIFO_TRIGGER_14); DELAY(100); switch (inb(iobase + com_iir) & 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: com->hasfifo = TRUE; printf(" <16550A>"); break; } outb(iobase + com_fifo, 0); } #ifdef COM_MULTIPORT if (COM_ISMULTIPORT(isdp)) { struct isa_device *masterdev; com->multiport = TRUE; printf(" (multiport)"); /* set the master's common-interrupt-enable reg., * as appropriate. YYY See your manual */ /* enable only common interrupt for port */ outb(iobase + com_mcr, 0); masterdev = find_isadev(isa_devtab_tty, &siodriver, COM_MPMASTER(isdp)); outb(masterdev->id_iobase+com_scr, 0x80); } else com->multiport = FALSE; #endif /* COM_MULTIPORT */ printf("\n"); #ifdef KGDB if (kgdb_dev == makedev(commajor, unit)) { if (comconsole == unit) kgdb_dev = -1; /* can't debug over console port */ else { cominit(unit, kgdb_rate); if (kgdb_debug_init) { /* * Print prefix of device name, * let kgdb_connect print the rest. */ printf("com%d: ", unit); kgdb_connect(1); } else printf("com%d: kgdb enabled\n", unit); } } #endif /* * Need to reset baud rate, etc. of next print so reset comconsinit. * Also make sure console is always "hardwired" */ if (unit == comconsole) { comconsinit = FALSE; com->softDCD = TRUE; } com_addr(unit) = com; splx(s); if (!comwakeup_started) { comwakeup(); 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 = 0; Port_t iobase; int s; struct tty *tp; int unit = UNIT(dev); #ifdef COM_BIDIR bool_t callout = CALLOUT(dev); #endif /* COM_BIDIR */ if ((u_int) unit >= NSIO || (com = com_addr(unit)) == NULL) return (ENXIO); #ifdef COM_BIDIR /* if it's a callout device, and bidir not possible on that dev, die */ if (callout && !(com->bidir)) return (ENXIO); #endif /* COM_BIDIR */ tp = com->tp; s = spltty(); #ifdef COM_BIDIR bidir_open_top: /* if it's bidirectional, we've gotta deal with it... */ if (com->bidir) { if (callout) { if (com->active_in) { /* it's busy. die */ splx(s); return (EBUSY); } else { /* it's ours. lock it down, and set it up */ com->active_out = TRUE; com->softDCD = TRUE; } } else { if (com->active_out) { /* it's busy, outgoing. wait, if possible */ if (flag & O_NONBLOCK) { /* can't wait; bail */ splx(s); return (EBUSY); } else { /* wait for it... */ error = tsleep(&com->active_out, TTIPRI|PCATCH, "comoth", 0); /* if there was an error, take off. */ if (error != 0) { splx(s); return (error); } /* else take it from the top */ goto bidir_open_top; } } else if (com->last_modem_status & MSR_DCD) { /* there's a carrier on the line; we win */ com->active_in = TRUE; com->softDCD = FALSE; } else { /* there is no carrier on the line */ if (flag & O_NONBLOCK) { /* can't wait; let it open */ com->active_in = TRUE; com->softDCD = FALSE; } else { /* put DTR & RTS up */ /* NOTE: cgd'sdriver used the ier register * to enable/disable interrupts. This one * uses both ier and IENABLE in the mcr. */ (void) commctl(com, MCR_DTR | MCR_RTS, DMSET); outb(com->iobase + com_ier, IER_EMSC); /* wait for it... */ error = tsleep(&com->active_in, TTIPRI|PCATCH, "comdcd", 0); /* if not active, turn DTR & RTS off */ if (!com->active) (void) commctl(com, MCR_DTR, DMBIC); /* if there was an error, take off. */ if (error != 0) { splx(s); return (error); } /* else take it from the top */ goto bidir_open_top; } } } } com->active = TRUE; #endif /* COM_BIDIR */ tp->t_oproc = comstart; tp->t_param = comparam; tp->t_dev = dev; if (!(tp->t_state & TS_ISOPEN)) { tp->t_state |= TS_WOPEN; ttychars(tp); if (tp->t_ispeed == 0) { /* * We no longer use the flags from * since those 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. */ tp->t_iflag = 0; tp->t_oflag = 0; tp->t_cflag = CREAD | CS8 | HUPCL; tp->t_lflag = 0; tp->t_ispeed = tp->t_ospeed = comdefaultrate; } (void) commctl(com, MCR_DTR | MCR_RTS, DMSET); error = comparam(tp, &tp->t_termios); if (error != 0) goto out; ttsetwater(tp); iobase = com->iobase; disable_intr(); if (com->hasfifo) /* (re)enable and drain FIFO */ outb(iobase + com_fifo, FIFO_ENABLE | FIFO_TRIGGER_14 | FIFO_RCV_RST | FIFO_XMT_RST); (void) inb(com->line_status_port); (void) inb(com->data_port); com->last_modem_status = com->prev_modem_status = inb(com->modem_status_port); outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC); enable_intr(); if (com->softDCD || com->prev_modem_status & MSR_DCD) tp->t_state |= TS_CARR_ON; } else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) { splx(s); return (EBUSY); } while (!(flag & O_NONBLOCK) && !(tp->t_cflag & CLOCAL) #ifdef COM_BIDIR /* We went through a lot of trouble to open it, * but it's certain we have a carrier now, so * don't spend any time on it now. */ && !(com->bidir) #endif /* COM_BIDIR */ && !(tp->t_state & TS_CARR_ON)) { tp->t_state |= TS_WOPEN; error = ttysleep(tp, (caddr_t)&tp->t_raw, TTIPRI | PCATCH, ttopen, 0); if (error != 0) break; } out: splx(s); if (error == 0) error = (*linesw[tp->t_line].l_open)(dev, tp); #ifdef COM_BIDIR /* wakeup sleepers */ wakeup((caddr_t) &com->active_in); #endif /* COM_BIDIR */ /* * XXX - the next step was once not done, so interrupts, DTR and RTS * remainded hot if the process was killed while it was sleeping * waiting for carrier. Now there is the opposite problem. If several * processes are sleeping waiting for carrier on the same line and one * is killed, interrupts are turned off so the other processes will * never see the carrier rise. */ if (error != 0 && !(tp->t_state & TS_ISOPEN)) { comhardclose(com); } tp->t_state &= ~TS_WOPEN; return (error); } /*ARGSUSED*/ int sioclose(dev, flag, mode, p) dev_t dev; int flag; int mode; struct proc *p; { struct com_s *com; struct tty *tp; com = com_addr(UNIT(dev)); tp = com->tp; (*linesw[tp->t_line].l_close)(tp, flag); comhardclose(com); ttyclose(tp); return (0); } void comhardclose(com) struct com_s *com; { Port_t iobase; int s; struct tty *tp; s = spltty(); iobase = com->iobase; outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK); #ifdef KGDB /* do not disable interrupts if debugging */ if (kgdb_dev != makedev(commajor, com - &com_structs[0])) #endif outb(iobase + com_ier, 0); tp = com->tp; if (tp->t_cflag & HUPCL || tp->t_state & TS_WOPEN || !(tp->t_state & TS_ISOPEN)) (void) commctl(com, MCR_RTS, DMSET); #ifdef COM_BIDIR com->active = com->active_in = com->active_out = FALSE; com->softDCD = FALSE; /* wakeup sleepers who are waiting for out to finish */ wakeup((caddr_t) &com->active_out); #endif /* COM_BIDIR */ splx(s); } int sioread(dev, uio, flag) dev_t dev; struct uio *uio; int flag; { struct tty *tp = com_addr(UNIT(dev))->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 unit = UNIT(dev); struct tty *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)); } void siointr(unit) int unit; { struct com_s *com; #ifndef COM_MULTIPORT u_char line_status; u_char modem_status; u_char *ioptr; u_char recv_data; com = com_addr(unit); #else /* COM_MULTIPORT */ int i; bool_t donesomething; do { donesomething = FALSE; for(i=0;iline_status_port); /* input event? (check first to help avoid overruns) */ while (line_status & LSR_RCV_MASK) { /* break/unnattached error bits or real input? */ #ifdef COM_MULTIPORT donesomething = TRUE; #endif /* COM_MULTIPORT */ if (!(line_status & LSR_RXRDY)) recv_data = 0; else recv_data = inb(com->data_port); ++com->bytes_in; #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; 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); } /* * "& 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. */ #ifdef COM_MULTIPORT donesomething = TRUE; #endif /* COM_MULTIPORT */ com->last_modem_status = modem_status; if (!(com->state & CS_CHECKMSR)) { com_events += LOTS_OF_EVENTS; com->state |= CS_CHECKMSR; schedsoftcom(); } /* 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)) { #ifdef COM_MULTIPORT donesomething = TRUE; #endif /* COM_MULTIPORT */ ioptr = com->optr; 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); schedsoftcom(); /* handle at high level ASAP */ } } /* finished? */ if ((inb(com->int_id_port) & IIR_IMASK) == IIR_NOPEND) #ifdef COM_MULTIPORT return (donesomething); #else return; #endif /* COM_MULTIPORT */ } } static int tiocm2mcr(data) int data; { register m = 0; if (data & TIOCM_DTR) m |= MCR_DTR; if (data & TIOCM_RTS) m |= MCR_RTS; return m; } 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 s; struct tty *tp; com = com_addr(UNIT(dev)); tp = com->tp; error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 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: (void) commctl(com, MCR_DTR, DMBIS); break; case TIOCCDTR: (void) commctl(com, MCR_DTR, DMBIC); break; case TIOCMSET: (void) commctl(com, tiocm2mcr(*(int *)data), DMSET); break; case TIOCMBIS: (void) commctl(com, tiocm2mcr(*(int *)data), DMBIS); break; case TIOCMBIC: (void) commctl(com, tiocm2mcr(*(int *)data), DMBIC); break; case TIOCMGET: { register int bits = 0, mode; mode = commctl(com, 0, DMGET); if (inb(com->iobase+com_ier)) bits |= TIOCM_LE; /* XXX */ if (mode & MSR_DCD) bits |= TIOCM_CD; if (mode & MSR_CTS) bits |= TIOCM_CTS; if (mode & MSR_DSR) bits |= TIOCM_DSR; if (mode & (MCR_DTR<<8)) bits |= TIOCM_DTR; if (mode & (MCR_RTS<<8)) bits |= TIOCM_RTS; if (mode & (MSR_RI|MSR_TERI)) bits |= TIOCM_RI; *(int *)data = bits; } break; #ifdef COM_BIDIR case TIOCMSBIDIR: /* must be root to set bidir. capability */ if (p->p_ucred->cr_uid != 0) return(EPERM); /* if it's the console, can't do it */ if (UNIT(dev) == comconsole) return(ENOTTY); /* can't do the next, for obvious reasons... * but there are problems to be looked at... */ /* if the port is active, don't do it */ /* if (com->active) return(EBUSY); */ com->bidir = *(int *)data; break; case TIOCMGBIDIR: *(int *)data = com->bidir; break; #endif /* COM_BIDIR */ default: splx(s); return (ENOTTY); } splx(s); return (0); } /* cancel pending output */ static void comflush(com) struct com_s *com; { struct ringb *rbp; disable_intr(); if (com->state & CS_ODONE) com_events -= LOTS_OF_EVENTS; com->state &= ~(CS_ODONE | CS_BUSY); enable_intr(); rbp = &com->tp->t_out; rbp->rb_hd += com->ocount; rbp->rb_hd = RB_ROLLOVER(rbp, rbp->rb_hd); com->ocount = 0; com->tp->t_state &= ~TS_BUSY; } static void compoll() { static bool_t awake = FALSE; struct com_s *com; int s; int unit; if (com_events == 0) return; disable_intr(); if (awake) { enable_intr(); return; } awake = TRUE; enable_intr(); s = spltty(); repeat: for (unit = 0; unit < NSIO; ++unit) { u_char *buf; u_char *ibuf; int incc; struct tty *tp; com = com_addr(unit); if (com == NULL) continue; tp = com->tp; /* switch the role of the low-level input buffers */ if (com->iptr == (ibuf = com->ibuf)) incc = 0; else { 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. */ if (!(com->mcr_image & MCR_RTS) && !(tp->t_state & TS_RTSBLOCK)) 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 && unit != comconsole) { #ifdef COM_BIDIR if (com->prev_modem_status & MSR_DCD) { (*linesw[tp->t_line].l_modem)(tp, 1); com->softDCD = FALSE; wakeup((caddr_t) &com->active_in); } #else if (com->prev_modem_status & MSR_DCD) (*linesw[tp->t_line].l_modem)(tp, 1); #endif /* COM_BIDIR */ else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) { disable_intr(); outb(com->modem_ctl_port, com->mcr_image &= ~MCR_DTR); enable_intr(); } } } /* XXX */ if (TRUE) { u_int delta; u_int delta_error_counts[CE_NTYPES]; int errnum; u_long total; disable_intr(); bcopy(com->delta_error_counts, delta_error_counts, sizeof delta_error_counts); bzero(com->delta_error_counts, sizeof delta_error_counts); enable_intr(); for (errnum = 0; errnum < CE_NTYPES; ++errnum) { delta = delta_error_counts[errnum]; if (delta != 0) { total = com->error_counts[errnum] += delta; log(LOG_WARNING, "com%d: %u more %s%s (total %lu)\n", unit, delta, error_desc[errnum], delta == 1 ? "" : "s", total); } } } 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 && RB_LEN(&tp->t_raw) + incc >= RB_I_HIGH_WATER && !(tp->t_state & TS_RTSBLOCK) /* * 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_RTSBLOCK; 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] += incc - rb_write(&tp->t_raw, (char *) buf, incc); 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; splx(s); awake = FALSE; } 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 (divisor < 0 || t->c_ispeed != 0 && t->c_ispeed != t->c_ospeed) return (EINVAL); /* parameters are OK, convert them to the com struct and the device */ unit = UNIT(tp->t_dev); com = com_addr(unit); iobase = com->iobase; s = spltty(); if (divisor == 0) { (void) commctl(com, MCR_RTS, DMSET); /* hang up line */ splx(s); return (0); } 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; /* * 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 siointr() might lose some receiver * error bits, but that is acceptable here. */ disable_intr(); com->state &= ~CS_TTGO; enable_intr(); while ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY)) != (LSR_TSRE | LSR_TXRDY)) { error = ttysleep(tp, (caddr_t)&tp->t_raw, TTIPRI | PCATCH, "comparam", 1); 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 */ 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 16+ msec latency, while CTS flow has 50- usec latency. * Note that DCD flow control stupidly uses the same state flag * (TS_TTSTOP) as XON/XOFF flow control. */ com->state &= ~CS_CTS_OFLOW; com->state |= CS_ODEVREADY; if (cflag & CCTS_OFLOW) { com->state |= CS_CTS_OFLOW; if (!(com->prev_modem_status & MSR_CTS)) com->state &= ~CS_ODEVREADY; } enable_intr(); siointr(unit); /* recover from fiddling with CS_TTGO */ splx(s); return (0); } static int /* XXX - should be void */ comstart(tp) struct tty *tp; { struct com_s *com; int s; int unit; unit = 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_RTSBLOCK) { if (com->mcr_image & MCR_RTS && com->state & CS_RTS_IFLOW) outb(com->modem_ctl_port, com->mcr_image &= ~MCR_RTS); } else { if (!(com->mcr_image & MCR_RTS) && com->iptr < com->ihighwater) { tp->t_state &= ~TS_RTSBLOCK; outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS); } } enable_intr(); if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) goto out; if (RB_LEN(&tp->t_out) <= tp->t_lowat) { if (tp->t_state & TS_ASLEEP) { tp->t_state &= ~TS_ASLEEP; wakeup((caddr_t)&tp->t_out); } if (tp->t_wsel) { selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); tp->t_wsel = 0; tp->t_state &= ~TS_WCOLL; } } if (com->ocount != 0) { disable_intr(); siointr(unit); enable_intr(); } else if (RB_LEN(&tp->t_out) != 0) { tp->t_state |= TS_BUSY; com->ocount = RB_CONTIGGET(&tp->t_out); disable_intr(); com->obufend = (com->optr = (u_char *) tp->t_out.rb_hd) + com->ocount; com->state |= CS_BUSY; siointr(unit); /* fake interrupt to start output */ enable_intr(); } out: splx(s); return (1); } void siostop(tp, rw) struct tty *tp; int rw; { struct com_s *com; com = com_addr(UNIT(tp->t_dev)); if (rw & FWRITE) comflush(com); disable_intr(); if (tp->t_state & TS_TTSTOP) com->state &= ~CS_TTGO; else com->state |= CS_TTGO; enable_intr(); } static int commctl(com, bits, how) struct com_s *com; int bits; int how; { disable_intr(); switch (how) { case DMSET: #ifdef COM_MULTIPORT /* YYY maybe your card doesn't want IENABLE to be reset? */ if(com->multiport) outb(com->modem_ctl_port, com->mcr_image = bits); else #endif /* COM_MULTIPORT */ outb(com->modem_ctl_port, com->mcr_image = bits | MCR_IENABLE); break; case DMBIS: outb(com->modem_ctl_port, com->mcr_image |= bits); break; case DMBIC: #ifdef COM_MULTIPORT /* YYY maybe your card doesn't want IENABLE to be reset? */ if(com->multiport) outb(com->modem_ctl_port, com->mcr_image &= ~(bits)); else #endif /* COM_MULTIPORT */ outb(com->modem_ctl_port, com->mcr_image &= ~(bits & ~MCR_IENABLE)); break; case DMGET: bits = com->prev_modem_status | (com->mcr_image << 8); break; } enable_intr(); return (bits); } static void comwakeup() { struct com_s *com; int unit; timeout((timeout_func_t) comwakeup, (caddr_t) NULL, 1); if (com_events != 0) /* schedule compoll() to run when the cpl allows */ schedsoftcom(); /* recover from lost output interrupts */ for (unit = 0; unit < NSIO; ++unit) { com = com_addr(unit); if (com != NULL && com->state >= (CS_BUSY | CS_TTGO)) { disable_intr(); siointr(unit); enable_intr(); } } } void softsio0() { compoll(); } void softsio1() { compoll(); } void softsio2() { compoll(); } void softsio3() { compoll(); } void softsio4() { compoll(); } void softsio5() { compoll(); } void softsio6() { compoll(); } void softsio7() { compoll(); } void softsio8() { compoll(); } /* * Following are all routines needed for COM to act as console * XXX - not tested in this version * XXX - check that the corresponding serial interrupts are never enabled */ #include "i386/i386/cons.h" void siocnprobe(cp) struct consdev *cp; { int unit; /* locate the major number */ for (commajor = 0; commajor < nchrdev; commajor++) if (cdevsw[commajor].d_open == (bogus_open_t) sioopen) break; /* XXX: ick */ unit = CONUNIT; com_addr(unit) = &com_structs[unit]; com_addr(unit)->iobase = CONADDR; /* make sure hardware exists? XXX */ /* initialize required fields */ cp->cn_dev = makedev(commajor, unit); cp->cn_tp = &sio_tty[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; { int unit; unit = UNIT(cp->cn_dev); cominit(unit, comdefaultrate); comconsole = unit; comconsinit = TRUE; } static void cominit(unit, rate) int unit; int rate; { Port_t iobase; int s; iobase = com_addr(unit)->iobase; s = splhigh(); outb(iobase + com_cfcr, CFCR_DLAB); rate = ttspeedtab(comdefaultrate, comspeedtab); outb(iobase + com_data, rate & 0xFF); outb(iobase + com_ier, rate >> 8); outb(iobase + com_cfcr, CFCR_8BITS); /* * XXX - fishy to enable interrupts and then poll. * It shouldn't be necessary to ready the iir. */ outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC); outb(iobase + com_fifo, FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER_14); (void) inb(iobase + com_iir); splx(s); } int siocngetc(dev) dev_t dev; { int c; Port_t iobase; int s; iobase = com_addr(UNIT(dev))->iobase; s = splhigh(); while (!(inb(iobase + com_lsr) & LSR_RXRDY)) ; c = inb(iobase + com_data); (void) inb(iobase + com_iir); splx(s); return (c); } void siocnputc(dev, c) dev_t dev; int c; { Port_t iobase; int s; int timo; iobase = com_addr(UNIT(dev))->iobase; s = splhigh(); #ifdef KGDB if (dev != kgdb_dev) #endif if (!comconsinit) { (void) cominit(UNIT(dev), comdefaultrate); comconsinit = TRUE; } /* wait for any pending transmission to finish */ timo = 50000; while (!(inb(iobase + com_lsr) & LSR_TXRDY) && --timo) ; outb(iobase + com_data, c); /* wait for this transmission to complete */ timo = 1500000; while (!(inb(iobase + com_lsr) & LSR_TXRDY) && --timo) ; /* clear any interrupts generated by this transmission */ (void) inb(iobase + com_iir); splx(s); } /* * 10 Feb 93 Jordan K. Hubbard Added select code * 27 May 93 Rodney W. Grimes Stole the select code from com.c.pl5 */ int sioselect(dev, rw, p) dev_t dev; int rw; struct proc *p; { register struct tty *tp = &sio_tty[UNIT(dev)]; int nread; int s = spltty(); struct proc *selp; switch (rw) { case FREAD: nread = ttnread(tp); if (nread > 0 || ((tp->t_cflag&CLOCAL) == 0 && (tp->t_state&TS_CARR_ON) == 0)) goto win; if (tp->t_rsel && (selp = pfind(tp->t_rsel)) && selp->p_wchan == (caddr_t)&selwait) tp->t_state |= TS_RCOLL; else tp->t_rsel = p->p_pid; break; case FWRITE: if (RB_LEN(&tp->t_out) <= tp->t_lowat) goto win; if (tp->t_wsel && (selp = pfind(tp->t_wsel)) && selp->p_wchan == (caddr_t)&selwait) tp->t_state |= TS_WCOLL; else tp->t_wsel = p->p_pid; break; } splx(s); return (0); win: splx(s); return (1); } #endif /* NSIO > 0 */ Index: head/sys/dev/speaker/spkr.c =================================================================== --- head/sys/dev/speaker/spkr.c (revision 618) +++ head/sys/dev/speaker/spkr.c (revision 619) @@ -1,521 +1,523 @@ /* * spkr.c -- device driver for console speaker on 80386 * * v1.1 by Eric S. Raymond (esr@snark.thyrsus.com) Feb 1990 * modified for 386bsd by Andrew A. Chernov * 386bsd only clean version, all SYSV stuff removed * use hz value from param.c + * + * $Id$ */ #include "speaker.h" #if NSPEAKER > 0 #include "param.h" #include "systm.h" #include "kernel.h" #include "errno.h" #include "buf.h" #include "uio.h" #include "spkr.h" /**************** MACHINE DEPENDENT PART STARTS HERE ************************* * * This section defines a function tone() which causes a tone of given * frequency and duration from the 80x86's console speaker. * Another function endtone() is defined to force sound off, and there is * also a rest() entry point to do pauses. * * Audible sound is generated using the Programmable Interval Timer (PIT) and * Programmable Peripheral Interface (PPI) attached to the 80x86's speaker. The * PPI controls whether sound is passed through at all; the PIT's channel 2 is * used to generate clicks (a square wave) of whatever frequency is desired. */ /* * PIT and PPI port addresses and control values * * Most of the magic is hidden in the TIMER_PREP value, which selects PIT * channel 2, frequency LSB first, square-wave mode and binary encoding. * The encoding is as follows: * * +----------+----------+---------------+-----+ * | 1 0 | 1 1 | 0 1 1 | 0 | * | SC1 SC0 | RW1 RW0 | M2 M1 M0 | BCD | * +----------+----------+---------------+-----+ * Counter Write Mode 3 Binary * Channel 2 LSB first, (Square Wave) Encoding * MSB second */ #define PPI 0x61 /* port of Programmable Peripheral Interface */ #define PPI_SPKR 0x03 /* turn these PPI bits on to pass sound */ #define PIT_CTRL 0x43 /* PIT control address */ #define PIT_COUNT 0x42 /* PIT count address */ #define PIT_MODE 0xB6 /* set timer mode for sound generation */ /* * Magic numbers for timer control. */ #define TIMER_CLK 1193180L /* corresponds to 18.2 MHz tick rate */ static int endtone() /* turn off the speaker, ending current tone */ { wakeup((caddr_t)endtone); outb(PPI, inb(PPI) & ~PPI_SPKR); } static void tone(hz, ticks) /* emit tone of frequency hz for given number of ticks */ unsigned int hz, ticks; { unsigned int divisor = TIMER_CLK / hz; int sps; #ifdef DEBUG printf("tone: hz=%d ticks=%d\n", hz, ticks); #endif /* DEBUG */ /* set timer to generate clicks at given frequency in Hertz */ sps = spltty(); outb(PIT_CTRL, PIT_MODE); /* prepare timer */ outb(PIT_COUNT, (unsigned char) divisor); /* send lo byte */ outb(PIT_COUNT, (divisor >> 8)); /* send hi byte */ splx(sps); /* turn the speaker on */ outb(PPI, inb(PPI) | PPI_SPKR); /* * Set timeout to endtone function, then give up the timeslice. * This is so other processes can execute while the tone is being * emitted. */ timeout((caddr_t)endtone, (caddr_t)NULL, ticks); sleep((caddr_t)endtone, PZERO - 1); } static int endrest() /* end a rest */ { wakeup((caddr_t)endrest); } static void rest(ticks) /* rest for given number of ticks */ int ticks; { /* * Set timeout to endrest function, then give up the timeslice. * This is so other processes can execute while the rest is being * waited out. */ #ifdef DEBUG printf("rest: %d\n", ticks); #endif /* DEBUG */ timeout((caddr_t)endrest, (caddr_t)NULL, ticks); sleep((caddr_t)endrest, PZERO - 1); } /**************** PLAY STRING INTERPRETER BEGINS HERE ********************** * * Play string interpretation is modelled on IBM BASIC 2.0's PLAY statement; * M[LNS] are missing and the ~ synonym and octave-tracking facility is added. * Requires tone(), rest(), and endtone(). String play is not interruptible * except possibly at physical block boundaries. */ typedef int bool; #define TRUE 1 #define FALSE 0 #define toupper(c) ((c) - ' ' * (((c) >= 'a') && ((c) <= 'z'))) #define isdigit(c) (((c) >= '0') && ((c) <= '9')) #define dtoi(c) ((c) - '0') static int octave; /* currently selected octave */ static int whole; /* whole-note time at current tempo, in ticks */ static int value; /* whole divisor for note time, quarter note = 1 */ static int fill; /* controls spacing of notes */ static bool octtrack; /* octave-tracking on? */ static bool octprefix; /* override current octave-tracking state? */ /* * Magic number avoidance... */ #define SECS_PER_MIN 60 /* seconds per minute */ #define WHOLE_NOTE 4 /* quarter notes per whole note */ #define MIN_VALUE 64 /* the most we can divide a note by */ #define DFLT_VALUE 4 /* default value (quarter-note) */ #define FILLTIME 8 /* for articulation, break note in parts */ #define STACCATO 6 /* 6/8 = 3/4 of note is filled */ #define NORMAL 7 /* 7/8ths of note interval is filled */ #define LEGATO 8 /* all of note interval is filled */ #define DFLT_OCTAVE 4 /* default octave */ #define MIN_TEMPO 32 /* minimum tempo */ #define DFLT_TEMPO 120 /* default tempo */ #define MAX_TEMPO 255 /* max tempo */ #define NUM_MULT 3 /* numerator of dot multiplier */ #define DENOM_MULT 2 /* denominator of dot multiplier */ /* letter to half-tone: A B C D E F G */ static int notetab[8] = {9, 11, 0, 2, 4, 5, 7}; /* * This is the American Standard A440 Equal-Tempered scale with frequencies * rounded to nearest integer. Thank Goddess for the good ol' CRC Handbook... * our octave 0 is standard octave 2. */ #define OCTAVE_NOTES 12 /* semitones per octave */ static int pitchtab[] = { /* C C# D D# E F F# G G# A A# B*/ /* 0 */ 65, 69, 73, 78, 82, 87, 93, 98, 103, 110, 117, 123, /* 1 */ 131, 139, 147, 156, 165, 175, 185, 196, 208, 220, 233, 247, /* 2 */ 262, 277, 294, 311, 330, 349, 370, 392, 415, 440, 466, 494, /* 3 */ 523, 554, 587, 622, 659, 698, 740, 784, 831, 880, 932, 988, /* 4 */ 1047, 1109, 1175, 1245, 1319, 1397, 1480, 1568, 1661, 1760, 1865, 1975, /* 5 */ 2093, 2217, 2349, 2489, 2637, 2794, 2960, 3136, 3322, 3520, 3729, 3951, /* 6 */ 4186, 4435, 4698, 4978, 5274, 5588, 5920, 6272, 6644, 7040, 7459, 7902, }; static void playinit() { octave = DFLT_OCTAVE; whole = (hz * SECS_PER_MIN * WHOLE_NOTE) / DFLT_TEMPO; fill = NORMAL; value = DFLT_VALUE; octtrack = FALSE; octprefix = TRUE; /* act as though there was an initial O(n) */ } static void playtone(pitch, value, sustain) /* play tone of proper duration for current rhythm signature */ int pitch, value, sustain; { register int sound, silence, snum = 1, sdenom = 1; /* this weirdness avoids floating-point arithmetic */ for (; sustain; sustain--) { snum *= NUM_MULT; sdenom *= DENOM_MULT; } if (pitch == -1) rest(whole * snum / (value * sdenom)); else { sound = (whole * snum) / (value * sdenom) - (whole * (FILLTIME - fill)) / (value * FILLTIME); silence = whole * (FILLTIME-fill) * snum / (FILLTIME * value * sdenom); #ifdef DEBUG printf("playtone: pitch %d for %d ticks, rest for %d ticks\n", pitch, sound, silence); #endif /* DEBUG */ tone(pitchtab[pitch], sound); if (fill != LEGATO) rest(silence); } } static int abs(n) int n; { if (n < 0) return(-n); else return(n); } static void playstring(cp, slen) /* interpret and play an item from a notation string */ char *cp; size_t slen; { int pitch, lastpitch = OCTAVE_NOTES * DFLT_OCTAVE; #define GETNUM(cp, v) for(v=0; isdigit(cp[1]) && slen > 0; ) \ {v = v * 10 + (*++cp - '0'); slen--;} for (; slen--; cp++) { int sustain, timeval, tempo; register char c = toupper(*cp); #ifdef DEBUG printf("playstring: %c (%x)\n", c, c); #endif /* DEBUG */ switch (c) { case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': /* compute pitch */ pitch = notetab[c - 'A'] + octave * OCTAVE_NOTES; /* this may be followed by an accidental sign */ if (cp[1] == '#' || cp[1] == '+') { ++pitch; ++cp; slen--; } else if (cp[1] == '-') { --pitch; ++cp; slen--; } /* * If octave-tracking mode is on, and there has been no octave- * setting prefix, find the version of the current letter note * closest to the last regardless of octave. */ if (octtrack && !octprefix) { if (abs(pitch-lastpitch) > abs(pitch+OCTAVE_NOTES-lastpitch)) { ++octave; pitch += OCTAVE_NOTES; } if (abs(pitch-lastpitch) > abs((pitch-OCTAVE_NOTES)-lastpitch)) { --octave; pitch -= OCTAVE_NOTES; } } octprefix = FALSE; lastpitch = pitch; /* ...which may in turn be followed by an override time value */ GETNUM(cp, timeval); if (timeval <= 0 || timeval > MIN_VALUE) timeval = value; /* ...and/or sustain dots */ for (sustain = 0; cp[1] == '.'; cp++) { slen--; sustain++; } /* time to emit the actual tone */ playtone(pitch, timeval, sustain); break; case 'O': if (cp[1] == 'N' || cp[1] == 'n') { octprefix = octtrack = FALSE; ++cp; slen--; } else if (cp[1] == 'L' || cp[1] == 'l') { octtrack = TRUE; ++cp; slen--; } else { GETNUM(cp, octave); if (octave >= sizeof(pitchtab) / OCTAVE_NOTES) octave = DFLT_OCTAVE; octprefix = TRUE; } break; case '>': if (octave < sizeof(pitchtab) / OCTAVE_NOTES - 1) octave++; octprefix = TRUE; break; case '<': if (octave > 0) octave--; octprefix = TRUE; break; case 'N': GETNUM(cp, pitch); for (sustain = 0; cp[1] == '.'; cp++) { slen--; sustain++; } playtone(pitch - 1, value, sustain); break; case 'L': GETNUM(cp, value); if (value <= 0 || value > MIN_VALUE) value = DFLT_VALUE; break; case 'P': case '~': /* this may be followed by an override time value */ GETNUM(cp, timeval); if (timeval <= 0 || timeval > MIN_VALUE) timeval = value; for (sustain = 0; cp[1] == '.'; cp++) { slen--; sustain++; } playtone(-1, timeval, sustain); break; case 'T': GETNUM(cp, tempo); if (tempo < MIN_TEMPO || tempo > MAX_TEMPO) tempo = DFLT_TEMPO; whole = (hz * SECS_PER_MIN * WHOLE_NOTE) / tempo; break; case 'M': if (cp[1] == 'N' || cp[1] == 'n') { fill = NORMAL; ++cp; slen--; } else if (cp[1] == 'L' || cp[1] == 'l') { fill = LEGATO; ++cp; slen--; } else if (cp[1] == 'S' || cp[1] == 's') { fill = STACCATO; ++cp; slen--; } break; } } } /******************* UNIX DRIVER HOOKS BEGIN HERE ************************** * * This section implements driver hooks to run playstring() and the tone(), * endtone(), and rest() functions defined above. */ static int spkr_active; /* exclusion flag */ static struct buf *spkr_inbuf; /* incoming buf */ int spkropen(dev) dev_t dev; { #ifdef DEBUG printf("spkropen: entering with dev = %x\n", dev); #endif /* DEBUG */ if (minor(dev) != 0) return(ENXIO); else if (spkr_active) return(EBUSY); else { playinit(); spkr_inbuf = geteblk(DEV_BSIZE); spkr_active = 1; } return(0); } int spkrwrite(dev, uio) dev_t dev; struct uio *uio; { register unsigned n; char *cp; int error; #ifdef DEBUG printf("spkrwrite: entering with dev = %x, count = %d\n", dev, uio->uio_resid); #endif /* DEBUG */ if (minor(dev) != 0) return(ENXIO); else { n = MIN(DEV_BSIZE, uio->uio_resid); cp = spkr_inbuf->b_un.b_addr; error = uiomove(cp, n, uio); if (!error) playstring(cp, n); return(error); } } int spkrclose(dev) dev_t dev; { #ifdef DEBUG printf("spkrclose: entering with dev = %x\n", dev); #endif /* DEBUG */ if (minor(dev) != 0) return(ENXIO); else { endtone(); brelse(spkr_inbuf); spkr_active = 0; } return(0); } int spkrioctl(dev, cmd, cmdarg) dev_t dev; int cmd; caddr_t cmdarg; { #ifdef DEBUG printf("spkrioctl: entering with dev = %x, cmd = %x\n", dev, cmd); #endif /* DEBUG */ if (minor(dev) != 0) return(ENXIO); else if (cmd == SPKRTONE) { tone_t *tp = (tone_t *)cmdarg; if (tp->frequency == 0) rest(tp->duration); else tone(tp->frequency, tp->duration); } else if (cmd == SPKRTUNE) { tone_t *tp = (tone_t *)(*(caddr_t *)cmdarg); tone_t ttp; int error; for (; ; tp++) { error = copyin(tp, &ttp, sizeof(tone_t)); if (error) return(error); if (ttp.duration == 0) break; if (ttp.frequency == 0) rest(ttp.duration); else tone(ttp.frequency, ttp.duration); } } else return(EINVAL); return(0); } #endif /* NSPEAKER > 0 */ /* spkr.c ends here */ Index: head/sys/dev/syscons/syscons.c =================================================================== --- head/sys/dev/syscons/syscons.c (revision 618) +++ head/sys/dev/syscons/syscons.c (revision 619) @@ -1,2416 +1,2414 @@ /*- * 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: @(#)pccons.c 5.11 (Berkeley) 5/21/91 + * from: @(#)syscons.c 1.0 930928 + * $Id$ + * * Heavily modified by Søren Schmidt (sos@login.dkuug.dk) to provide: * * virtual consoles, SYSV ioctl's, ANSI emulation - * - * @(#)syscons.c 1.0 930928 - * Derived from: - * @(#)pccons.c 5.11 (Berkeley) 5/21/91 */ #define STAR_SAVER /* #define FAT_CURSOR /* This breaks on some CGA displays */ #include "param.h" #include "conf.h" #include "ioctl.h" #include "proc.h" #include "user.h" #include "tty.h" #include "uio.h" #include "callout.h" #include "systm.h" #include "kernel.h" #include "syslog.h" #include "errno.h" #include "machine/console.h" #include "malloc.h" #include "i386/isa/icu.h" #include "i386/isa/isa.h" #include "i386/isa/isa_device.h" #include "machine/pc/display.h" #include "i386/i386/cons.h" #include "machine/psl.h" #include "machine/frame.h" #include "sc.h" #include "ddb.h" #include "iso8859.font" #include "kbdtables.h" #if NSC > 0 #ifndef NCONS #define NCONS 12 #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 /* virtual video memory addresses */ #define MONO_BUF (KERNBASE + 0xB0000) #define CGA_BUF (KERNBASE + 0xB8000) #define VGA_BUF (KERNBASE + 0xA0000) #define VIDEOMEM 0x000A0000 #define MEMSIZE 0x00020000 /* misc defines */ #define MAX_ESC_PAR 3 #define TEXT80x25 1 #define TEXT80x50 2 #define COL 80 #define ROW 25 #ifndef XTALSPEED #define XTALSPEED 1193182 /* should be in isa.h */ #endif /* 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 */ typedef struct term_stat { int esc; /* processing escape sequence */ int n_par; /* # of parameters to ESC */ int last_par; /* last parameter # */ int par[MAX_ESC_PAR]; /* contains ESC parameters */ int 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; /* buffer when off screen */ u_short *crtat; /* cursor address */ int posx; /* current X position */ int posy; /* current Y position */ int max_posx; /* X size */ int max_posy; /* X size */ term_stat term; /* terminal emulation stuff */ char cursor_start; /* cursor start line # */ char cursor_end; /* cursor start end # */ 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 default_attr *current_default; static scr_stat cons_scr_stat[NCONS]; static scr_stat *cur_scr_stat = &cons_scr_stat[0]; static scr_stat *new_scp, *old_scp; static term_stat kernel_console; static int switch_in_progress = 0; u_short *Crtat = (u_short *)MONO_BUF; 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; static u_char nlkcnt = 0, clkcnt = 0, slkcnt = 0, alkcnt = 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, nx_scr; static char saved_console = -1; /* saved console number */ static long scrn_blank_time = 0; /* screen saver timout value */ static int scrn_blanked = 0; /* screen saver active flag */ static long scrn_time_stamp; static u_char scr_map[256]; struct tty pccons[NCONS]; struct tty *cur_pccons = &pccons[0]; struct tty *new_pccons; extern int hz; extern struct timeval time; #define CSF_ACTIVE 0x1 /* timeout active */ #define CSF_POLLING 0x2 /* polling for input */ struct pcconsoftc { char cs_flags; char cs_lastc; /* last char sent */ int cs_timo; /* timeouts since interrupt */ u_long cs_wedgecnt; /* times restarted */ } pcconsoftc = {0, 0, 0, 0}; /* special characters */ #define bs 8 #define lf 10 #define cr 13 #define cntlc 3 #define del 0177 #define cntld 4 /* 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); int pcxint(dev_t dev); int pcstart(struct tty *tp); int pccnprobe(struct consdev *cp); int pccninit(struct consdev *cp); int pccnputc(dev_t dev, char c); int pccngetc(dev_t dev); int scintr(dev_t dev, int irq, int cpl); void scrn_saver(int test); static struct tty *get_pccons(dev_t dev); static scr_stat *get_scr_stat(dev_t dev); static int get_scr_num(scr_stat *scp); static void cursor_shape(int start, int end); static void get_cursor_shape(int *start, int *end); static void cursor_pos(void); static void clear_screen(scr_stat *scp); static 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); void consinit(void); static void sput(u_char c); static u_char *get_fstr(u_int c, u_int *len); static update_leds(int which); void reset_cpu(void); u_int sgetc(int noblock); int pcmmap(dev_t dev, int offset, int nprot); int getchar(void); 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 load_font(int segment, int size, char* font); static void save_palette(void); static void load_palette(void); static change_winsize(struct tty *tp, int x, int y); struct isa_driver scdriver = { pcprobe, pcattach, "sc", }; int pcprobe(struct isa_device *dev) { u_char c; int again = 0; /* Enable interrupts and keyboard controller */ kbd_wait(); outb(KB_STAT, KB_WRITE); kbd_cmd(0x4D); /* Start keyboard stuff RESET */ kbd_cmd(KB_RESET); while ((c=inb(KB_DATA)) != KB_ACK) { if ((c == 0xFE) || (c == 0xFF)) { if (!again) printf("KEYBOARD disconnected: RECONNECT \n"); kbd_cmd(KB_RESET); again = 1; } } kbd_wait(); return (IO_KBDSIZE); } int pcattach(struct isa_device *dev) { scr_stat *scp; int start = -1, end = -1, i; 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 (crtc_vga) { #ifdef FAT_CURSOR start = 0; end = 18; #else get_cursor_shape(&start, &end); #endif save_palette(); load_font(0, 16, font_8x16); load_font(1, 8, font_8x8); load_font(2, 14, font_8x14); } current_default = &user_default; for (i = 0; i < NCONS; i++) { scp = &cons_scr_stat[i]; scp->scr = (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.attr = scp->term.std_attr; scp->border = BG_BLACK; scp->cursor_start = start; scp->cursor_end = end; scp->max_posx = COL; scp->max_posy = ROW; scp->bell_pitch = 800; scp->bell_duration = 10; scp->status = 0; scp->pid = 0; scp->proc = NULL; scp->smode.mode = VT_AUTO; if (i > 0) { scp->crt_base = scp->crtat = scp->scr; fillw(scp->term.attr|scr_map[0x20], scp->scr, COL*ROW); } } /* get cursor going */ #ifdef FAT_CURSOR cursor_shape(cons_scr_stat[0].cursor_start, cons_scr_stat[0].cursor_end); #endif cursor_pos(); } static struct tty *get_pccons(dev_t dev) { int i = minor(dev); if (i >= NCONS) return(NULL); return(&pccons[i]); } static scr_stat *get_scr_stat(dev_t dev) { int i = minor(dev); if (i >= NCONS) return(NULL); return(&cons_scr_stat[i]); } static int get_scr_num(scr_stat *scp) /* allways call with legal scp !! */ { int i = 0; while ((i < NCONS) && (cur_scr_stat != &cons_scr_stat[i])) i++; return i; } pcopen(dev_t dev, int flag, int mode, struct proc *p) { struct tty *tp = get_pccons(dev); if (!tp) return(ENXIO); tp->t_oproc = pcstart; tp->t_param = pcparam; tp->t_dev = dev; if ((tp->t_state & TS_ISOPEN) == 0) { tp->t_state |= TS_WOPEN; ttychars(tp); tp->t_iflag = TTYDEF_IFLAG; tp->t_oflag = TTYDEF_OFLAG; tp->t_cflag = TTYDEF_CFLAG; tp->t_lflag = TTYDEF_LFLAG; tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; pcparam(tp, &tp->t_termios); ttsetwater(tp); } else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0) return(EBUSY); tp->t_state |= TS_CARR_ON; return((*linesw[tp->t_line].l_open)(dev, tp)); } pcclose(dev_t dev, int flag, int mode, struct proc *p) { struct tty *tp = get_pccons(dev); struct scr_stat *scp; if (!tp) return(ENXIO); scp = get_scr_stat(tp->t_dev); scp->pid = 0; scp->proc = NULL; scp->smode.mode = VT_AUTO; (*linesw[tp->t_line].l_close)(tp, flag); ttyclose(tp); return(0); } pcread(dev_t dev, struct uio *uio, int flag) { struct tty *tp = get_pccons(dev); if (!tp) return(ENXIO); return((*linesw[tp->t_line].l_read)(tp, uio, flag)); } pcwrite(dev_t dev, struct uio *uio, int flag) { struct tty *tp = get_pccons(dev); if (!tp) return(ENXIO); return((*linesw[tp->t_line].l_write)(tp, uio, flag)); } /* * Got a console interrupt, keyboard action ! * Catch the character, and see who it goes to. */ scintr(dev_t dev, int irq, int cpl) { int c, len; u_char *cp; /* make screensaver happy */ scrn_time_stamp = time.tv_sec; if (scrn_blanked) scrn_saver(0); c = sgetc(1); if (c & 0x100) return; if ((cur_pccons->t_state & TS_ISOPEN) == 0) return; if (pcconsoftc.cs_flags & CSF_POLLING) return; if (c < 0x100) (*linesw[cur_pccons->t_line].l_rint)(c & 0xFF, cur_pccons); else if (cp = get_fstr((u_int)c, (u_int *)&len)) { while (len-- > 0) (*linesw[cur_pccons->t_line].l_rint) (*cp++ & 0xFF, cur_pccons); } } /* * Set line parameters */ 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); } pcioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) { int i, error; struct tty *tp; struct syscframe *fp; scr_stat *scp; tp = get_pccons(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_80x25TEXT: /* set 80x25 text mode */ if (!crtc_vga) return ENXIO; scp->mode = TEXT80x25; scp->max_posy = 25; free(scp->scr, M_DEVBUF); scp->scr = (u_short *)malloc(scp->max_posx*scp->max_posy*2, M_DEVBUF, M_NOWAIT); if (scp != cur_scr_stat) scp->crt_base = scp->scr; set_mode(scp); clear_screen(scp); change_winsize(tp, scp->max_posx, scp->max_posy); return 0; case CONS_80x50TEXT: /* set 80x50 text mode */ if (!crtc_vga) return ENXIO; scp->mode = TEXT80x50; scp->max_posy = 50; free(scp->scr, M_DEVBUF); scp->scr = (u_short *)malloc(scp->max_posx*scp->max_posy*2, M_DEVBUF, M_NOWAIT); if (scp != cur_scr_stat) scp->crt_base = scp->scr; set_mode(scp); clear_screen(scp); change_winsize(tp, scp->max_posx, scp->max_posy); return 0; case CONS_GETVERS: /* get version number */ *(int*)data = 0x100; /* version 1.0 */ return 0; case CONS_GETINFO: /* get current (virtual) console info */ if (*data == sizeof(struct vid_info)) { vid_info_t *ptr = (vid_info_t*)data; ptr->m_num = get_scr_num(scp); ptr->mv_col = scp->posx; ptr->mv_row = scp->posy; ptr->mv_csz = scp->max_posx; ptr->mv_rsz = scp->max_posy; 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++) if (!(pccons[i].t_state & TS_ISOPEN)) { *data = i + 1; return 0; } return EINVAL; /* NOT REACHED */ case VT_GETACTIVE: /* return number of active virtual console */ *data = get_scr_num(scp) + 1; return 0; 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_scr_stat) return 0; while ((error=tsleep(&scp->smode, PZERO|PCATCH, "waitvt", 0)) == ERESTART) ; } else while ((error=tsleep(&cons_scr_stat[*data].smode, PZERO|PCATCH, "waitvt", 0)) == ERESTART) ; return error; case KDENABIO: /* allow io operations */ fp = (struct syscframe *)p->p_regs; fp->sf_eflags |= PSL_IOPL; return 0; case KDDISABIO: /* disallow io operations (default) */ fp = (struct syscframe *)p->p_regs; fp->sf_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) { load_font(0, 16, font_8x16); load_font(1, 8, font_8x8); load_font(2, 14, font_8x14); 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_scr_stat) 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_scr_stat) update_leds(scp->status & LED_MASK); 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 (*(u_char*)data < 0x80) { kbd_cmd(KB_SETRAD); kbd_cmd(*data & 0x7f); return 0; } return EINVAL; 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 */ 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_scr_stat) sysbeep(scp->bell_pitch, scp->bell_duration); return 0; case KIOCSOUND: /* make tone (*data) hz */ if (scp == cur_scr_stat) { if (*(int*)data) { int pitch = XTALSPEED/(*(int*)data); /* enable counter 2 */ outb(0x61, inb(0x61) | 3); /* set command for counter 2, 2 byte write */ outb(0x43, 0xb6); /* set pitch */ outb(0x42, pitch); outb(0x42, (pitch>>8)); } else { /* disable counter 2 */ outb(0x61, inb(0x61) & 0xFC); } } 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_scr_stat) update_leds(scp->status & LED_MASK); 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_8x8, sizeof(font_8x8)); load_font(1, 8, font_8x8); return 0; case GIO_FONT8x8: /* get 8x8 dot font */ if (!crtc_vga) return ENXIO; bcopy(&font_8x8, data, sizeof(font_8x8)); return 0; case PIO_FONT8x14: /* set 8x14 dot font */ if (!crtc_vga) return ENXIO; bcopy(data, &font_8x14, sizeof(font_8x14)); load_font(2, 14, font_8x14); return 0; case GIO_FONT8x14: /* get 8x14 dot font */ if (!crtc_vga) return ENXIO; bcopy(&font_8x14, data, sizeof(font_8x14)); return 0; case PIO_FONT8x16: /* set 8x16 dot font */ if (!crtc_vga) return ENXIO; bcopy(data, &font_8x16, sizeof(font_8x16)); load_font(0, 16, font_8x16); return 0; case GIO_FONT8x16: /* get 8x16 dot font */ if (!crtc_vga) return ENXIO; bcopy(&font_8x16, data, sizeof(font_8x16)); return 0; case CONSOLE_X_MODE_ON: /* just to be compatible */ if (saved_console < 0) { saved_console = get_scr_num(cur_scr_stat); switch_scr(minor(dev)); fp = (struct syscframe *)p->p_regs; fp->sf_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 syscframe *)p->p_regs; fp->sf_eflags &= ~PSL_IOPL; if (crtc_vga) { load_font(0, 16, font_8x16); load_font(1, 8, font_8x8); load_font(2, 14, font_8x14); 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(XTALSPEED/((int*)data)[0], ((int*)data)[1]*hz/3000); else sysbeep(0x31b, hz/4); return 0; default: break; } error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); if (error >= 0) return(error); error = ttioctl(tp, cmd, data, flag); if (error >= 0) return(error); return(ENOTTY); } pcxint(dev_t dev) { pccons[minor(dev)].t_state &= ~TS_BUSY; pcconsoftc.cs_timo = 0; if (pccons[minor(dev)].t_line) (*linesw[pccons[minor(dev)].t_line].l_start) (&pccons[minor(dev)]); else pcstart(&pccons[minor(dev)]); } pcstart(struct tty *tp) { int c, s; scr_stat *scp = get_scr_stat(tp->t_dev); s = spltty(); if (!(tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))) for (;;) { if (RB_LEN(&tp->t_out) <= tp->t_lowat) { if (tp->t_state & TS_ASLEEP) { tp->t_state &= ~TS_ASLEEP; wakeup((caddr_t)&tp->t_out); } if (tp->t_wsel) { selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); tp->t_wsel = 0; tp->t_state &= ~TS_WCOLL; } } if (RB_LEN(&tp->t_out) == 0) break; if (scp->status & SLKED) break; c = getc(&tp->t_out); tp->t_state |= TS_BUSY; splx(s); ansi_put(scp, c); s = spltty(); tp->t_state &= ~TS_BUSY; } splx(s); } pccnprobe(struct consdev *cp) { int maj; /* locate the major number */ for (maj = 0; maj < nchrdev; maj++) if (cdevsw[maj].d_open == pcopen) break; /* initialize required fields */ cp->cn_dev = makedev(maj, 0); cp->cn_tp = &pccons[0]; cp->cn_pri = CN_INTERNAL; } pccninit(struct consdev *cp) { } pccnputc(dev_t dev, char c) { int pos; if (cur_scr_stat->status & UNKNOWN_MODE) return; if (c == '\n') sput('\r'); sput(c); pos = cur_scr_stat->crtat - cur_scr_stat->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); } } pccngetc(dev_t dev) { int c, s; s = spltty(); /* block scintr while we poll */ c = sgetc(0); splx(s); if (c == '\r') c = '\n'; return(c); } #if !defined(STAR_SAVER) && !defined(SNAKE_SAVER) void scrn_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); } } #endif #if defined(STAR_SAVER) || defined(SNAKE_SAVER) static u_long rand_next = 1; static rand() { return ((rand_next = rand_next * 1103515245 + 12345) & 0x7FFFFFFF); } #endif #ifdef STAR_SAVER /* * Alternate saver that got its inspiration from a well known utility * package for an unfamous OS. */ #define NUM_STARS 50 void scrn_saver(int test) { scr_stat *scp = cur_scr_stat; 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, scp->max_posx * scp->max_posy * 2); fillw((FG_LIGHTGREY|BG_BLACK)<<8 | scr_map[0x20], Crtat, scp->max_posx * scp->max_posy); set_border(0); i = scp->max_posy * scp->max_posx + 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; imax_posx*scp->max_posy); stars[i][1] = 0; } } cell = rand() % NUM_STARS; *((u_short*)(Crtat + stars[cell][0])) = scr_map[pattern[stars[cell][1]]] | colors[rand()%sizeof(colors)] << 8; if ((stars[cell][1]+=(rand()%4)) >= sizeof(pattern)-1) { stars[cell][0] = rand() % (scp->max_posx*scp->max_posy); stars[cell][1] = 0; } } else { if (scrn_blanked) { bcopy(scp->scr, Crtat, scp->max_posx*scp->max_posy*2); cur_cursor_pos = -1; set_border(scp->border); scrn_blanked = 0; } } } #endif #ifdef SNAKE_SAVER /* * alternative screen saver for cards that do not like blanking */ void scrn_saver(int test) { const char saves[] = {"FreeBSD"}; static u_char *savs[sizeof(saves)-1]; static int dirx, diry; int f; scr_stat *scp = cur_scr_stat; if (test) { if (!scrn_blanked) { bcopy(Crtat, scp->scr, scp->max_posx * scp->max_posy * 2); fillw((FG_LIGHTGREY|BG_BLACK)<<8 | scr_map[0x20], Crtat, scp->max_posx * scp->max_posy); set_border(0); dirx = (scp->posx ? 1 : -1); diry = (scp->posy ? scp->max_posx : -scp->max_posx); for (f=0; f< sizeof(saves)-1; f++) savs[f] = (u_char *)Crtat + 2 * (scp->posx+scp->posy*scp->max_posx); *(savs[0]) = scr_map[*saves]; f = scp->max_posy * scp->max_posx + 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->max_posx) == 0 || (f % scp->max_posx) == scp->max_posx - 1 || (rand() % 50) == 0) dirx = -dirx; if ((f / scp->max_posx) == 0 || (f / scp->max_posx) == scp->max_posy - 1 || (rand() % 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, Crtat, scp->max_posx * scp->max_posy * 2); cur_cursor_pos = -1; set_border(scp->border); scrn_blanked = 0; } } } #endif 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); } 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; } static void cursor_pos(void) { int pos; if (cur_scr_stat->status & UNKNOWN_MODE) return; if (scrn_blank_time && (time.tv_sec > scrn_time_stamp+scrn_blank_time)) scrn_saver(1); pos = cur_scr_stat->crtat - cur_scr_stat->crt_base; if (!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(cursor_pos, 0, hz/20); } static void clear_screen(scr_stat *scp) { move_crsr(scp, 0, 0); fillw(scp->term.attr | scr_map[0x20], scp->crt_base, scp->max_posx * scp->max_posy); } static switch_scr(u_int next_scr) { if (in_putc) { /* don't switch if in putc */ nx_scr = next_scr+1; return 0; } if (switch_in_progress && (cur_scr_stat->proc != pfind(cur_scr_stat->pid))) switch_in_progress = 0; if (next_scr >= NCONS || switch_in_progress) { sysbeep(800, hz/4); return -1; } switch_in_progress = 1; old_scp = cur_scr_stat; new_scp = &cons_scr_stat[next_scr]; wakeup(&new_scp->smode); if (new_scp == old_scp) { switch_in_progress = 0; return 0; } new_pccons = &pccons[next_scr]; /* 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) { bcopy(Crtat, old_scp->scr, old_scp->max_posx * old_scp->max_posy * 2); old_scp->crt_base = old_scp->scr; move_crsr(old_scp, old_scp->posx, old_scp->posy); cur_scr_stat = new_scp; cur_pccons = new_pccons; if (old_scp->status & KBD_RAW_MODE || new_scp->status & KBD_RAW_MODE) shfts = ctls = alts = 0; update_leds(new_scp->status & LED_MASK); set_mode(new_scp); new_scp->crt_base = Crtat; move_crsr(new_scp, new_scp->posx, new_scp->posy); bcopy(new_scp->scr, Crtat, new_scp->max_posx * new_scp->max_posy * 2); nx_scr = 0; } static void move_crsr(scr_stat *scp, int x, int y) { if (x < 0 || y < 0 || x >= scp->max_posx || y >= scp->max_posy) return; scp->posx = x; scp->posy = y; scp->crtat = scp->crt_base + scp->posy * scp->max_posx + scp->posx; } 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_par = -1; for (i = scp->term.n_par; i < MAX_ESC_PAR; i++) scp->term.par[i] = 1; scp->term.n_par = 0; return; case 'M': /* Move cursor up 1 line, scroll if at top */ if (scp->posy > 0) move_crsr(scp, scp->posx, scp->posy - 1); else { move_up(scp->crt_base, scp->crt_base + scp->max_posx, (scp->max_posy - 1) * scp->max_posx); fillw(scp->term.attr | scr_map[0x20], scp->crt_base, scp->max_posx); } 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.n_par < MAX_ESC_PAR) { if (scp->term.last_par != scp->term.n_par) { scp->term.last_par = scp->term.n_par; scp->term.par[scp->term.n_par] = 0; } else scp->term.par[scp->term.n_par] *= 10; scp->term.par[scp->term.n_par] += c - '0'; return; } } scp->term.n_par = scp->term.last_par + 1; switch (c) { case ';': if (scp->term.n_par < MAX_ESC_PAR) return; break; case '=': scp->term.esc = 3; scp->term.last_par = -1; for (i = scp->term.n_par; i < MAX_ESC_PAR; i++) scp->term.par[i] = 1; scp->term.n_par = 0; return; case 'A': /* up n rows */ n = scp->term.par[0]; if (n < 1) n = 1; move_crsr(scp, scp->posx, scp->posy - n); break; case 'B': /* down n rows */ n = scp->term.par[0]; if (n < 1) n = 1; move_crsr(scp, scp->posx, scp->posy + n); break; case 'C': /* right n columns */ n = scp->term.par[0]; if (n < 1) n = 1; move_crsr(scp, scp->posx + n, scp->posy); break; case 'D': /* left n columns */ n = scp->term.par[0]; if (n < 1) n = 1; move_crsr(scp, scp->posx - n, scp->posy); break; case 'E': /* cursor to start of line n lines down */ n = scp->term.par[0]; if (n < 1) n = 1; move_crsr(scp, 0, scp->posy + n); break; case 'F': /* cursor to start of line n lines up */ n = scp->term.par[0]; if (n < 1) n = 1; move_crsr(scp, 0, scp->posy - n); break; case 'f': /* System V consoles .. */ case 'H': /* Cursor move */ if (scp->term.n_par == 0) move_crsr(scp, 0, 0); else if (scp->term.n_par == 2) move_crsr(scp, scp->term.par[1] - 1, scp->term.par[0] - 1); break; case 'J': /* Clear all or part of display */ if (scp->term.n_par == 0) n = 0; else n = scp->term.par[0]; switch (n) { case 0: /* clear form cursor to end of display */ fillw(scp->term.attr | scr_map[0x20], scp->crtat, scp->crt_base + scp->max_posx * scp->max_posy - scp->crtat); break; case 1: /* clear from beginning of display to cursor */ fillw(scp->term.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.n_par == 0) n = 0; else n = scp->term.par[0]; switch (n) { case 0: /* clear form cursor to end of line */ fillw(scp->term.attr | scr_map[0x20], scp->crtat, scp->max_posx - scp->posx); break; case 1: /* clear from beginning of line to cursor */ fillw(scp->term.attr|scr_map[0x20], scp->crtat - (scp->max_posx - scp->posx), (scp->max_posx - scp->posx) + 1); break; case 2: /* clear entire line */ fillw(scp->term.attr|scr_map[0x20], scp->crtat - (scp->max_posx - scp->posx), scp->max_posx); break; } break; case 'L': /* Insert n lines */ n = scp->term.par[0]; if (n < 1) n = 1; if (n > scp->max_posy - scp->posy) n = scp->max_posy - scp->posy; src = scp->crt_base + scp->posy * scp->max_posx; dst = src + n * scp->max_posx; count = scp->max_posy - (scp->posy + n); move_up(src, dst, count * scp->max_posx); fillw(scp->term.attr | scr_map[0x20], src, n * scp->max_posx); break; case 'M': /* Delete n lines */ n = scp->term.par[0]; if (n < 1) n = 1; if (n > scp->max_posy - scp->posy) n = scp->max_posy - scp->posy; dst = scp->crt_base + scp->posy * scp->max_posx; src = dst + n * scp->max_posx; count = scp->max_posy - (scp->posy + n); move_down(src, dst, count * scp->max_posx); src = dst + count * scp->max_posx; fillw(scp->term.attr | scr_map[0x20], src, n * scp->max_posx); break; case 'P': /* Delete n chars */ n = scp->term.par[0]; if (n < 1) n = 1; if (n > scp->max_posx - scp->posx) n = scp->max_posx - scp->posx; dst = scp->crtat; src = dst + n; count = scp->max_posx - (scp->posx + n); move_down(src, dst, count); src = dst + count; fillw(scp->term.attr | scr_map[0x20], src, n); break; case '@': /* Insert n chars */ n = scp->term.par[0]; if (n < 1) n = 1; if (n > scp->max_posx - scp->posx) n = scp->max_posx - scp->posx; src = scp->crtat; dst = src + n; count = scp->max_posx - (scp->posx + n); move_up(src, dst, count); fillw(scp->term.attr | scr_map[0x20], src, n); break; case 'S': /* scroll up n lines */ n = scp->term.par[0]; if (n < 1) n = 1; bcopy(scp->crt_base + (scp->max_posx * n), scp->crt_base, scp->max_posx * (scp->max_posy - n) * sizeof(u_short)); fillw(scp->term.attr | scr_map[0x20], scp->crt_base + scp->max_posx * (scp->max_posy - 1), scp->max_posx); break; case 'T': /* scroll down n lines */ n = scp->term.par[0]; if (n < 1) n = 1; bcopy(scp->crt_base, scp->crt_base + (scp->max_posx * n), scp->max_posx * (scp->max_posy - n) * sizeof(u_short)); fillw(scp->term.attr | scr_map[0x20], scp->crt_base, scp->max_posx); break; case 'X': /* delete n characters in line */ n = scp->term.par[0]; if (n < 1) n = 1; fillw(scp->term.attr | scr_map[0x20], scp->crt_base + scp->posx + ((scp->max_posx*scp->posy) * sizeof(u_short)), n); break; case 'Z': /* move n tabs backwards */ n = scp->term.par[0]; if (n < 1) n = 1; if ((i = scp->posx & 0xf8) == scp->posx) i -= 8*n; else i -= 8*(n-1); if (i < 0) i = 0; move_crsr(scp, i, scp->posy); break; case '`': /* move cursor to column n */ n = scp->term.par[0]; if (n < 1) n = 1; move_crsr(scp, n, scp->posy); break; case 'a': /* move cursor n columns to the right */ n = scp->term.par[0]; if (n < 1) n = 1; move_crsr(scp, scp->posx + n, scp->posy); break; case 'd': /* move cursor to row n */ n = scp->term.par[0]; if (n < 1) n = 1; move_crsr(scp, scp->posx, n); break; case 'e': /* move cursor n rows down */ n = scp->term.par[0]; if (n < 1) n = 1; move_crsr(scp, scp->posx, scp->posy + n); break; case 'm': /* change attribute */ if (scp->term.n_par == 0) n = 0; else n = scp->term.par[0]; switch (n) { case 0: /* back to normal */ scp->term.attr = scp->term.std_attr; break; case 1: /* highlight (bold) */ scp->term.attr &= 0xFF00; scp->term.attr |= 0x0800; break; case 4: /* highlight (underline) */ scp->term.attr &= 0x0F00; scp->term.attr |= 0x0800; break; case 5: /* blink */ scp->term.attr &= 0xFF00; scp->term.attr |= 0x8000; break; case 7: /* reverse video */ scp->term.attr = scp->term.rev_attr; break; case 30: case 31: case 32: case 33: /* set fg color */ case 34: case 35: case 36: case 37: scp->term.attr = (scp->term.attr & 0xF0FF) | (ansi_col[(n - 30) & 7] << 8); break; case 40: case 41: case 42: case 43: /* set bg color */ case 44: case 45: case 46: case 47: scp->term.attr = (scp->term.attr & 0x0FFF) | (ansi_col[(n - 40) & 7] << 12); break; } break; case 'x': if (scp->term.n_par == 0) n = 0; else n = scp->term.par[0]; switch (n) { case 0: /* reset attributes */ scp->term.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.attr = scp->term.std_attr = (scp->term.std_attr & 0x0F00) | (ansi_col[(scp->term.par[1])&0x0F]<<12); break; case 2: /* set ansi foreground */ scp->term.attr = scp->term.std_attr = (scp->term.std_attr & 0xF000) | (ansi_col[(scp->term.par[1])&0x0F]<<8); break; case 3: /* set ansi attribute directly */ scp->term.attr = scp->term.std_attr = (scp->term.par[1]&0xFF)<<8; break; case 5: /* set ansi reverse video background */ scp->term.rev_attr = (scp->term.rev_attr & 0x0F00) | (ansi_col[(scp->term.par[1])&0x0F]<<12); break; case 6: /* set ansi reverse video foreground */ scp->term.rev_attr = (scp->term.rev_attr & 0xF000) | (ansi_col[(scp->term.par[1])&0x0F]<<8); break; case 7: /* set ansi reverse video directly */ scp->term.rev_attr = (scp->term.par[1]&0xFF)<<8; break; } break; case 'z': /* switch to (virtual) console n */ if (scp->term.n_par == 1) switch_scr(scp->term.par[0]); break; } } else if (scp->term.esc == 3) { if (c >= '0' && c <= '9') { if (scp->term.n_par < MAX_ESC_PAR) { if (scp->term.last_par != scp->term.n_par) { scp->term.last_par = scp->term.n_par; scp->term.par[scp->term.n_par] = 0; } else scp->term.par[scp->term.n_par] *= 10; scp->term.par[scp->term.n_par] += c - '0'; return; } } scp->term.n_par = scp->term.last_par + 1; switch (c) { case ';': if (scp->term.n_par < MAX_ESC_PAR) return; break; case 'A': /* set display border color */ if (scp->term.n_par == 1) scp->border=scp->term.par[0] & 0xff; if (scp == cur_scr_stat) set_border(scp->border); break; case 'B': /* set bell pitch and duration */ if (scp->term.n_par == 2) { scp->bell_pitch = scp->term.par[0]; scp->bell_duration = scp->term.par[1]*10; } break; case 'C': /* set cursor shape (start & end line) */ if (scp->term.n_par == 2) { scp->cursor_start = scp->term.par[0] & 0x1F; scp->cursor_end = scp->term.par[1] & 0x1F; if (scp == cur_scr_stat) cursor_shape(scp->cursor_start, scp->cursor_end); } break; case 'F': /* set ansi foreground */ if (scp->term.n_par == 1) scp->term.attr = scp->term.std_attr = (scp->term.std_attr & 0xF000) | ((scp->term.par[0] & 0x0F) << 8); break; case 'G': /* set ansi background */ if (scp->term.n_par == 1) scp->term.attr = scp->term.std_attr = (scp->term.std_attr & 0x0F00) | ((scp->term.par[0] & 0x0F) << 12); break; case 'H': /* set ansi reverse video foreground */ if (scp->term.n_par == 1) scp->term.rev_attr = (scp->term.rev_attr & 0xF000) | ((scp->term.par[0] & 0x0F) << 8); break; case 'I': /* set ansi reverse video background */ if (scp->term.n_par == 1) scp->term.rev_attr = (scp->term.rev_attr & 0x0F00) | ((scp->term.par[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_scr_stat) { 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.n_par = 0; break; case 0x07: if (scp == cur_scr_stat) sysbeep(scp->bell_pitch, scp->bell_duration); break; case '\t': /* non-destructive tab */ scp->crtat += (8 - scp->posx % 8); scp->posx += (8 - scp->posx % 8); break; case '\b': /* non-destructive backspace */ if (scp->crtat > scp->crt_base) { scp->crtat--; if (scp->posx > 0) scp->posx--; else { scp->posx += scp->max_posx - 1; scp->posy--; } } break; case '\r': /* return to pos 0 */ move_crsr(scp, 0, scp->posy); break; case '\n': /* newline, same pos */ scp->crtat += scp->max_posx; scp->posy++; break; case '\f': /* form feed, clears screen */ clear_screen(scp); break; default: /* Print only printables */ *scp->crtat = (scp->term.attr | scr_map[c]); scp->crtat++; if (++scp->posx >= scp->max_posx) { scp->posx = 0; scp->posy++; } break; } if (scp->crtat >= scp->crt_base + scp->max_posy * scp->max_posx) { bcopy(scp->crt_base + scp->max_posx, scp->crt_base, scp->max_posx * (scp->max_posy - 1) * sizeof(u_short)); fillw(scp->term.attr | scr_map[0x20], scp->crt_base + scp->max_posx * (scp->max_posy - 1), scp->max_posx); scp->crtat -= scp->max_posx; scp->posy--; } in_putc--; if (nx_scr) switch_scr(nx_scr - 1); } void consinit(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 consinit 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; cons_scr_stat[0].crtat = crtat; cons_scr_stat[0].crt_base = Crtat; cons_scr_stat[0].term.esc = 0; cons_scr_stat[0].term.std_attr = current_default->std_attr; cons_scr_stat[0].term.rev_attr = current_default->rev_attr; cons_scr_stat[0].term.attr = current_default->std_attr; cons_scr_stat[0].posx = cursorat % COL; cons_scr_stat[0].posy = cursorat / COL; cons_scr_stat[0].border = BG_BLACK;; cons_scr_stat[0].max_posx = COL; cons_scr_stat[0].max_posy = ROW; cons_scr_stat[0].status = 0; cons_scr_stat[0].pid = 0; cons_scr_stat[0].proc = NULL; cons_scr_stat[0].smode.mode = VT_AUTO; cons_scr_stat[0].bell_pitch = 800; cons_scr_stat[0].bell_duration = 10; kernel_console.esc = 0; kernel_console.std_attr = kernel_default.std_attr; kernel_console.rev_attr = kernel_default.rev_attr; kernel_console.attr = kernel_default.std_attr; /* initialize mapscrn array to */ for (i=0; iterm; scp->term = kernel_console; current_default = &kernel_default; ansi_put(scp, c); kernel_console = scp->term; current_default = &user_default; scp->term = save; } 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 update_leds(int which) { u_char xlate_leds[8] = { 0, 4, 2, 6, 1, 5, 3, 7 }; kbd_cmd(KB_SETLEDS); /* LED Command */ kbd_cmd(xlate_leds[which & LED_MASK]); kbd_wait(); } volatile void reset_cpu(void) { while (1) { kbd_cmd(KB_RESET_CPU); /* Reset Command */ DELAY(4000000); kbd_cmd(KB_RESET); /* Keyboard Reset Command */ } } /* * sgetc(noblock) : get a character from the keyboard. * If noblock = 0 wait until a key is gotten. Otherwise return a 0x100. */ u_int sgetc(int noblock) { u_char val, code, release; 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) val = inb(KB_DATA); else if (noblock) return(0x100); else goto next_code; if (cur_scr_stat->status & KBD_RAW_MODE) return val; code = val & 0x7F; release = val & 0x80; /* Check for cntl-alt-del */ if ((code == 83) && ctls && alts) cpu_reset(); #if NDDB > 0 /* Check for cntl-alt-esc */ if ((val == 1) && ctls && alts) { /* if debugger called, try to switch to console 0 */ if (cur_scr_stat->smode.mode == VT_AUTO && cons_scr_stat[0].smode.mode == VT_AUTO) switch_scr(0); Debugger(); return(0x100); } #endif switch (esc_flag) { case 0x00: /* normal scancode */ switch(code) { case 0x38: /* left alt (compose key) */ if (release && compose) { compose = 0; if (chr > 255) { sysbeep(500, hz/4); chr = 0; } } else { if (!compose) { compose = 1; chr = 0; } } break; case 0x60: case 0x61: esc_flag = code; goto next_code; } break; case 0x60: /* 0xE0 prefix */ esc_flag = 0; switch (code) { case 0x1c: /* right enter key */ code = 0x59; break; case 0x1d: /* right ctrl key */ code = 0x5a; break; case 0x35: /* keypad divide key */ code = 0x5b; break; case 0x37: /* print scrn key */ code = 0x5c; break; case 0x38: /* right alt key (alt gr) */ code = 0x5d; break; case 0x47: /* grey home key */ code = 0x5e; break; case 0x48: /* grey up arrow key */ code = 0x5f; break; case 0x49: /* grey page up key */ code = 0x60; break; case 0x4b: /* grey left arrow key */ code = 0x61; break; case 0x4d: /* grey right arrow key */ code = 0x62; break; case 0x4f: /* grey end key */ code = 0x63; break; case 0x50: /* grey down arrow key */ code = 0x64; break; case 0x51: /* grey page down key */ code = 0x65; break; case 0x52: /* grey insert key */ code = 0x66; break; case 0x53: /* grey delete key */ code = 0x67; break; default: /* ignore everything else */ goto next_code; } break; case 0x61: /* 0xE1 prefix */ esc_flag = 0; if (code == 0x1D) esc_flag = 0x1D; goto next_code; /* NOT REACHED */ case 0x1D: /* pause / break */ esc_flag = 0; if (code != 0x45) goto next_code; code = 0x68; break; } if (compose) { switch (code) { case 0x47: case 0x48: /* keypad 7,8,9 */ case 0x49: if (!release) chr = (code - 0x40) + chr*10; goto next_code; case 0x4b: case 0x4c: /* keypad 4,5,6 */ case 0x4d: if (!release) chr = (code - 0x47) + chr*10; goto next_code; case 0x4f: case 0x50: /* keypad 1,2,3 */ case 0x51: if (!release) chr = (code - 0x4e) + chr*10; goto next_code; case 0x52: /* keypad 0 */ if (!release) chr *= 10; goto next_code; case 0x38: /* left alt key */ break; default: if (chr) { compose = chr = 0; sysbeep(500, hz/4); goto next_code; } break; } } state = (shfts ? 1 : 0 ) | (2 * (ctls ? 1 : 0)) | (4 * (alts ? 1 : 0)); if ((!agrs && (cur_scr_stat->status & ALKED)) || (agrs && !(cur_scr_stat->status & ALKED))) code += ALTGR_OFFSET; key = &key_map.key[code]; if ( ((key->flgs & FLAG_LOCK_C) && (cur_scr_stat->status & CLKED)) || ((key->flgs & FLAG_LOCK_N) && (cur_scr_stat->status & NLKED)) ) state ^= 1; /* Check for make/break */ action = key->map[state]; if (release) { /* 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; } } 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_scr_stat->status & NLKED) cur_scr_stat->status &= ~NLKED; else cur_scr_stat->status |= NLKED; update_leds(cur_scr_stat->status & LED_MASK); } break; case CLK: if (!clkcnt) { clkcnt++; if (cur_scr_stat->status & CLKED) cur_scr_stat->status &= ~CLKED; else cur_scr_stat->status |= CLKED; update_leds(cur_scr_stat->status & LED_MASK); } break; case SLK: if (!slkcnt) { slkcnt++; if (cur_scr_stat->status & SLKED) { cur_scr_stat->status &= ~SLKED; pcstart(&pccons[get_scr_num(cur_scr_stat)]); } else cur_scr_stat->status |= SLKED; update_leds(cur_scr_stat->status & LED_MASK); } break; case ALK: if (!alkcnt) { alkcnt++; if (cur_scr_stat->status & ALKED) cur_scr_stat->status &= ~ALKED; else cur_scr_stat->status |= ALKED; } break; /* NON-LOCKING KEYS */ 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 NOP: break; default: if (action >= F_SCR && action <= L_SCR) { switch_scr(action - F_SCR); break; } if (action >= F_FN && action <= L_FN) { return(action | FKEY); } return(action); } } else return(action); } goto next_code; } /* July '93, jkh. Added in for init_main.c */ void cons_highlight() { cons_scr_stat[0].term.attr &= 0xFF00; cons_scr_stat[0].term.attr |= 0x0800; } void cons_normal() { cons_scr_stat[0].term.attr = cons_scr_stat[0].term.std_attr; } int getchar(void) { char thechar; int s; pcconsoftc.cs_flags |= CSF_POLLING; s = splhigh(); sput('>'); thechar = (char) sgetc(0); pcconsoftc.cs_flags &= ~CSF_POLLING; splx(s); switch (thechar) { default: if (thechar >= scr_map[0x20]) sput(thechar); return(thechar); case cr: case lf: sput(cr); sput(lf); return(lf); case bs: case del: sput(bs); sput(scr_map[0x20]); sput(bs); return(thechar); case cntld: sput('^'); sput('D'); sput('\r'); sput('\n'); return(0); } } 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; for (i=0; i<10000; i++) if ((inb(KB_STAT) & KB_READY) == 0) break; } static void kbd_cmd(u_char command) { kbd_wait(); outb(KB_DATA, command); } static void set_mode(scr_stat *scp) { u_char byte; int s; if (scp != cur_scr_stat) return; /* (re)activate cursor */ untimeout(cursor_pos, 0); cursor_pos(); /* 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: return; } 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 load_font(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++) *((char *)atdevbase+(segment*0x4000)+(ch*32)+line) = font[(ch*size)+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 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 */ Index: head/sys/i386/i386/tsc.c =================================================================== --- head/sys/i386/i386/tsc.c (revision 618) +++ head/sys/i386/i386/tsc.c (revision 619) @@ -1,271 +1,252 @@ /*- * 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. * - * @(#)clock.c 7.2 (Berkeley) 5/12/91 - * - * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE - * -------------------- ----- ---------------------- - * CURRENT PATCH LEVEL: 5 00158 - * -------------------- ----- ---------------------- - * - * 14 Aug 92 Arne Henrik Juul Added code in the kernel to - * allow for DST in the BIOS. - * 17 Jan 93 Bruce Evans Fixed leap year and second - * calculations - * 01 Feb 93 Julian Elischer Added code to for the cpu - * speed independent spinwait() - * function, (used by scsi and others) - * 25 Mar 93 Sean Eric Fagan Add microtimer support using timer 1 - * 08 Apr 93 Poul-Henning Kamp/P-HK Fixes, and support for dcfclock - * 26 Apr 93 Bruce Evans Eliminate findspeed, new spinwait - * 26 Apr 93 Rodney W. Grimes I merged in Bruce changes and hope I - * still kept the other fixes... Had to - * add back in findcpuspeed that Bruce - * had removed. + * from: @(#)clock.c 7.2 (Berkeley) 5/12/91 + * $Id$ */ /* * Primitive clock interrupt routines. */ #include "param.h" #include "systm.h" #include "time.h" #include "kernel.h" #include "machine/segments.h" #include "i386/isa/icu.h" #include "i386/isa/isa.h" #include "i386/isa/rtc.h" #include "i386/isa/timerreg.h" #define DAYST 119 #define DAYEN 303 /* 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 startrtclock() { int s; findcpuspeed(); /* use the clock (while it's free) to find the cpu speed */ /* 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_FREQ+hz/2)/hz); outb (IO_TIMER1, ((TIMER_FREQ+hz/2)/hz)/256); /* initialize brain-dead battery powered clock */ outb (IO_RTC, RTC_STATUSA); outb (IO_RTC+1, 0x26); outb (IO_RTC, RTC_STATUSB); outb (IO_RTC+1, 2); outb (IO_RTC, RTC_DIAG); if (s = inb (IO_RTC+1)) printf("RTC BIOS diagnostic error %b\n", s, RTCDG_BITS); outb (IO_RTC, RTC_DIAG); outb (IO_RTC+1, 0); } unsigned int delaycount; /* calibrated loop variable (1 millisecond) */ #define FIRST_GUESS 0x2000 findcpuspeed() { unsigned char low; unsigned int remainder; /* Put counter in count down mode */ outb(IO_TIMER1+3, 0x34); outb(IO_TIMER1, 0xff); outb(IO_TIMER1, 0xff); delaycount = FIRST_GUESS; spinwait(1); /* Read the value left in the counter */ low = inb(IO_TIMER1); /* least siginifcant */ remainder = inb(IO_TIMER1); /* most significant */ remainder = (remainder<<8) + low ; /* Formula for delaycount is : * (loopcount * timer clock speed)/ (counter ticks * 1000) */ delaycount = (FIRST_GUESS * (TIMER_FREQ/1000)) / (0xffff-remainder); } /* convert 2 digit BCD number */ bcd(i) int i; { return ((i/16)*10 + (i%16)); } /* convert years to seconds (from 1970) */ unsigned long ytos(y) 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(m,leap) int m,leap; { int i; unsigned long ret; ret = 0; for(i=1;i= DAYST) && ( yd <= DAYEN)) { sec -= 60*60; } 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(base) 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 /* * Restart the clock. */ resettodr() { } /* * Wire clock interrupt in. */ #define V(s) __CONCAT(V, s) extern V(clk)(); enablertclock() { setidt(ICU_OFFSET+0, &V(clk), SDT_SYS386IGT, SEL_KPL); INTREN(IRQ0); } /* * Delay for some number of milliseconds. */ void spinwait(millisecs) int millisecs; { DELAY(1000 * millisecs); } Index: head/sys/i386/isa/clock.c =================================================================== --- head/sys/i386/isa/clock.c (revision 618) +++ head/sys/i386/isa/clock.c (revision 619) @@ -1,271 +1,252 @@ /*- * 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. * - * @(#)clock.c 7.2 (Berkeley) 5/12/91 - * - * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE - * -------------------- ----- ---------------------- - * CURRENT PATCH LEVEL: 5 00158 - * -------------------- ----- ---------------------- - * - * 14 Aug 92 Arne Henrik Juul Added code in the kernel to - * allow for DST in the BIOS. - * 17 Jan 93 Bruce Evans Fixed leap year and second - * calculations - * 01 Feb 93 Julian Elischer Added code to for the cpu - * speed independent spinwait() - * function, (used by scsi and others) - * 25 Mar 93 Sean Eric Fagan Add microtimer support using timer 1 - * 08 Apr 93 Poul-Henning Kamp/P-HK Fixes, and support for dcfclock - * 26 Apr 93 Bruce Evans Eliminate findspeed, new spinwait - * 26 Apr 93 Rodney W. Grimes I merged in Bruce changes and hope I - * still kept the other fixes... Had to - * add back in findcpuspeed that Bruce - * had removed. + * from: @(#)clock.c 7.2 (Berkeley) 5/12/91 + * $Id$ */ /* * Primitive clock interrupt routines. */ #include "param.h" #include "systm.h" #include "time.h" #include "kernel.h" #include "machine/segments.h" #include "i386/isa/icu.h" #include "i386/isa/isa.h" #include "i386/isa/rtc.h" #include "i386/isa/timerreg.h" #define DAYST 119 #define DAYEN 303 /* 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 startrtclock() { int s; findcpuspeed(); /* use the clock (while it's free) to find the cpu speed */ /* 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_FREQ+hz/2)/hz); outb (IO_TIMER1, ((TIMER_FREQ+hz/2)/hz)/256); /* initialize brain-dead battery powered clock */ outb (IO_RTC, RTC_STATUSA); outb (IO_RTC+1, 0x26); outb (IO_RTC, RTC_STATUSB); outb (IO_RTC+1, 2); outb (IO_RTC, RTC_DIAG); if (s = inb (IO_RTC+1)) printf("RTC BIOS diagnostic error %b\n", s, RTCDG_BITS); outb (IO_RTC, RTC_DIAG); outb (IO_RTC+1, 0); } unsigned int delaycount; /* calibrated loop variable (1 millisecond) */ #define FIRST_GUESS 0x2000 findcpuspeed() { unsigned char low; unsigned int remainder; /* Put counter in count down mode */ outb(IO_TIMER1+3, 0x34); outb(IO_TIMER1, 0xff); outb(IO_TIMER1, 0xff); delaycount = FIRST_GUESS; spinwait(1); /* Read the value left in the counter */ low = inb(IO_TIMER1); /* least siginifcant */ remainder = inb(IO_TIMER1); /* most significant */ remainder = (remainder<<8) + low ; /* Formula for delaycount is : * (loopcount * timer clock speed)/ (counter ticks * 1000) */ delaycount = (FIRST_GUESS * (TIMER_FREQ/1000)) / (0xffff-remainder); } /* convert 2 digit BCD number */ bcd(i) int i; { return ((i/16)*10 + (i%16)); } /* convert years to seconds (from 1970) */ unsigned long ytos(y) 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(m,leap) int m,leap; { int i; unsigned long ret; ret = 0; for(i=1;i= DAYST) && ( yd <= DAYEN)) { sec -= 60*60; } 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(base) 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 /* * Restart the clock. */ resettodr() { } /* * Wire clock interrupt in. */ #define V(s) __CONCAT(V, s) extern V(clk)(); enablertclock() { setidt(ICU_OFFSET+0, &V(clk), SDT_SYS386IGT, SEL_KPL); INTREN(IRQ0); } /* * Delay for some number of milliseconds. */ void spinwait(millisecs) int millisecs; { DELAY(1000 * millisecs); } Index: head/sys/i386/isa/fdreg.h =================================================================== --- head/sys/i386/isa/fdreg.h (revision 618) +++ head/sys/i386/isa/fdreg.h (revision 619) @@ -1,72 +1,66 @@ /*- * 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. * - * @(#)fdreg.h 7.1 (Berkeley) 5/9/91 - * - * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE - * -------------------- ----- ---------------------- - * CURRENT PATCH LEVEL: 1 00153 - * -------------------- ----- ---------------------- - * - * 20 Apr 93 Julian Elischer Heavily re worked, see notes below + * from: @(#)fdreg.h 7.1 (Berkeley) 5/9/91 + * $Id$ */ /* * 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 */ Index: head/sys/i386/isa/ic/i8042.h =================================================================== --- head/sys/i386/isa/ic/i8042.h (revision 618) +++ head/sys/i386/isa/ic/i8042.h (revision 619) @@ -1,23 +1,27 @@ +/* + * $Id$ + */ + #define KBSTATP 0x64 /* kbd controller status port (I) */ #define KBS_DIB 0x01 /* kbd data in buffer */ #define KBS_IBF 0x02 /* kbd input buffer low */ #define KBS_WARM 0x04 /* kbd input buffer low */ #define KBS_OCMD 0x08 /* kbd output buffer has command */ #define KBS_NOSEC 0x10 /* kbd security lock not engaged */ #define KBS_TERR 0x20 /* kbd transmission error */ #define KBS_RERR 0x40 /* kbd receive error */ #define KBS_PERR 0x80 /* kbd parity error */ #define KBCMDP 0x64 /* kbd controller port (O) */ #define KBDATAP 0x60 /* kbd data port (I) */ #define KBOUTP 0x60 /* kbd data port (O) */ #define K_LDCMDBYTE 0x60 #define KC8_TRANS 0x40 /* convert to old scan codes */ #define KC8_OLDPC 0x20 /* old 9bit codes instead of new 11bit */ #define KC8_DISABLE 0x10 /* disable keyboard */ #define KC8_IGNSEC 0x08 /* ignore security lock */ #define KC8_CPU 0x04 /* exit from protected mode reset */ #define KC8_IEN 0x01 /* enable interrupt */ #define CMDBYTE (KC8_TRANS|KC8_IGNSEC|KC8_CPU|KC8_IEN) Index: head/sys/i386/isa/ic/i8237.h =================================================================== --- head/sys/i386/isa/ic/i8237.h (revision 618) +++ head/sys/i386/isa/ic/i8237.h (revision 619) @@ -1,9 +1,11 @@ /* * Intel 8237 DMA Controller + * + * $Id$ */ #define DMA37MD_SINGLE 0x40 /* single pass mode */ #define DMA37MD_CASCADE 0xc0 /* cascade mode */ #define DMA37MD_WRITE 0x04 /* read the device, write memory operation */ #define DMA37MD_READ 0x08 /* write the device, read memory operation */ Index: head/sys/i386/isa/ic/nec765.h =================================================================== --- head/sys/i386/isa/ic/nec765.h (revision 618) +++ head/sys/i386/isa/ic/nec765.h (revision 619) @@ -1,71 +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. * - * @(#)nec765.h 7.1 (Berkeley) 5/9/91 + * 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 */ Index: head/sys/i386/isa/ic/ns16450.h =================================================================== --- head/sys/i386/isa/ic/ns16450.h (revision 618) +++ head/sys/i386/isa/ic/ns16450.h (revision 619) @@ -1,49 +1,50 @@ /*- * 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. * - * @(#)ns16450.h 7.1 (Berkeley) 5/9/91 + * from: @(#)ns16450.h 7.1 (Berkeley) 5/9/91 + * $Id$ */ /* * NS16450 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_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) */ Index: head/sys/i386/isa/ic/ns16550.h =================================================================== --- head/sys/i386/isa/ic/ns16550.h (revision 618) +++ head/sys/i386/isa/ic/ns16550.h (revision 619) @@ -1,50 +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. * - * @(#)ns16550.h 7.1 (Berkeley) 5/9/91 + * 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) */ Index: head/sys/i386/isa/icu.h =================================================================== --- head/sys/i386/isa/icu.h (revision 618) +++ head/sys/i386/isa/icu.h (revision 619) @@ -1,109 +1,103 @@ /*- * 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. * - * @(#)icu.h 5.6 (Berkeley) 5/9/91 - * - * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE - * -------------------- ----- ---------------------- - * CURRENT PATCH LEVEL: 1 00158 - * -------------------- ----- ---------------------- - * - * 25 Apr 93 Bruce Evans New fast interrupt code (intr-0.1) + * from: @(#)icu.h 5.6 (Berkeley) 5/9/91 + * $Id$ */ /* * AT/386 Interrupt Control constants * W. Jolitz 8/89 */ #ifndef __ICU__ #define __ICU__ #ifndef LOCORE /* * Interrupt "level" mechanism variables, masks, and macros */ extern unsigned imen; /* interrupt mask enable */ extern unsigned cpl; /* current priority level mask */ extern unsigned highmask; /* group of interrupts masked with splhigh() */ extern unsigned ttymask; /* group of interrupts masked with spltty() */ extern unsigned biomask; /* group of interrupts masked with splbio() */ extern unsigned netmask; /* group of interrupts masked with splimp() */ #define INTREN(s) (imen &= ~(s), SET_ICUS()) #define INTRDIS(s) (imen |= (s), SET_ICUS()) #define INTRMASK(msk,s) (msk |= (s)) #if 0 #define SET_ICUS() (outb(IO_ICU1 + 1, imen), outb(IU_ICU2 + 1, imen >> 8)) #else /* * XXX - IO_ICU* are defined in isa.h, not icu.h, and nothing much bothers to * include isa.h, while too many things include icu.h. */ #define SET_ICUS() (outb(0x21, imen), outb(0xa1, imen >> 8)) #endif #endif /* * Interrupt enable bits -- in order of priority */ #define IRQ0 0x0001 /* highest priority - timer */ #define IRQ1 0x0002 #define IRQ_SLAVE 0x0004 #define IRQ8 0x0100 #define IRQ9 0x0200 #define IRQ2 IRQ9 #define IRQ10 0x0400 #define IRQ11 0x0800 #define IRQ12 0x1000 #define IRQ13 0x2000 #define IRQ14 0x4000 #define IRQ15 0x8000 #define IRQ3 0x0008 #define IRQ4 0x0010 #define IRQ5 0x0020 #define IRQ6 0x0040 #define IRQ7 0x0080 /* lowest - parallel printer */ /* * Interrupt Control offset into Interrupt descriptor table (IDT) */ #define ICU_OFFSET 32 /* 0-31 are processor exceptions */ #define ICU_LEN 16 /* 32-47 are ISA interrupts */ #endif __ICU__ Index: head/sys/i386/isa/if_is.c =================================================================== --- head/sys/i386/isa/if_is.c (revision 618) +++ head/sys/i386/isa/if_is.c (revision 619) @@ -1,977 +1,978 @@ /* * Isolan AT 4141-0 Ethernet driver * Isolink 4110 * * By Paul Richards * * Copyright (C) 1993, Paul Richards. This software may be used, modified, * copied, distributed, and sold, in both source and binary form provided * that the above copyright and these terms are retained. Under no * circumstances is the author responsible for the proper functioning * of this software, nor does the author assume any responsibility * for damages incurred with its use. * -*/ + * $Id$ + */ /* TODO 1) Add working multicast support 2) Use better allocation of memory to card 3) Advertise for more packets until all transmit buffers are full 4) Add more of the timers/counters e.g. arpcom.opackets etc. */ #include "is.h" #if NIS > 0 #include "bpfilter.h" #include "param.h" #include "systm.h" #include "errno.h" #include "ioctl.h" #include "mbuf.h" #include "socket.h" #include "syslog.h" #include "net/if.h" #include "net/if_dl.h" #include "net/if_types.h" #include "net/netisr.h" #ifdef INET #include "netinet/in.h" #include "netinet/in_systm.h" #include "netinet/in_var.h" #include "netinet/ip.h" #include "netinet/if_ether.h" #endif #ifdef NS #include "netns/ns.h" #include "netns/ns_if.h" #endif #if NBPFILTER > 0 #include "net/bpf.h" #include "net/bpfdesc.h" #endif #include "i386/isa/isa_device.h" #include "i386/isa/if_isreg.h" #include "i386/isa/icu.h" #include "vm/vm.h" #define ETHER_MIN_LEN 64 #define ETHER_MAX_LEN 1518 #define ETHER_ADDR_LEN 6 /* * Ethernet software status per interface. * * Each interface is referenced by a network interface structure, * arpcom.ac_if, which the routing code uses to locate the interface. * This structure contains the output queue for the interface, its address, ... */ struct is_softc { struct arpcom arpcom; /* Ethernet common part */ int iobase; /* IO base address of card */ struct mds *rd; struct mds *td; unsigned char *rbuf; unsigned char *tbuf; int last_rd; int last_td; int no_td; caddr_t bpf; /* BPF "magic cookie" */ } is_softc[NIS] ; struct init_block init_block[NIS]; /* Function prototypes */ int is_probe(),is_attach(),is_watchdog(); int is_ioctl(),is_init(),is_start(); static inline void is_rint(int unit); static inline void isread(struct is_softc*, unsigned char*, int); struct mbuf *isget(); struct isa_driver isdriver = { is_probe, is_attach, "is" }; iswrcsr(unit,port,val) int unit; u_short port; u_short val; { int iobase; iobase = is_softc[unit].iobase; outw(iobase+RAP,port); outw(iobase+RDP,val); } u_short isrdcsr(unit,port) int unit; u_short port; { int iobase; iobase = is_softc[unit].iobase; outw(iobase+RAP,port); return(inw(iobase+RDP)); } is_probe(isa_dev) struct isa_device *isa_dev; { int val,i,s; int unit = isa_dev->id_unit ; register struct is_softc *is = &is_softc[unit]; is->iobase = isa_dev->id_iobase; /* Stop the lance chip, put it known state */ iswrcsr(unit,0,STOP); DELAY(100); /* is there a lance? */ iswrcsr(unit,3, 0xffff); if (isrdcsr(unit,3) != 7) { is->iobase = 0; return (0); } iswrcsr(unit,3, 0); /* Extract board address */ for(i=0;iarpcom.ac_enaddr[i]=inb(is->iobase+(i*2)); return (1); } /* * Reset of interface. */ int is_reset(int unit) { int s; if (unit >= NIS) return; s = splnet(); printf("is%d: reset\n", unit); is_init(unit); (void) splx(s); } /* * Interface exists: make available by filling in network interface * record. System will initialize the interface when it is ready * to accept packets. We get the ethernet address here. */ int is_attach(isa_dev) struct isa_device *isa_dev; { int unit = isa_dev->id_unit; struct is_softc *is = &is_softc[unit]; struct ifnet *ifp = &is->arpcom.ac_if; struct ifaddr *ifa; struct sockaddr_dl *sdl; ifp->if_unit = unit; ifp->if_name = isdriver.name ; ifp->if_mtu = ETHERMTU; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS; ifp->if_init = is_init; ifp->if_output = ether_output; ifp->if_start = is_start; ifp->if_ioctl = is_ioctl; ifp->if_reset = is_reset; ifp->if_watchdog = is_watchdog; /* Set up DMA */ isa_dmacascade(isa_dev->id_drq); if_attach(ifp); /* * Search down the ifa address list looking for the AF_LINK type entry */ ifa = ifp->if_addrlist; while ((ifa != 0) && (ifa->ifa_addr != 0) && (ifa->ifa_addr->sa_family != AF_LINK)) ifa = ifa->ifa_next; /* * If we find an AF_LINK type entry, we will fill * in the hardware address for this interface. */ if ((ifa != 0) && (ifa->ifa_addr != 0)) { /* * Fill in the link level address for this interface */ sdl = (struct sockaddr_dl *)ifa->ifa_addr; sdl->sdl_type = IFT_ETHER; sdl->sdl_alen = ETHER_ADDR_LEN; sdl->sdl_slen = 0; bcopy(is->arpcom.ac_enaddr, LLADDR(sdl), ETHER_ADDR_LEN); } printf ("is%d: address %s\n", unit, ether_sprintf(is->arpcom.ac_enaddr)) ; #if NBPFILTER > 0 bpfattach(&is->bpf, ifp, DLT_EN10MB, sizeof(struct ether_header)); #endif } int is_watchdog(unit) int unit; { log(LOG_ERR, "is%d: device timeout\n", unit); is_reset(unit); } /* Lance initialisation block set up */ init_mem(unit) int unit; { int i; u_long temp; struct is_softc *is = &is_softc[unit]; /* Allocate memory */ /* Temporary hack, will use kmem_alloc in future */ #define MAXMEM ((NRBUF+NTBUF)*(BUFSIZE) + (NRBUF+NTBUF)*sizeof(struct mds) + 8) static u_char lance_mem[NIS][MAXMEM]; /* Align message descriptors on quad word boundary (this is essential) */ temp = (u_long) &lance_mem[unit]; temp = (temp+8) - (temp%8); is->rd = (struct mds *) temp; is->td = (struct mds *) (temp + (NRBUF*sizeof(struct mds))); temp += (NRBUF+NTBUF) * sizeof(struct mds); init_block[unit].mode = 0; init_block[unit].rdra = kvtop(is->rd); init_block[unit].rlen = ((kvtop(is->rd) >> 16) & 0xff) | (RLEN<<13); init_block[unit].tdra = kvtop(is->td); init_block[unit].tlen = ((kvtop(is->td) >> 16) & 0xff) | (TLEN<<13); /* Set up receive ring descriptors */ is->rbuf = (unsigned char *)temp; for (i=0; ird+i)->addr = kvtop(temp); (is->rd+i)->flags= ((kvtop(temp) >> 16) & 0xff) | OWN; (is->rd+i)->bcnt = -BUFSIZE; (is->rd+i)->mcnt = 0; temp += BUFSIZE; } /* Set up transmit ring descriptors */ is->tbuf = (unsigned char *)temp; #if ISDEBUG > 4 printf("rd = %x,td = %x, rbuf = %x, tbuf = %x,td+1=%x\n",is->rd,is->td,is->rbuf,is->tbuf,is->td+1); #endif for (i=0; itd+i)->addr = kvtop(temp); (is->td+i)->flags= ((kvtop(temp) >> 16) & 0xff); (is->td+i)->bcnt = 0; (is->td+i)->mcnt = 0; temp += BUFSIZE; } } /* * Initialization of interface; set up initialization block * and transmit/receive descriptor rings. */ is_init(unit) int unit; { register struct is_softc *is = &is_softc[unit]; struct ifnet *ifp = &is->arpcom.ac_if; int s; register i; /* Address not known */ if (ifp->if_addrlist == (struct ifaddr *)0) return; s = splnet(); is->last_rd = is->last_td = is->no_td = 0; /* Set up lance's memory area */ init_mem(unit); /* Stop Lance to get access to other registers */ iswrcsr(unit,0,STOP); /* Get ethernet address */ for (i=0; iarpcom.ac_enaddr[i]; #if NBPFILTER > 0 /* * Initialize multicast address hashing registers to accept * all multicasts (only used when in promiscuous mode) */ for (i = 0; i < 8; ++i) init_block[unit].ladrf[i] = 0xff; #endif /* I wish I knew what this was */ iswrcsr(unit,3,0); /* Give lance the physical address of its memory area */ iswrcsr(unit,1,kvtop(&init_block[unit])); iswrcsr(unit,2,(kvtop(&init_block[unit]) >> 16) & 0xff); /* OK, let's try and initialise the Lance */ iswrcsr(unit,0,INIT); /* Wait for initialisation to finish */ for(i=0; i<1000; i++){ if (isrdcsr(unit,0)&IDON) break; } if (isrdcsr(unit,0)&IDON) { /* Start lance */ iswrcsr(unit,0,STRT|IDON|INEA); ifp->if_flags |= IFF_RUNNING; ifp->if_flags &= ~IFF_OACTIVE; is_start(ifp); } else printf("is%d: card failed to initialise\n", unit); (void) splx(s); } /* * Setup output on interface. * Get another datagram to send off of the interface queue, * and map it to the interface before starting the output. * called only at splimp or interrupt level. */ is_start(ifp) struct ifnet *ifp; { int unit = ifp->if_unit; register struct is_softc *is = &is_softc[unit]; struct mbuf *m0, *m; unsigned char *buffer; u_short len; int i; struct mds *cdm; if ((is->arpcom.ac_if.if_flags & IFF_RUNNING) == 0) return; do { cdm = (is->td + is->last_td); if (cdm->flags&OWN) return; IF_DEQUEUE(&is->arpcom.ac_if.if_snd, m); if (m == 0) return; /* * Copy the mbuf chain into the transmit buffer */ buffer = is->tbuf+(BUFSIZE*is->last_td); len=0; for (m0=m; m != 0; m=m->m_next) { bcopy(mtod(m,caddr_t),buffer,m->m_len); buffer += m->m_len; len += m->m_len; } #if NBPFILTER > 0 if (is->bpf) { u_short etype; int off, datasize, resid; struct ether_header *eh; struct trailer_header { u_short ether_type; u_short ether_residual; } trailer_header; char ether_packet[ETHER_MAX_LEN]; char *ep; ep = ether_packet; /* * We handle trailers below: * Copy ether header first, then residual data, * then data. Put all this in a temporary buffer * 'ether_packet' and send off to bpf. Since the * system has generated this packet, we assume * that all of the offsets in the packet are * correct; if they're not, the system will almost * certainly crash in m_copydata. * We make no assumptions about how the data is * arranged in the mbuf chain (i.e. how much * data is in each mbuf, if mbuf clusters are * used, etc.), which is why we use m_copydata * to get the ether header rather than assume * that this is located in the first mbuf. */ /* copy ether header */ m_copydata(m0, 0, sizeof(struct ether_header), ep); eh = (struct ether_header *) ep; ep += sizeof(struct ether_header); etype = ntohs(eh->ether_type); if (etype >= ETHERTYPE_TRAIL && etype < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { datasize = ((etype - ETHERTYPE_TRAIL) << 9); off = datasize + sizeof(struct ether_header); /* copy trailer_header into a data structure */ m_copydata(m0, off, sizeof(struct trailer_header), &trailer_header.ether_type); /* copy residual data */ resid = trailer_header.ether_residual - sizeof(struct trailer_header); resid = ntohs(resid); m_copydata(m0, off+sizeof(struct trailer_header), resid, ep); ep += resid; /* copy data */ m_copydata(m0, sizeof(struct ether_header), datasize, ep); ep += datasize; /* restore original ether packet type */ eh->ether_type = trailer_header.ether_type; bpf_tap(is->bpf, ether_packet, ep - ether_packet); } else bpf_mtap(is->bpf, m0); } #endif m_freem(m0); len = MAX(len,ETHER_MIN_LEN); /* * Init transmit registers, and set transmit start flag. */ cdm->flags |= (OWN|STP|ENP); cdm->bcnt = -len; cdm->mcnt = 0; #if ISDEBUG > 3 xmit_print(unit,is->last_td); #endif iswrcsr(unit,0,TDMD|INEA); if (++is->last_td >= NTBUF) is->last_td=0; }while(++is->no_td < NTBUF); is->no_td = NTBUF; is->arpcom.ac_if.if_flags |= IFF_OACTIVE; #if ISDEBUG >4 printf("no_td = %x, last_td = %x\n",is->no_td, is->last_td); #endif return(0); } /* * Controller interrupt. */ isintr(unit) { register struct is_softc *is = &is_softc[unit]; u_short isr; while((isr=isrdcsr(unit,0))&INTR) { if (isr&ERR) { if (isr&BABL){ printf("is%d: BABL\n",unit); is->arpcom.ac_if.if_oerrors++; } if (isr&CERR) { printf("is%d: CERR\n",unit); is->arpcom.ac_if.if_collisions++; } if (isr&MISS) { printf("is%d: MISS\n",unit); is->arpcom.ac_if.if_ierrors++; } if (isr&MERR) printf("is%d: MERR\n",unit); iswrcsr(unit,0,BABL|CERR|MISS|MERR|INEA); } if (!(isr&RXON)) { printf("is%d: !(isr&RXON)\n", unit); is->arpcom.ac_if.if_ierrors++; is_reset(unit); return(1); } if (!(isr&TXON)) { printf("is%d: !(isr&TXON)\n", unit); is->arpcom.ac_if.if_oerrors++; is_reset(unit); return(1); } if (isr&RINT) { /* reset watchdog timer */ is->arpcom.ac_if.if_timer = 0; is_rint(unit); } if (isr&TINT) { /* reset watchdog timer */ is->arpcom.ac_if.if_timer = 0; iswrcsr(unit,0,TINT|INEA); istint(unit); } } } istint(unit) int unit; { struct is_softc *is = &is_softc[unit]; register struct ifnet *ifp = &is->arpcom.ac_if; int i,loopcount=0; struct mds *cdm; is->arpcom.ac_if.if_opackets++; do { if ((i=is->last_td - is->no_td) < 0) i+=NTBUF; cdm = (is->td+i); #if ISDEBUG >4 printf("Trans cdm = %x\n",cdm); #endif if (cdm->flags&OWN) { if (loopcount) break; return; } loopcount++; is->arpcom.ac_if.if_flags &= ~IFF_OACTIVE; }while(--is->no_td > 0); is_start(ifp); } #define NEXTRDS \ if (++rmd == NRBUF) rmd=0, cdm=is->rd; else ++cdm /* only called from one place, so may as well integrate */ static inline void is_rint(int unit) { register struct is_softc *is=&is_softc[unit]; register int rmd = is->last_rd; struct mds *cdm = (is->rd + rmd); /* Out of sync with hardware, should never happen */ if (cdm->flags & OWN) { printf("is%d: error: out of sync\n",unit); iswrcsr(unit,0,RINT|INEA); return; } /* Process all buffers with valid data */ while (!(cdm->flags&OWN)) { /* Clear interrupt to avoid race condition */ iswrcsr(unit,0,RINT|INEA); if (cdm->flags&ERR) { if (cdm->flags&FRAM) printf("is%d: FRAM\n",unit); if (cdm->flags&OFLO) printf("is%d: OFLO\n",unit); if (cdm->flags&CRC) printf("is%d: CRC\n",unit); if (cdm->flags&RBUFF) printf("is%d: RBUFF\n",unit); }else if (cdm->flags&(STP|ENP) != (STP|ENP)) { do { iswrcsr(unit,0,RINT|INEA); cdm->mcnt = 0; cdm->flags |= OWN; NEXTRDS; }while (!(cdm->flags&(OWN|ERR|STP|ENP))); is->last_rd = rmd; printf("is%d: Chained buffer\n",unit); if ((cdm->flags & (OWN|ERR|STP|ENP)) != ENP) { is_reset(unit); return; } }else { #if ISDEBUG >2 recv_print(unit,is->last_rd); #endif isread(is,is->rbuf+(BUFSIZE*rmd),(int)cdm->mcnt); is->arpcom.ac_if.if_ipackets++; } cdm->flags |= OWN; cdm->mcnt = 0; NEXTRDS; #if ISDEBUG >4 printf("is->last_rd = %x, cdm = %x\n",is->last_rd,cdm); #endif } /* while */ is->last_rd = rmd; } /* is_rint */ /* * Pass a packet to the higher levels. * We deal with the trailer protocol here. */ static inline void isread(struct is_softc *is, unsigned char *buf, int len) { register struct ether_header *eh; struct mbuf *m; int off, resid; register struct ifqueue *inq; /* * Deal with trailer protocol: if type is trailer type * get true type from first 16-bit word past data. * Remember that type was trailer by setting off. */ eh = (struct ether_header *)buf; eh->ether_type = ntohs((u_short)eh->ether_type); len = len - sizeof(struct ether_header) - 4; #define nedataaddr(eh, off, type) ((type)(((caddr_t)((eh)+1)+(off)))) if (eh->ether_type >= ETHERTYPE_TRAIL && eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { off = (eh->ether_type - ETHERTYPE_TRAIL) * 512; if (off >= ETHERMTU) return; /* sanity */ eh->ether_type = ntohs(*nedataaddr(eh, off, u_short *)); resid = ntohs(*(nedataaddr(eh, off+2, u_short *))); if (off + resid > len) return; /* sanity */ len = off + resid; } else off = 0; if (len == 0) return; /* * Pull packet off interface. Off is nonzero if packet * has trailing header; neget will then force this header * information to be at the front, but we still have to drop * the type and length which are at the front of any trailer data. */ is->arpcom.ac_if.if_ipackets++; m = isget(buf, len, off, &is->arpcom.ac_if); if (m == 0) return; #if NBPFILTER > 0 /* * Check if there's a BPF listener on this interface. * If so, hand off the raw packet to bpf. */ if (is->bpf) { bpf_mtap(is->bpf, m); /* * Note that the interface cannot be in promiscuous mode if * there are no BPF listeners. And if we are in promiscuous * mode, we have to check if this packet is really ours. * * XXX This test does not support multicasts. */ if ((is->arpcom.ac_if.if_flags & IFF_PROMISC) && bcmp(eh->ether_dhost, is->arpcom.ac_enaddr, sizeof(eh->ether_dhost)) != 0 && bcmp(eh->ether_dhost, etherbroadcastaddr, sizeof(eh->ether_dhost)) != 0) { m_freem(m); return; } } #endif ether_input(&is->arpcom.ac_if, eh, m); } /* * Supporting routines */ /* * Pull read data off a interface. * Len is length of data, with local net header stripped. * Off is non-zero if a trailer protocol was used, and * gives the offset of the trailer information. * We copy the trailer information and then all the normal * data into mbufs. When full cluster sized units are present * we copy into clusters. */ struct mbuf * isget(buf, totlen, off0, ifp) caddr_t buf; int totlen, off0; struct ifnet *ifp; { struct mbuf *top, **mp, *m, *p; int off = off0, len; register caddr_t cp = buf; char *epkt; buf += sizeof(struct ether_header); cp = buf; epkt = cp + totlen; if (off) { cp += off + 2 * sizeof(u_short); totlen -= 2 * sizeof(u_short); } MGETHDR(m, M_DONTWAIT, MT_DATA); if (m == 0) return (0); m->m_pkthdr.rcvif = ifp; m->m_pkthdr.len = totlen; m->m_len = MHLEN; top = 0; mp = ⊤ while (totlen > 0) { if (top) { MGET(m, M_DONTWAIT, MT_DATA); if (m == 0) { m_freem(top); return (0); } m->m_len = MLEN; } len = min(totlen, epkt - cp); if (len >= MINCLSIZE) { MCLGET(m, M_DONTWAIT); if (m->m_flags & M_EXT) m->m_len = len = min(len, MCLBYTES); else len = m->m_len; } else { /* * Place initial small packet/header at end of mbuf. */ if (len < m->m_len) { if (top == 0 && len + max_linkhdr <= m->m_len) m->m_data += max_linkhdr; m->m_len = len; } else len = m->m_len; } bcopy(cp, mtod(m, caddr_t), (unsigned)len); cp += len; *mp = m; mp = &m->m_next; totlen -= len; if (cp == epkt) cp = buf; } return (top); } /* * Process an ioctl request. */ is_ioctl(ifp, cmd, data) register struct ifnet *ifp; int cmd; caddr_t data; { register struct ifaddr *ifa = (struct ifaddr *)data; int unit = ifp->if_unit; struct is_softc *is = &is_softc[unit]; struct ifreq *ifr = (struct ifreq *)data; int s, error = 0; s = splnet(); switch (cmd) { case SIOCSIFADDR: ifp->if_flags |= IFF_UP; switch (ifa->ifa_addr->sa_family) { #ifdef INET case AF_INET: is_init(ifp->if_unit); /* before arpwhohas */ /* * See if another station has *our* IP address. * i.e.: There is an address conflict! If a * conflict exists, a message is sent to the * console. */ ((struct arpcom *)ifp)->ac_ipaddr = IA_SIN(ifa)->sin_addr; arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); break; #endif #ifdef NS /* * XXX - This code is probably wrong */ case AF_NS: { register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); if (ns_nullhost(*ina)) ina->x_host = *(union ns_host *)(is->arpcom.ac_enaddr); else { /* * */ bcopy((caddr_t)ina->x_host.c_host, (caddr_t)is->arpcom.ac_enaddr, sizeof(is->arpcom.ac_enaddr)); } /* * Set new address */ is_init(ifp->if_unit); break; } #endif default: is_init(ifp->if_unit); break; } break; case SIOCSIFFLAGS: /* * If interface is marked down and it is running, then stop it */ if ((ifp->if_flags & IFF_UP) == 0 && ifp->if_flags & IFF_RUNNING) { iswrcsr(unit,0,STOP); ifp->if_flags &= ~IFF_RUNNING; } else { /* * If interface is marked up and it is stopped, then start it */ if ((ifp->if_flags & IFF_UP) && (ifp->if_flags & IFF_RUNNING) == 0) is_init(ifp->if_unit); } #if NBPFILTER > 0 if (ifp->if_flags & IFF_PROMISC) { /* * Set promiscuous mode on interface. * XXX - for multicasts to work, we would need to * write 1's in all bits of multicast * hashing array. For now we assume that * this was done in is_init(). */ init_block[unit].mode = PROM; } else /* * XXX - for multicasts to work, we would need to * rewrite the multicast hashing array with the * proper hash (would have been destroyed above). */ { /* Don't know about this */}; #endif break; #ifdef notdef case SIOCGHWADDR: bcopy((caddr_t)is->arpcom.ac_enaddr, (caddr_t) &ifr->ifr_data, sizeof(is->arpcom.ac_enaddr)); break; #endif default: error = EINVAL; } (void) splx(s); return (error); } recv_print(unit,no) int unit,no; { register struct is_softc *is=&is_softc[unit]; struct mds *rmd; int len,i,printed=0; rmd = (is->rd+no); len = rmd->mcnt; printf("is%d: Receive buffer %d, len = %d\n",unit,no,len); printf("is%d: Status %x\n",unit,isrdcsr(unit,0)); for (i=0; irbuf+(BUFSIZE*no)+i)); } if (printed) printf("\n"); } xmit_print(unit,no) int unit,no; { register struct is_softc *is=&is_softc[unit]; struct mds *rmd; int i, printed=0; u_short len; rmd = (is->td+no); len = -(rmd->bcnt); printf("is%d: Transmit buffer %d, len = %d\n",unit,no,len); printf("is%d: Status %x\n",unit,isrdcsr(unit,0)); printf("is%d: addr %x, flags %x, bcnt %x, mcnt %x\n", unit,rmd->addr,rmd->flags,rmd->bcnt,rmd->mcnt); for (i=0; itbuf+(BUFSIZE*no)+i)); } if (printed) printf("\n"); } #endif Index: head/sys/i386/isa/if_isreg.h =================================================================== --- head/sys/i386/isa/if_isreg.h (revision 618) +++ head/sys/i386/isa/if_isreg.h (revision 619) @@ -1,90 +1,106 @@ +/* + * Isolan AT 4141-0 Ethernet driver header file + * Isolink 4110 + * + * By Paul Richards + * + * Copyright (C) 1993, Paul Richards. This software may be used, modified, + * copied, distributed, and sold, in both source and binary form provided + * that the above copyright and these terms are retained. Under no + * circumstances is the author responsible for the proper functioning + * of this software, nor does the author assume any responsibility + * for damages incurred with its use. + * + * $Id$ + */ + /* Declarations specific to this driver */ #define NTBUF 2 #define TLEN 1 #define NRBUF 8 #define RLEN 3 #define BUFSIZE 1518 #define RAP 0xe #define RDP 0xc /* Control and status register 0 flags */ #define ERR 0x8000 #define BABL 0x4000 #define CERR 0x2000 #define MISS 0x1000 #define MERR 0x0800 #define RINT 0x0400 #define TINT 0x0200 #define IDON 0x0100 #define INTR 0x0080 #define INEA 0x0040 #define RXON 0x0020 #define TXON 0x0010 #define TDMD 0x0008 #define STOP 0x0004 #define STRT 0x0002 #define INIT 0x0001 /* Coontrol and status register 3 flags */ #define BSWP 0x0004 #define ACON 0x0002 #define BCON 0x0001 /* Initialisation block (must be on word boundary) */ struct init_block { u_short mode; /* Mode register */ u_char padr[6]; /* Ethernet address */ u_char ladrf[8]; /* Logical address filter (multicast) */ u_short rdra; /* Low order pointer to receive ring */ u_short rlen; /* High order pointer and no. rings */ u_short tdra; /* Low order pointer to transmit ring */ u_short tlen; /* High order pointer and no rings */ }; /* Mode settings */ #define PROM 0x8000 /* Promiscuous */ #define INTL 0x0040 /* Internal loopback */ #define DRTY 0x0020 /* Disable retry */ #define COLL 0x0010 /* Force collision */ #define DTCR 0x0008 /* Disable transmit crc */ #define LOOP 0x0004 /* Loop back */ #define DTX 0x0002 /* Disable transmitter */ #define DRX 0x0001 /* Disable receiver */ /* Message descriptor structure */ struct mds { u_short addr; u_short flags; u_short bcnt; u_short mcnt; }; /* Receive ring status flags */ #define OWN 0x8000 /* Owner bit, 0=host, 1=Lance */ #define MDERR 0x4000 /* Error */ #define FRAM 0x2000 /* Framing error error */ #define OFLO 0x1000 /* Silo overflow */ #define CRC 0x0800 /* CRC error */ #define RBUFF 0x0400 /* Buffer error */ #define STP 0x0200 /* Start of packet */ #define ENP 0x0100 /* End of packet */ /* Transmit ring flags */ #define MORE 0x1000 /* More than 1 retry */ #define ONE 0x0800 /* One retry */ #define DEF 0x0400 /* Deferred transmit */ /* Transmit errors */ #define TBUFF 0x8000 /* Buffer error */ #define UFLO 0x4000 /* Silo underflow */ #define LCOL 0x1000 /* Late collision */ #define LCAR 0x0800 /* Loss of carrier */ #define RTRY 0x0400 /* Tried 16 times */ Index: head/sys/i386/isa/isa.h =================================================================== --- head/sys/i386/isa/isa.h (revision 618) +++ head/sys/i386/isa/isa.h (revision 619) @@ -1,188 +1,180 @@ /*- * 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. * - * @(#)isa.h 5.7 (Berkeley) 5/9/91 - * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE - * -------------------- ----- ---------------------- - * CURRENT PATCH LEVEL: 3 00158 - * -------------------- ----- ---------------------- - * - * 15 Feb 93 Julian Elischer Added entries for some scsi adapters - * 06 Apr 93 Rodney W. Grimes Added com3 and com4, added IO_ISASIZES - * section - * 26 Apr 93 Bruce Evans Support for intr-0.1 + * from: @(#)isa.h 5.7 (Berkeley) 5/9/91 + * $Id$ */ /* * ISA Bus conventions */ #ifndef LOCORE #include unsigned char rtcin __P((int)); extern unsigned int atdevbase; /* offset in virtual memory of ISA io mem */ void sysbeep __P((int, int)); unsigned kbd_8042cmd __P((int)); struct isa_device; int isa_irq_pending __P((struct isa_device *dvp)); #endif /* * Input / Output Port Assignments */ #ifndef IO_BEGIN #define IO_ISABEGIN 0x000 /* 0x000 - Beginning of I/O Registers */ /* CPU Board */ #define IO_DMA1 0x000 /* 8237A DMA Controller #1 */ #define IO_ICU1 0x020 /* 8259A Interrupt Controller #1 */ #define IO_TIMER1 0x040 /* 8252 Timer #1 */ #define IO_TIMER2 0x048 /* 8252 Timer #2 */ #define IO_KBD 0x060 /* 8042 Keyboard */ #define IO_RTC 0x070 /* RTC */ #define IO_NMI IO_RTC /* NMI Control */ #define IO_DMAPG 0x080 /* DMA Page Registers */ #define IO_ICU2 0x0A0 /* 8259A Interrupt Controller #2 */ #define IO_DMA2 0x0C0 /* 8237A DMA Controller #2 */ #define IO_NPX 0x0F0 /* Numeric Coprocessor */ /* Cards */ /* 0x100 - 0x16F Open */ #define IO_WD2 0x170 /* Secondary Fixed Disk Controller */ /* 0x178 - 0x1EF Open */ #define IO_WD1 0x1f0 /* Primary Fixed Disk Controller */ #define IO_GAME 0x200 /* Game Controller */ /* 0x208 - 0x277 Open */ #define IO_LPT2 0x278 /* Parallel Port #2 */ /* 0x280 - 0x2E7 Open */ #define IO_COM4 0x2e8 /* COM4 i/o address */ /* 0x2F0 - 0x2F7 Open */ #define IO_COM2 0x2f8 /* COM2 i/o address */ /* 0x300 - 0x32F Open */ #define IO_BT0 0x330 /* bustek 742a default addr. */ #define IO_AHA0 0x330 /* adaptec 1542 default addr. */ #define IO_UHA0 0x330 /* ultrastore 14f default addr. */ #define IO_BT1 0x334 /* bustek 742a default addr. */ #define IO_AHA1 0x334 /* adaptec 1542 default addr. */ /* 0x338 - 0x36F Open */ #define IO_FD2 0x370 /* secondary base i/o address */ #define IO_LPT1 0x378 /* Parallel Port #1 */ /* 0x380 - 0x3AF Open */ #define IO_MDA 0x3B0 /* Monochome Adapter */ #define IO_LPT3 0x3BC /* Monochome Adapter Printer Port */ #define IO_VGA 0x3C0 /* E/VGA Ports */ #define IO_CGA 0x3D0 /* CGA Ports */ /* 0x3E0 - 0x3E7 Open */ #define IO_COM3 0x3e8 /* COM3 i/o address */ #define IO_FD1 0x3f0 /* primary base i/o address */ #define IO_COM1 0x3f8 /* COM1 i/o address */ #define IO_ISAEND 0x3FF /* - 0x3FF End of I/O Registers */ #endif IO_ISABEGIN /* * Input / Output Port Sizes - these are from several sources, and tend * to be the larger of what was found, ie COM ports can be 4, but some * boards do not fully decode the address, thus 8 ports are used. */ #ifndef IO_ISASIZES #define IO_ISASIZES #define IO_COMSIZE 8 /* 8250, 16X50 com controllers (4?) */ #define IO_CGASIZE 16 /* CGA controllers */ #define IO_DMASIZE 16 /* 8237 DMA controllers */ #define IO_DPGSIZE 32 /* 74LS612 DMA page reisters */ #define IO_FDCSIZE 8 /* Nec765 floppy controllers */ #define IO_WDCSIZE 8 /* WD compatible disk controllers */ #define IO_GAMSIZE 16 /* AT compatible game controllers */ #define IO_ICUSIZE 16 /* 8259A interrupt controllers */ #define IO_KBDSIZE 16 /* 8042 Keyboard controllers */ #define IO_LPTSIZE 8 /* LPT controllers, some use only 4 */ #define IO_MDASIZE 16 /* Monochrome display controllers */ #define IO_RTCSIZE 16 /* CMOS real time clock, NMI control */ #define IO_TMRSIZE 16 /* 8253 programmable timers */ #define IO_NPXSIZE 16 /* 80387/80487 NPX registers */ #define IO_VGASIZE 16 /* VGA controllers */ #endif /* IO_ISASIZES */ /* * Input / Output Memory Physical Addresses */ #ifndef IOM_BEGIN #define IOM_BEGIN 0x0a0000 /* Start of I/O Memory "hole" */ #define IOM_END 0x100000 /* End of I/O Memory "hole" */ #define IOM_SIZE (IOM_END - IOM_BEGIN) #endif IOM_BEGIN /* * RAM Physical Address Space (ignoring the above mentioned "hole") */ #ifndef RAM_BEGIN #define RAM_BEGIN 0x0000000 /* Start of RAM Memory */ #define RAM_END 0x1000000 /* End of RAM Memory */ #define RAM_SIZE (RAM_END - RAM_BEGIN) #endif RAM_BEGIN /* * Oddball Physical Memory Addresses */ #ifndef COMPAQ_RAMRELOC #define COMPAQ_RAMRELOC 0x80c00000 /* Compaq RAM relocation/diag */ #define COMPAQ_RAMSETUP 0x80c00002 /* Compaq RAM setup */ #define WEITEK_FPU 0xC0000000 /* WTL 2167 */ #define CYRIX_EMC 0xC0000000 /* Cyrix EMC */ #endif COMPAQ_RAMRELOC Index: head/sys/i386/isa/isa_device.h =================================================================== --- head/sys/i386/isa/isa_device.h (revision 618) +++ head/sys/i386/isa/isa_device.h (revision 619) @@ -1,85 +1,74 @@ /*- * 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. * - * @(#)isa_device.h 7.1 (Berkeley) 5/9/91 - * - * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE - * -------------------- ----- ---------------------- - * CURRENT PATCH LEVEL: 2 00163 - * -------------------- ----- ---------------------- - * - * 27 Feb 93 Chris Demetriou Add proper flag handling. - * 10 Mar 93 Rodney W. Grimes Fixed isa_device->id_irq to be - * the u_short instead of short. This - * enables us to use irq15! - * 27 May 93 Guido van Rooij Add prototype find_isadev() - * + * from: @(#)isa_device.h 7.1 (Berkeley) 5/9/91 + * $Id$ */ /* * ISA Bus Autoconfiguration */ /* * Per device structure. */ struct isa_device { struct isa_driver *id_driver; short id_iobase; /* base i/o address */ u_short id_irq; /* interrupt request */ short id_drq; /* DMA request */ caddr_t id_maddr; /* physical i/o memory address on bus (if any)*/ int id_msize; /* size of i/o memory */ int (*id_intr)(); /* interrupt interface routine */ int id_unit; /* unit number */ int id_flags; /* flags */ int id_scsiid; /* scsi id if needed */ int id_alive; /* device is present */ }; /* * Per-driver structure. * * Each device driver defines entries for a set of routines * as well as an array of types which are acceptable to it. * These are used at boot time by the configuration program. */ struct isa_driver { int (*probe)(); /* test whether device is present */ int (*attach)(); /* setup driver for a device */ char *name; /* device name */ }; extern struct isa_device isa_devtab_bio[], isa_devtab_tty[], isa_devtab_net[], isa_devtab_null[]; extern struct isa_device *find_isadev(/* table, driver, unit*/); Index: head/sys/i386/isa/iso8859.font =================================================================== --- head/sys/i386/isa/iso8859.font (revision 618) +++ head/sys/i386/isa/iso8859.font (revision 619) @@ -1,1226 +1,1230 @@ -/* ISO 8859-1 font file */ +/* + * ISO 8859-1 font file + * + * $Id$ + */ char font_8x8[256*8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x81, 0xA5, 0x81, 0xBD, 0x99, 0x81, 0x7E, 0x7E, 0xFF, 0xDB, 0xFF, 0xC3, 0xE7, 0xFF, 0x7E, 0x6C, 0xFE, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x38, 0x7C, 0x38, 0xFE, 0xFE, 0x7C, 0x38, 0x7C, 0x10, 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x7C, 0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00, 0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF, 0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, 0x3C, 0x00, 0xFF, 0xC3, 0x99, 0xBD, 0xBD, 0x99, 0xC3, 0xFF, 0x0F, 0x07, 0x0F, 0x7D, 0xCC, 0xCC, 0xCC, 0x78, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18, 0x3F, 0x33, 0x3F, 0x30, 0x30, 0x70, 0xF0, 0xE0, 0x7F, 0x63, 0x7F, 0x63, 0x63, 0x67, 0xE6, 0xC0, 0x99, 0x5A, 0x3C, 0xE7, 0xE7, 0x3C, 0x5A, 0x99, 0x80, 0xE0, 0xF8, 0xFE, 0xF8, 0xE0, 0x80, 0x00, 0x02, 0x0E, 0x3E, 0xFE, 0x3E, 0x0E, 0x02, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00, 0x7F, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x1B, 0x00, 0x3E, 0x63, 0x38, 0x6C, 0x6C, 0x38, 0xCC, 0x78, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x7E, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x7E, 0x3C, 0x18, 0xFF, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00, 0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xFE, 0x00, 0x00, 0x00, 0x24, 0x66, 0xFF, 0x66, 0x24, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00, 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6C, 0x6C, 0xFE, 0x6C, 0xFE, 0x6C, 0x6C, 0x00, 0x30, 0x7C, 0xC0, 0x78, 0x0C, 0xF8, 0x30, 0x00, 0x00, 0xC6, 0xCC, 0x18, 0x30, 0x66, 0xC6, 0x00, 0x38, 0x6C, 0x38, 0x76, 0xDC, 0xCC, 0x76, 0x00, 0x60, 0x60, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00, 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00, 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00, 0x00, 0x30, 0x30, 0xFC, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00, 0x7C, 0xC6, 0xCE, 0xDE, 0xF6, 0xE6, 0x7C, 0x00, 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xFC, 0x00, 0x78, 0xCC, 0x0C, 0x38, 0x60, 0xCC, 0xFC, 0x00, 0x78, 0xCC, 0x0C, 0x38, 0x0C, 0xCC, 0x78, 0x00, 0x1C, 0x3C, 0x6C, 0xCC, 0xFE, 0x0C, 0x1E, 0x00, 0xFC, 0xC0, 0xF8, 0x0C, 0x0C, 0xCC, 0x78, 0x00, 0x38, 0x60, 0xC0, 0xF8, 0xCC, 0xCC, 0x78, 0x00, 0xFC, 0xCC, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0xCC, 0xCC, 0x78, 0x00, 0x78, 0xCC, 0xCC, 0x7C, 0x0C, 0x18, 0x70, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60, 0x18, 0x30, 0x60, 0xC0, 0x60, 0x30, 0x18, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0C, 0x18, 0x30, 0x60, 0x00, 0x78, 0xCC, 0x0C, 0x18, 0x30, 0x00, 0x30, 0x00, 0x7C, 0xC6, 0xDE, 0xDE, 0xDE, 0xC0, 0x78, 0x00, 0x30, 0x78, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0x00, 0xFC, 0x66, 0x66, 0x7C, 0x66, 0x66, 0xFC, 0x00, 0x3C, 0x66, 0xC0, 0xC0, 0xC0, 0x66, 0x3C, 0x00, 0xF8, 0x6C, 0x66, 0x66, 0x66, 0x6C, 0xF8, 0x00, 0xFE, 0x62, 0x68, 0x78, 0x68, 0x62, 0xFE, 0x00, 0xFE, 0x62, 0x68, 0x78, 0x68, 0x60, 0xF0, 0x00, 0x3C, 0x66, 0xC0, 0xC0, 0xCE, 0x66, 0x3E, 0x00, 0xCC, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0xCC, 0x00, 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, 0x1E, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78, 0x00, 0xE6, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0xE6, 0x00, 0xF0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xFE, 0x00, 0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00, 0xC6, 0xE6, 0xF6, 0xDE, 0xCE, 0xC6, 0xC6, 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x00, 0xFC, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00, 0x78, 0xCC, 0xCC, 0xCC, 0xDC, 0x78, 0x1C, 0x00, 0xFC, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0xE6, 0x00, 0x78, 0xCC, 0xE0, 0x70, 0x1C, 0xCC, 0x78, 0x00, 0xFC, 0xB4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xFC, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00, 0xC6, 0xC6, 0xC6, 0xD6, 0xFE, 0xEE, 0xC6, 0x00, 0xC6, 0xC6, 0x6C, 0x38, 0x38, 0x6C, 0xC6, 0x00, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x30, 0x78, 0x00, 0xFE, 0xC6, 0x8C, 0x18, 0x32, 0x66, 0xFE, 0x00, 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00, 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x02, 0x00, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00, 0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00, 0xE0, 0x60, 0x60, 0x7C, 0x66, 0x66, 0xDC, 0x00, 0x00, 0x00, 0x78, 0xCC, 0xC0, 0xCC, 0x78, 0x00, 0x1C, 0x0C, 0x0C, 0x7C, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00, 0x38, 0x6C, 0x60, 0xF0, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8, 0xE0, 0x60, 0x6C, 0x76, 0x66, 0x66, 0xE6, 0x00, 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, 0x0C, 0x00, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78, 0xE0, 0x60, 0x66, 0x6C, 0x78, 0x6C, 0xE6, 0x00, 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, 0x00, 0x00, 0xCC, 0xFE, 0xFE, 0xD6, 0xC6, 0x00, 0x00, 0x00, 0xF8, 0xCC, 0xCC, 0xCC, 0xCC, 0x00, 0x00, 0x00, 0x78, 0xCC, 0xCC, 0xCC, 0x78, 0x00, 0x00, 0x00, 0xDC, 0x66, 0x66, 0x7C, 0x60, 0xF0, 0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0x1E, 0x00, 0x00, 0xDC, 0x76, 0x66, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x7C, 0xC0, 0x78, 0x0C, 0xF8, 0x00, 0x10, 0x30, 0x7C, 0x30, 0x30, 0x34, 0x18, 0x00, 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00, 0x00, 0x00, 0xC6, 0xD6, 0xFE, 0xFE, 0x6C, 0x00, 0x00, 0x00, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8, 0x00, 0x00, 0xFC, 0x98, 0x30, 0x64, 0xFC, 0x00, 0x1C, 0x30, 0x30, 0xE0, 0x30, 0x30, 0x1C, 0x00, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00, 0xE0, 0x30, 0x30, 0x1C, 0x30, 0x30, 0xE0, 0x00, 0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x7E, 0xFF, 0x7E, 0x18, 0x00, 0xAA, 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55, 0xAA, 0x44, 0x44, 0x44, 0x44, 0x1F, 0x04, 0x04, 0x04, 0x7C, 0x40, 0x40, 0x40, 0x1F, 0x10, 0x10, 0x10, 0x38, 0x44, 0x44, 0x38, 0x1E, 0x11, 0x14, 0x13, 0x40, 0x40, 0x40, 0x7C, 0x1F, 0x10, 0x10, 0x10, 0x38, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x00, 0x44, 0x64, 0x4C, 0x44, 0x10, 0x10, 0x10, 0x1F, 0x44, 0x44, 0x28, 0x10, 0x1F, 0x04, 0x04, 0x04, 0x18, 0x18, 0x18, 0x18, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x0C, 0x30, 0x60, 0x18, 0x0C, 0x7E, 0x00, 0x00, 0x30, 0x0C, 0x06, 0x18, 0x30, 0x7E, 0x00, 0x00, 0x00, 0x03, 0x3E, 0x36, 0x36, 0x6C, 0x00, 0x00, 0x00, 0x04, 0x7E, 0x10, 0x7E, 0x40, 0x00, 0x00, 0x1C, 0x30, 0x30, 0x30, 0x30, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x30, 0x30, 0x78, 0x78, 0x30, 0x00, 0x00, 0x00, 0x10, 0x7C, 0xC0, 0xC0, 0x7C, 0x10, 0x00, 0x38, 0x60, 0x60, 0xF0, 0x60, 0xFC, 0x00, 0x00, 0xC3, 0x3C, 0x66, 0x66, 0x3C, 0xC3, 0x00, 0x00, 0xCC, 0xCC, 0x78, 0x30, 0xFC, 0x30, 0x00, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00, 0x7E, 0xC0, 0x7C, 0xC6, 0x7C, 0x06, 0xFC, 0x00, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x82, 0xBA, 0xA2, 0xBA, 0x82, 0x7C, 0x00, 0x1C, 0x06, 0x1E, 0x22, 0x1F, 0x3F, 0x00, 0x00, 0x00, 0x33, 0x66, 0xCC, 0x66, 0x33, 0x00, 0x00, 0x00, 0xFE, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x82, 0xBA, 0xB2, 0xAA, 0x82, 0x7C, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x7C, 0x10, 0x00, 0x7C, 0x00, 0x00, 0x1C, 0x36, 0x06, 0x18, 0x3E, 0x00, 0x00, 0x00, 0x1E, 0x02, 0x0E, 0x02, 0x1E, 0x00, 0x00, 0x00, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0xC0, 0x7E, 0xCA, 0xCA, 0x7E, 0x0A, 0x0A, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x06, 0x0E, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x0E, 0x11, 0x11, 0x11, 0x0E, 0x1F, 0x00, 0x00, 0x00, 0xCC, 0x66, 0x33, 0x66, 0xCC, 0x00, 0x00, 0x60, 0xE0, 0x66, 0x6C, 0x33, 0x67, 0x0F, 0x03, 0x60, 0xE0, 0x66, 0x6C, 0x36, 0x6A, 0x04, 0x0E, 0xF0, 0x20, 0x96, 0x6C, 0x33, 0x67, 0x0F, 0x03, 0x30, 0x00, 0x30, 0x60, 0xC0, 0xCC, 0x78, 0x00, 0x18, 0x0C, 0x30, 0x78, 0xCC, 0xFC, 0xCC, 0x00, 0x60, 0xC0, 0x30, 0x78, 0xCC, 0xFC, 0xCC, 0x00, 0x78, 0x84, 0x30, 0x78, 0xCC, 0xFC, 0xCC, 0x00, 0x66, 0x98, 0x30, 0x78, 0xCC, 0xFC, 0xCC, 0x00, 0xCC, 0x00, 0x30, 0x78, 0xCC, 0xFC, 0xCC, 0x00, 0x30, 0x48, 0x30, 0x78, 0xCC, 0xFC, 0xCC, 0x00, 0x3E, 0x78, 0x98, 0x9C, 0xF8, 0x98, 0x9E, 0x00, 0x3C, 0x66, 0xC0, 0xC0, 0xC0, 0x66, 0x1C, 0x30, 0x30, 0x18, 0xFE, 0x62, 0x78, 0x62, 0xFE, 0x00, 0x18, 0x30, 0xFE, 0x62, 0x78, 0x62, 0xFE, 0x00, 0x38, 0x44, 0xFE, 0x62, 0x78, 0x62, 0xFE, 0x00, 0x66, 0x00, 0xFE, 0x62, 0x78, 0x62, 0xFE, 0x00, 0x60, 0x30, 0x78, 0x30, 0x30, 0x30, 0x78, 0x00, 0x18, 0x30, 0x78, 0x30, 0x30, 0x30, 0x78, 0x00, 0x78, 0x84, 0x78, 0x30, 0x30, 0x30, 0x78, 0x00, 0xCC, 0x00, 0x78, 0x30, 0x30, 0x30, 0x78, 0x00, 0x78, 0x6C, 0x66, 0xF6, 0x66, 0x6C, 0x78, 0x00, 0x66, 0x98, 0xE6, 0xF6, 0xDE, 0xCE, 0xC6, 0x00, 0x30, 0x18, 0x7C, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x18, 0x30, 0x7C, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x38, 0x44, 0x7C, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x66, 0x98, 0x7C, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0xC6, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0xC6, 0x6C, 0x38, 0x38, 0x6C, 0xC6, 0x00, 0x06, 0x7C, 0xCE, 0x9A, 0xB2, 0xE6, 0x78, 0xC0, 0x60, 0x30, 0xCC, 0xCC, 0xCC, 0xCC, 0xFC, 0x00, 0x18, 0x30, 0xCC, 0xCC, 0xCC, 0xCC, 0xFC, 0x00, 0x78, 0x84, 0xCC, 0xCC, 0xCC, 0xCC, 0xFC, 0x00, 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xFC, 0x00, 0x18, 0x30, 0xCC, 0xCC, 0x78, 0x30, 0x78, 0x00, 0x60, 0x78, 0x6C, 0x78, 0x60, 0x60, 0x60, 0x00, 0x78, 0xCC, 0xC4, 0xDC, 0xC6, 0xC6, 0xDC, 0xC0, 0x30, 0x18, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00, 0x18, 0x30, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00, 0x78, 0x84, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00, 0x66, 0x98, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00, 0xCC, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00, 0x30, 0x48, 0x38, 0x0C, 0x7C, 0xCC, 0x76, 0x00, 0x00, 0x00, 0xEC, 0x32, 0x7E, 0xB0, 0x6E, 0x00, 0x00, 0x00, 0x3C, 0x66, 0xC0, 0x66, 0x1C, 0x30, 0x30, 0x18, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00, 0x18, 0x30, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00, 0x78, 0x84, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00, 0xCC, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00, 0x60, 0x30, 0x00, 0x70, 0x30, 0x30, 0x78, 0x00, 0x18, 0x30, 0x00, 0x70, 0x30, 0x30, 0x78, 0x00, 0x70, 0x88, 0x00, 0x70, 0x30, 0x30, 0x78, 0x00, 0xCC, 0x00, 0x00, 0x70, 0x30, 0x30, 0x78, 0x00, 0x6C, 0x38, 0x6C, 0x0C, 0x6C, 0xCC, 0x78, 0x00, 0x66, 0x98, 0xF8, 0xCC, 0xCC, 0xCC, 0xCC, 0x00, 0x60, 0x30, 0x00, 0x7C, 0xC6, 0xC6, 0x7C, 0x00, 0x18, 0x30, 0x00, 0x7C, 0xC6, 0xC6, 0x7C, 0x00, 0x38, 0x44, 0x00, 0x7C, 0xC6, 0xC6, 0x7C, 0x00, 0x66, 0x98, 0x00, 0x7C, 0xC6, 0xC6, 0x7C, 0x00, 0xC6, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x18, 0x00, 0x7E, 0x00, 0x18, 0x00, 0x00, 0x00, 0x06, 0x7C, 0xDE, 0xF6, 0x7C, 0xC0, 0x60, 0x30, 0x00, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x18, 0x30, 0x00, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x30, 0x48, 0x00, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0xCC, 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x18, 0x30, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8, 0xE0, 0x78, 0x6C, 0x66, 0x6C, 0x78, 0xE0, 0x00, 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8 }; char font_8x14[256*14] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x81, 0xA5, 0x81, 0x81, 0xBD, 0x99, 0x81, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0xFF, 0xDB, 0xFF, 0xFF, 0xC3, 0xE7, 0xFF, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x7F, 0x7F, 0x7F, 0x7F, 0x3E, 0x1C, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x1C, 0x3E, 0x7F, 0x3E, 0x1C, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x3C, 0xE7, 0xE7, 0xE7, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x7E, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x24, 0x42, 0x42, 0x24, 0x3C, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xC3, 0xDB, 0xBD, 0xBD, 0xDB, 0xC3, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x1F, 0x07, 0x0D, 0x19, 0x78, 0xCC, 0xCC, 0xCC, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0A, 0x09, 0x09, 0x09, 0x0A, 0x08, 0x38, 0x78, 0x78, 0x30, 0x00, 0x00, 0x00, 0x1F, 0x11, 0x1F, 0x11, 0x11, 0x11, 0x13, 0x37, 0x77, 0x72, 0x20, 0x00, 0x00, 0x00, 0x18, 0x18, 0xDB, 0x3C, 0xE7, 0x3C, 0xDB, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x60, 0x70, 0x7C, 0x7F, 0x7C, 0x70, 0x60, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x07, 0x1F, 0x7F, 0x1F, 0x07, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x00, 0x33, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xDB, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x1B, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x63, 0x30, 0x1C, 0x36, 0x63, 0x63, 0x36, 0x1C, 0x06, 0x63, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x7F, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x06, 0x7F, 0x06, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x7F, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x60, 0x60, 0x60, 0x7F, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x42, 0xFF, 0x42, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x7E, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x7E, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x7F, 0x36, 0x36, 0x36, 0x7F, 0x36, 0x36, 0x00, 0x00, 0x00, 0x08, 0x08, 0x3E, 0x63, 0x60, 0x60, 0x3E, 0x03, 0x03, 0x63, 0x3E, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x61, 0x63, 0x06, 0x0C, 0x18, 0x30, 0x63, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x36, 0x36, 0x1C, 0x3B, 0x6E, 0x66, 0x66, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3C, 0x7E, 0x3C, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x63, 0x67, 0x6F, 0x7B, 0x73, 0x63, 0x63, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x1C, 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x63, 0x03, 0x06, 0x0C, 0x18, 0x30, 0x63, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x63, 0x03, 0x03, 0x1E, 0x03, 0x03, 0x63, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x0E, 0x1E, 0x36, 0x66, 0x7F, 0x06, 0x06, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x60, 0x60, 0x60, 0x7E, 0x03, 0x03, 0x63, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x30, 0x60, 0x60, 0x7E, 0x63, 0x63, 0x63, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x63, 0x03, 0x06, 0x0C, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x63, 0x63, 0x63, 0x3E, 0x63, 0x63, 0x63, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x63, 0x63, 0x63, 0x3F, 0x03, 0x03, 0x06, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x63, 0x63, 0x06, 0x0C, 0x0C, 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x63, 0x63, 0x6F, 0x6F, 0x6F, 0x6E, 0x60, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x1C, 0x36, 0x63, 0x63, 0x7F, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x33, 0x33, 0x33, 0x3E, 0x33, 0x33, 0x33, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x33, 0x60, 0x60, 0x60, 0x60, 0x60, 0x33, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x36, 0x33, 0x33, 0x33, 0x33, 0x33, 0x36, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x33, 0x30, 0x34, 0x3C, 0x34, 0x30, 0x33, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x33, 0x30, 0x34, 0x3C, 0x34, 0x30, 0x30, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x33, 0x60, 0x60, 0x60, 0x6F, 0x63, 0x33, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x63, 0x63, 0x63, 0x7F, 0x63, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x06, 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x33, 0x36, 0x36, 0x3C, 0x36, 0x36, 0x33, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x33, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x77, 0x7F, 0x6B, 0x63, 0x63, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x73, 0x7B, 0x7F, 0x6F, 0x67, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x36, 0x63, 0x63, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x33, 0x33, 0x33, 0x3E, 0x30, 0x30, 0x30, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x36, 0x63, 0x63, 0x63, 0x63, 0x6B, 0x3E, 0x1C, 0x06, 0x03, 0x00, 0x00, 0x00, 0x7E, 0x33, 0x33, 0x33, 0x3E, 0x36, 0x33, 0x33, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x63, 0x63, 0x30, 0x1C, 0x06, 0x63, 0x63, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x5A, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x63, 0x63, 0x63, 0x63, 0x6B, 0x6B, 0x7F, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x36, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x63, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x63, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C, 0x00, 0x00, 0x00, 0x08, 0x1C, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x18, 0x18, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x66, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x30, 0x30, 0x3E, 0x33, 0x33, 0x33, 0x33, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x63, 0x60, 0x60, 0x63, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x66, 0x66, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x63, 0x7F, 0x60, 0x63, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x33, 0x30, 0x7C, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3B, 0x66, 0x66, 0x66, 0x3E, 0x06, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x70, 0x30, 0x30, 0x36, 0x3B, 0x33, 0x33, 0x33, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00, 0x1C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00, 0x1C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0xCC, 0x78, 0x00, 0x00, 0x00, 0x70, 0x30, 0x30, 0x33, 0x36, 0x3C, 0x36, 0x33, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x7F, 0x6B, 0x6B, 0x6B, 0x6B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6E, 0x33, 0x33, 0x33, 0x33, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x63, 0x63, 0x63, 0x63, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6E, 0x33, 0x33, 0x33, 0x3E, 0x30, 0x30, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3B, 0x66, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6E, 0x33, 0x30, 0x30, 0x30, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x63, 0x38, 0x0E, 0x63, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x18, 0x7E, 0x18, 0x18, 0x18, 0x1B, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x63, 0x6B, 0x6B, 0x7F, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x36, 0x1C, 0x1C, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x66, 0x66, 0x66, 0x3E, 0x06, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x66, 0x0C, 0x18, 0x33, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0E, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3B, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x1C, 0x36, 0x63, 0x63, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x00, 0x44, 0x44, 0x7C, 0x44, 0x44, 0x00, 0x1F, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x7C, 0x40, 0x78, 0x40, 0x40, 0x00, 0x1F, 0x10, 0x1E, 0x10, 0x10, 0x00, 0x00, 0x00, 0x38, 0x44, 0x40, 0x44, 0x38, 0x00, 0x1E, 0x11, 0x1E, 0x14, 0x13, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x7C, 0x00, 0x1F, 0x10, 0x1E, 0x10, 0x10, 0x00, 0x00, 0x00, 0x38, 0x6C, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x44, 0x64, 0x54, 0x4C, 0x44, 0x00, 0x10, 0x10, 0x10, 0x10, 0x1F, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x28, 0x10, 0x00, 0x1F, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x3E, 0x76, 0x36, 0x36, 0x36, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x04, 0x7E, 0x08, 0x10, 0x7E, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x36, 0x30, 0x30, 0x7C, 0x30, 0x30, 0x73, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x3C, 0x3C, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x3E, 0x63, 0x60, 0x60, 0x63, 0x3E, 0x08, 0x08, 0x00, 0x00, 0x00, 0x1C, 0x36, 0x30, 0x30, 0x7C, 0x30, 0x30, 0x73, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18, 0x7E, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x63, 0x30, 0x1C, 0x36, 0x63, 0x63, 0x36, 0x1C, 0x06, 0x63, 0x3E, 0x00, 0x00, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x41, 0x5D, 0x51, 0x51, 0x5D, 0x41, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x38, 0x04, 0x3C, 0x44, 0x3C, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x36, 0x6C, 0x36, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x41, 0x5D, 0x55, 0x59, 0x55, 0x41, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6C, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6C, 0x18, 0x30, 0x64, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x0C, 0x38, 0x0C, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3B, 0x60, 0xC0, 0x00, 0x00, 0x00, 0x7F, 0xDB, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x1B, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x06, 0x1C, 0x00, 0x30, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6C, 0x36, 0x1B, 0x36, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xE0, 0x63, 0x66, 0x6C, 0x18, 0x33, 0x67, 0xCF, 0x1F, 0x03, 0x03, 0x00, 0x00, 0x60, 0xE0, 0x63, 0x66, 0x6C, 0x18, 0x30, 0x6E, 0xC3, 0x06, 0x0C, 0x1F, 0x00, 0x00, 0xF0, 0x30, 0x63, 0xF6, 0x6C, 0x18, 0x33, 0x67, 0xCF, 0x1F, 0x03, 0x03, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x30, 0x63, 0x63, 0x3E, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x1C, 0x36, 0x63, 0x63, 0x7F, 0x63, 0x63, 0x00, 0x00, 0x00, 0x03, 0x06, 0x0C, 0x00, 0x1C, 0x36, 0x63, 0x63, 0x7F, 0x63, 0x63, 0x00, 0x00, 0x00, 0x08, 0x1C, 0x36, 0x00, 0x1C, 0x36, 0x63, 0x63, 0x7F, 0x63, 0x63, 0x00, 0x00, 0x00, 0x3B, 0x6E, 0x00, 0x08, 0x1C, 0x36, 0x63, 0x63, 0x7F, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00, 0x63, 0x63, 0x08, 0x1C, 0x36, 0x63, 0x63, 0x7F, 0x63, 0x63, 0x00, 0x00, 0x00, 0x1C, 0x36, 0x1C, 0x00, 0x1C, 0x36, 0x63, 0x63, 0x7F, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x36, 0x66, 0x66, 0x67, 0x7E, 0x66, 0x66, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x33, 0x60, 0x60, 0x60, 0x60, 0x60, 0x33, 0x1E, 0x0C, 0x06, 0x1C, 0x60, 0x30, 0x18, 0x00, 0x7F, 0x33, 0x30, 0x3E, 0x30, 0x33, 0x7F, 0x00, 0x00, 0x00, 0x06, 0x0C, 0x18, 0x00, 0x7F, 0x33, 0x30, 0x3E, 0x30, 0x33, 0x7F, 0x00, 0x00, 0x00, 0x08, 0x1C, 0x36, 0x00, 0x7F, 0x33, 0x30, 0x3E, 0x30, 0x33, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x63, 0x63, 0x00, 0x7F, 0x33, 0x30, 0x3E, 0x30, 0x33, 0x7F, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x06, 0x0C, 0x18, 0x00, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x66, 0x00, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x00, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x36, 0x33, 0x33, 0x7B, 0x33, 0x33, 0x36, 0x3C, 0x00, 0x00, 0x00, 0x3B, 0x6E, 0x00, 0x63, 0x73, 0x7B, 0x7F, 0x6F, 0x67, 0x63, 0x63, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x1C, 0x36, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00, 0x00, 0x00, 0x03, 0x06, 0x0C, 0x00, 0x1C, 0x36, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00, 0x00, 0x00, 0x08, 0x1C, 0x36, 0x00, 0x1C, 0x36, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x3B, 0x6E, 0x00, 0x1C, 0x36, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x63, 0x63, 0x00, 0x1C, 0x36, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x36, 0x1C, 0x08, 0x1C, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x1E, 0x36, 0x67, 0x6F, 0x6B, 0x7B, 0x73, 0x36, 0x3C, 0x60, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3E, 0x00, 0x00, 0x00, 0x03, 0x06, 0x0C, 0x00, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3E, 0x00, 0x00, 0x00, 0x08, 0x1C, 0x36, 0x00, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x63, 0x63, 0x00, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3E, 0x00, 0x00, 0x00, 0x06, 0x0C, 0x18, 0x00, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x78, 0x30, 0x3E, 0x33, 0x33, 0x3E, 0x30, 0x30, 0x30, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x36, 0x63, 0x66, 0x6C, 0x67, 0x63, 0x6B, 0x6E, 0x60, 0x60, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x66, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x06, 0x0C, 0x18, 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x66, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x08, 0x1C, 0x36, 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x66, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3B, 0x6E, 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x66, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x66, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x36, 0x1C, 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x66, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0x0B, 0x3B, 0x6E, 0x68, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x63, 0x60, 0x60, 0x63, 0x3E, 0x0C, 0x06, 0x1C, 0x00, 0x30, 0x18, 0x0C, 0x00, 0x3E, 0x63, 0x7F, 0x60, 0x63, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x03, 0x06, 0x0C, 0x00, 0x3E, 0x63, 0x7F, 0x60, 0x63, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x08, 0x1C, 0x36, 0x00, 0x3E, 0x63, 0x7F, 0x60, 0x63, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x63, 0x00, 0x3E, 0x63, 0x7F, 0x60, 0x63, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x06, 0x0C, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x1C, 0x36, 0x06, 0x3E, 0x66, 0x66, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3B, 0x6E, 0x00, 0x6E, 0x33, 0x33, 0x33, 0x33, 0x33, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x3E, 0x63, 0x63, 0x63, 0x63, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x06, 0x0C, 0x18, 0x00, 0x3E, 0x63, 0x63, 0x63, 0x63, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x08, 0x1C, 0x36, 0x00, 0x3E, 0x63, 0x63, 0x63, 0x63, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3B, 0x6E, 0x00, 0x3E, 0x63, 0x63, 0x63, 0x63, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x63, 0x00, 0x3E, 0x63, 0x63, 0x63, 0x63, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x3E, 0x67, 0x6F, 0x7B, 0x73, 0x3E, 0x60, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x06, 0x0C, 0x18, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x66, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x06, 0x0C, 0x18, 0x00, 0x63, 0x66, 0x66, 0x66, 0x3E, 0x06, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x78, 0x30, 0x3E, 0x33, 0x33, 0x33, 0x33, 0x3E, 0x30, 0x78, 0x00, 0x00, 0x00, 0x66, 0x66, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3E, 0x06, 0x66, 0x3C, 0x00 }; char font_8x16[256*16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x81, 0xA5, 0x81, 0x81, 0xBD, 0x99, 0x81, 0x81, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0xFF, 0xDB, 0xFF, 0xFF, 0xC3, 0xE7, 0xFF, 0xFF, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6C, 0xFE, 0xFE, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x3C, 0xE7, 0xE7, 0xE7, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x7E, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC3, 0x99, 0xBD, 0xBD, 0x99, 0xC3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x1E, 0x0E, 0x1A, 0x32, 0x78, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x33, 0x3F, 0x30, 0x30, 0x30, 0x30, 0x70, 0xF0, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x63, 0x7F, 0x63, 0x63, 0x63, 0x63, 0x67, 0xE7, 0xE6, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0xDB, 0x3C, 0xE7, 0x3C, 0xDB, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFE, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0E, 0x1E, 0x3E, 0xFE, 0x3E, 0x1E, 0x0E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xDB, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0x60, 0x38, 0x6C, 0xC6, 0xC6, 0x6C, 0x38, 0x0C, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x66, 0xFF, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7C, 0x7C, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0x7C, 0x7C, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x3C, 0x3C, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6C, 0x6C, 0xFE, 0x6C, 0x6C, 0x6C, 0xFE, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7C, 0xC6, 0xC2, 0xC0, 0x7C, 0x06, 0x06, 0x86, 0xC6, 0x7C, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC2, 0xC6, 0x0C, 0x18, 0x30, 0x60, 0xC6, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6C, 0x6C, 0x38, 0x76, 0xDC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, 0xC3, 0xC3, 0xDB, 0xDB, 0xC3, 0xC3, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0x06, 0x06, 0x3C, 0x06, 0x06, 0x06, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x1C, 0x3C, 0x6C, 0xCC, 0xFE, 0x0C, 0x0C, 0x0C, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xC0, 0xC0, 0xC0, 0xFC, 0x06, 0x06, 0x06, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x60, 0xC0, 0xC0, 0xFC, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xC6, 0x06, 0x06, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x06, 0x06, 0x0C, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0x0C, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xDE, 0xDE, 0xDE, 0xDC, 0xC0, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x66, 0x66, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, 0xC2, 0xC0, 0xC0, 0xC0, 0xC0, 0xC2, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x6C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6C, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, 0xC2, 0xC0, 0xC0, 0xDE, 0xC6, 0xC6, 0x66, 0x3A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0xCC, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0x66, 0x66, 0x6C, 0x78, 0x78, 0x6C, 0x66, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x62, 0x66, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC3, 0xE7, 0xFF, 0xFF, 0xDB, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xE6, 0xF6, 0xFE, 0xDE, 0xCE, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xD6, 0xDE, 0x7C, 0x0C, 0x0E, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0x66, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0x60, 0x38, 0x0C, 0x06, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xDB, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x66, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xDB, 0xDB, 0xFF, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC3, 0xC3, 0x66, 0x3C, 0x18, 0x18, 0x3C, 0x66, 0xC3, 0xC3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC3, 0xC3, 0xC3, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xC3, 0x86, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0xC3, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0x70, 0x38, 0x1C, 0x0E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x60, 0x60, 0x78, 0x6C, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC0, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x0C, 0x0C, 0x3C, 0x6C, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6C, 0x64, 0x60, 0xF0, 0x60, 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xCC, 0x78, 0x00, 0x00, 0x00, 0xE0, 0x60, 0x60, 0x6C, 0x76, 0x66, 0x66, 0x66, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x0E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3C, 0x00, 0x00, 0x00, 0xE0, 0x60, 0x60, 0x66, 0x6C, 0x78, 0x78, 0x6C, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xFF, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0x0C, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x76, 0x66, 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0x60, 0x38, 0x0C, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x30, 0x30, 0xFC, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC3, 0xC3, 0xC3, 0xC3, 0x66, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC3, 0xC3, 0xC3, 0xDB, 0xDB, 0xFF, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC3, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0xC3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x0C, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xCC, 0x18, 0x30, 0x60, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0E, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x00, 0x88, 0x88, 0xF8, 0x88, 0x88, 0x88, 0x00, 0x3E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0xF8, 0x80, 0xF0, 0x80, 0x80, 0x80, 0x00, 0x3E, 0x20, 0x3C, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x70, 0x88, 0x80, 0x80, 0x88, 0x70, 0x00, 0x3C, 0x22, 0x3C, 0x28, 0x24, 0x22, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0xF8, 0x00, 0x3E, 0x20, 0x3C, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x38, 0x6C, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xC8, 0xA8, 0xA8, 0x98, 0x88, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3E, 0x00, 0x00, 0x00, 0x88, 0x88, 0x88, 0x88, 0x50, 0x20, 0x00, 0x3E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x7E, 0xEC, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0xCC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x0C, 0x7E, 0x18, 0x18, 0x7E, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6C, 0x64, 0x60, 0xF0, 0x60, 0x60, 0x60, 0x60, 0xE6, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x3C, 0x3C, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E, 0xC3, 0xC0, 0xC0, 0xC0, 0xC3, 0x7E, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6C, 0x64, 0x60, 0xF0, 0x60, 0x60, 0x60, 0x60, 0xE6, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0xC6, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0xC6, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC3, 0x66, 0x3C, 0x18, 0xFF, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0x60, 0x38, 0x6C, 0xC6, 0xC6, 0x6C, 0x38, 0x0C, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0x82, 0xBA, 0xA2, 0xA2, 0xBA, 0x82, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x18, 0x78, 0xC8, 0x78, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6C, 0xD8, 0x6C, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0x82, 0xBA, 0xAA, 0xB2, 0xAA, 0x82, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6C, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xD8, 0x30, 0x60, 0xC8, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x18, 0x30, 0x18, 0xD8, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x63, 0x60, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xDB, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0C, 0x06, 0x3C, 0x00, 0x00, 0x00, 0x60, 0xE0, 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xD8, 0x88, 0xD8, 0x70, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0x6C, 0x36, 0x6C, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0, 0xC2, 0xC6, 0xCC, 0x18, 0x30, 0x66, 0xCE, 0x96, 0x3E, 0x06, 0x06, 0x00, 0x00, 0x00, 0xC0, 0xC0, 0xC2, 0xC6, 0xCC, 0x18, 0x30, 0x60, 0xCE, 0x9B, 0x06, 0x0C, 0x1F, 0x00, 0x00, 0x00, 0xF0, 0x30, 0x72, 0x36, 0xEC, 0x18, 0x30, 0x66, 0xCE, 0x96, 0x3E, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xC0, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x18, 0x30, 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6C, 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xDC, 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6C, 0x38, 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x6C, 0xCC, 0xCC, 0xFE, 0xCC, 0xCC, 0xCC, 0xCC, 0xCE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, 0xC2, 0xC0, 0xC0, 0xC0, 0xC2, 0x66, 0x3C, 0x0C, 0x06, 0x7C, 0x00, 0x00, 0x30, 0x18, 0x0C, 0x00, 0xFE, 0x66, 0x60, 0x7C, 0x60, 0x60, 0x66, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0xFE, 0x66, 0x60, 0x7C, 0x60, 0x60, 0x66, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6C, 0x00, 0xFE, 0x66, 0x60, 0x7C, 0x60, 0x60, 0x66, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x00, 0xFE, 0x66, 0x60, 0x60, 0x7C, 0x60, 0x60, 0x66, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18, 0x0C, 0x00, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x18, 0x30, 0x00, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x66, 0x00, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x6C, 0x66, 0x66, 0x66, 0xF6, 0x66, 0x66, 0x6C, 0x78, 0x00, 0x00, 0x00, 0x00, 0x76, 0xDC, 0x00, 0xC6, 0xE6, 0xF6, 0xFE, 0xDE, 0xCE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x18, 0x30, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6C, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x76, 0xDC, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x6C, 0x38, 0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x7C, 0xCE, 0xCE, 0xDE, 0xD6, 0xD6, 0xF6, 0xE6, 0xE6, 0x7C, 0xC0, 0x80, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x18, 0x30, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6C, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x18, 0x30, 0x00, 0xC3, 0xC3, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x60, 0x7C, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6C, 0xC6, 0xCE, 0xDC, 0xD8, 0xCC, 0xC6, 0xD6, 0xDC, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6C, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xDC, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6C, 0x38, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6E, 0x3B, 0x1B, 0x7E, 0xD8, 0xDC, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, 0x60, 0x60, 0x66, 0x3C, 0x0C, 0x06, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x18, 0x30, 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6C, 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x00, 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x0C, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6C, 0x38, 0x38, 0x6C, 0x0C, 0x3C, 0x6C, 0xCC, 0xCC, 0xCC, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xDC, 0x00, 0xDC, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6C, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xDC, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7E, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x7C, 0xCE, 0xDE, 0xD6, 0xF6, 0xE6, 0x7C, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x78, 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x0C, 0xF8, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x60, 0x7C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x66, 0x66, 0x00, 0xEE, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3E, 0x06, 0x0C, 0x38, 0x00 }; Index: head/sys/i386/isa/kbd.h =================================================================== --- head/sys/i386/isa/kbd.h (revision 618) +++ head/sys/i386/isa/kbd.h (revision 619) @@ -1,58 +1,52 @@ /* - * - * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE - * -------------------- ----- ---------------------- - * CURRENT PATCH LEVEL: 1 00162 - * -------------------- ----- ---------------------- - * - * 26 May 93 Holger Veit added more 8042 defines - * * Keyboard definitions + * from: unknown origin, 386BSD 0.1 + * $Id$ */ /* Reference: IBM AT Technical Reference Manual, * pp. 1-38 to 1-43, 4-3 to 4-22 */ /* commands sent to KBCMDP */ #define KBC_CMDREAD 0x20 /* read kbd cntrl command byte */ #define KBC_CMDWRITE 0x60 /* == LD_CMDBYTE in kd.h, write command */ #define KBC_SELFTEST 0xAA /* perform self test, returns 55 when ok */ #define KBC_IFTEST 0xAB /* perform interface test */ #define KBC_DIAGDUMP 0xAC /* send 19 status bytes to system */ #define KBC_DISKBD 0xAD /* disable keyboard */ #define KBC_ENAKBD 0xAE /* enable keyboard */ #define KBC_RDINP 0xC0 /* read input port */ #define KBC_RDID 0xC4 /* read keyboard ID */ #define KBC_RDOUTP 0xD0 /* read output port */ #define KBC_WROUTP 0xD1 /* write output port */ #define KBC_RDTINP 0xE0 /* read test inputs */ /* commands sent to KBDATAP */ #define KBC_STSIND 0xED /* set keyboard status indicators */ #define KBC_ECHO 0xEE /* reply with 0xEE */ #define KBC_SETTPM 0xF3 /* Set typematic rate/delay */ #define KBC_ENABLE 0xF4 /* Start scanning */ #define KBC_SETDEFD 0xF5 /* =KBC_SETDEF, but disable scanning */ #define KBC_SETDEF 0xF6 /* Set power on defaults */ #define KBC_RESEND 0xFE /* system wants keyboard to resend last code */ #define KBC_RESET 0xFF /* Reset the keyboard */ /* responses */ #define KBR_OVERRUN 0x00 /* Keyboard flooded */ #define KBR_STOK 0x55 /* Selftest ok response */ #define KBR_IFOK 0x00 /* Interface test ok */ #define KBR_IFCL_SA0 0x01 /* Clock Stuck-at-0 fault */ #define KBR_IFCL_SA1 0x02 /* Clock Stuck-at-1 fault */ #define KBR_IFDA_SA0 0x03 /* Data Stuck-at-0 fault */ #define KBR_IFDA_SA1 0x04 /* Data Stuck-at-1 fault */ #define KBR_RSTDONE 0xAA /* Keyboard reset (BAT) complete */ #define KBR_E0 0xE0 /* Extended prefix */ #define KBR_E1 0xE1 /* BREAK'S HIT :-( */ #define KBR_ECHO 0xEE /* Echo response */ #define KBR_F0 0xF0 /* Break code prefix */ #define KBR_ACK 0xFA /* Keyboard did receive command */ #define KBR_BATFAIL 0xFC /* BAT failed */ #define KBR_DIAGFAIL 0xFD /* Diagnostic failed response */ #define KBR_RESEND 0xFE /* Keyboard needs resend of command */ Index: head/sys/i386/isa/kbdtables.h =================================================================== --- head/sys/i386/isa/kbdtables.h (revision 618) +++ head/sys/i386/isa/kbdtables.h (revision 619) @@ -1,856 +1,858 @@ /* * Copyright (C) 1992, 1993 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@kmd-ac.dk * Tritonvej 36 UUCP: ...uunet!dkuug!kmd-ac!sos * DK9210 Aalborg SO Phone: +45 9814 8076 + * + * $Id$ */ #define META 0x80 /* eight bit for emacs META-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, NOP, NOP, 0x1B, 0x1B, NOP, NOP, 0x33, 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 */ '*', '*', '*', '*', '*', '*', '*', '*', 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, '.', '.', '.', '.', '.', '.', '.', 0x00, 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 */ '*', '*', '*', '*', '*', '*', '*', '*', 0x00, 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), F(54), 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, 0x1B, 0x1B, 0x00, 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, 0x7F, 0x7F, 0x00, 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 */ '\\', '|', 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 */ '*', '*', '*', '*', '*', '*', '*', '*', 0x00, 0x02, /* 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), F(54), 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, 0x1B, 0x1B, 0x00, 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, 0x7F, 0x7F, 0x00, 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 */ '*', '*', '*', '*', '*', '*', '*', '*', 0x00, 0x02, /* 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), F(54), 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, 0x1B, 0x1B, 0x00, 0x00, /* sc=02 */ '1', '!', NOP, NOP, NOP, NOP, NOP, NOP, 0x3F, 0x00, /* sc=03 */ '2', '"', NOP, NOP, NOP, '@', NOP, NOP, 0x3B, 0x00, /* sc=04 */ '3', 0xA3, NOP, NOP, NOP, '#', NOP, NOP, 0x3B, 0x00, /* sc=05 */ '4', '$', NOP, NOP, NOP, NOP, NOP, NOP, 0x3F, 0x00, /* sc=06 */ '5', '%', NOP, NOP, NOP, NOP, NOP, NOP, 0x3F, 0x00, /* sc=07 */ '6', '&', 0x1E, NOP, NOP, '^', 0x1E, NOP, 0x19, 0x00, /* sc=08 */ '7', '/', NOP, NOP, NOP, '&', NOP, NOP, 0x3B, 0x00, /* sc=09 */ '8', '(', NOP, NOP, NOP, '*', NOP, NOP, 0x3B, 0x00, /* sc=0a */ '9', ')', NOP, NOP, NOP, '(', NOP, NOP, 0x3B, 0x00, /* sc=0b */ '0', '=', NOP, NOP, NOP, ')', NOP, NOP, 0x3B, 0x00, /* sc=0c */ '+', '?', 0x1F, 0x1F, '-', '_', 0x1F, 0x1F, 0x00, 0x00, /* sc=0d */ 0xB4, '`', 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 */ 0xE5, 0xC5, NOP, NOP, '[', '{', 0x1B, NOP, 0x31, 0x01, /* sc=1b */ 0xA8, '^', NOP, NOP, ']', '}', 0x1D, NOP, 0x31, 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 */ 0xF8, 0xD8, NOP, NOP, ';', ':', NOP, NOP, 0x33, 0x01, /* sc=28 */ 0xE6, 0xC6, NOP, NOP, '\'', '"', NOP, NOP, 0x33, 0x01, /* sc=29 */ '<', '>', NOP, NOP, '\\', '|', 0x1C, NOP, 0x31, 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, 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, 0x7F, 0x7F, 0x00, 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 */ '*', '*', '*', '*', '*', '*', '*', '*', 0x00, 0x02, /* 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), F(54), 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, META|0x1B, META|0x1B, NOP, NOP, 0x33, 0x00, /* sc=02 */ '1', '!', NOP, NOP, META|'1', META|'!', NOP, NOP, 0x33, 0x00, /* sc=03 */ '2', '@', 0x00, 0x00, META|'2', META|'@', META|0x00, META|0x00, 0x00, 0x00, /* sc=04 */ '3', '#', NOP, NOP, META|'3', META|'#', NOP, NOP, 0x33, 0x00, /* sc=05 */ '4', '$', NOP, NOP, META|'4', META|'$', NOP, NOP, 0x33, 0x00, /* sc=06 */ '5', '%', NOP, NOP, META|'5', META|'%', NOP, NOP, 0x33, 0x00, /* sc=07 */ '6', '^', 0x1E, 0x1E, META|'6', META|'^', META|0x1E, META|0x1E, 0x00, 0x00, /* sc=08 */ '7', '&', NOP, NOP, META|'7', META|'&', NOP, NOP, 0x33, 0x00, /* sc=09 */ '8', '*', NOP, NOP, META|'8', META|'*', NOP, NOP, 0x33, 0x00, /* sc=0a */ '9', '(', NOP, NOP, META|'9', META|'(', NOP, NOP, 0x33, 0x00, /* sc=0b */ '0', ')', NOP, NOP, META|'0', META|')', NOP, NOP, 0x33, 0x00, /* sc=0c */ '-', '_', 0x1F, 0x1F, META|'-', META|'_', META|0x1F, META|0x1F, 0x00, 0x00, /* sc=0d */ '=', '+', NOP, NOP, META|'=', META|'+', NOP, NOP, 0x33, 0x00, /* sc=0e */ 0x08, 0x08, 0x7F, 0x7F, META|0x08, META|0x08, META|0x7F, META|0x7F, 0x00, 0x00, /* sc=0f */ 0x09, F(16), NOP, NOP, META|0x09, F(16), NOP, NOP, 0x77, 0x00, /* sc=10 */ 'q', 'Q', 0x11, 0x11, META|'q', META|'Q', META|0x11, META|0x11, 0x00, 0x01, /* sc=11 */ 'w', 'W', 0x17, 0x17, META|'w', META|'W', META|0x17, META|0x17, 0x00, 0x01, /* sc=12 */ 'e', 'E', 0x05, 0x05, META|'e', META|'E', META|0x05, META|0x05, 0x00, 0x01, /* sc=13 */ 'r', 'R', 0x12, 0x12, META|'r', META|'R', META|0x12, META|0x12, 0x00, 0x01, /* sc=14 */ 't', 'T', 0x14, 0x14, META|'t', META|'T', META|0x14, META|0x14, 0x00, 0x01, /* sc=15 */ 'y', 'Y', 0x19, 0x19, META|'y', META|'Y', META|0x19, META|0x19, 0x00, 0x01, /* sc=16 */ 'u', 'U', 0x15, 0x15, META|'u', META|'U', META|0x15, META|0x15, 0x00, 0x01, /* sc=17 */ 'i', 'I', 0x09, 0x09, META|'i', META|'I', META|0x09, META|0x09, 0x00, 0x01, /* sc=18 */ 'o', 'O', 0x0F, 0x0F, META|'o', META|'O', META|0x0F, META|0x0F, 0x00, 0x01, /* sc=19 */ 'p', 'P', 0x10, 0x10, META|'p', META|'P', META|0x10, META|0x10, 0x00, 0x01, /* sc=1a */ '[', '{', 0x1B, 0x1B, META|'[', META|'{', META|0x1B, META|0x1B, 0x00, 0x00, /* sc=1b */ ']', '}', 0x1D, 0x1D, META|']', META|'}', META|0x1D, META|0x1D, 0x00, 0x00, /* sc=1c */ 0x0D, 0x0D, 0x0A, 0x0A, META|0x0D, META|0x0D, META|0x0A, META|0x0A, 0x00, 0x00, /* sc=1d */ LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, 0xFF, 0x00, /* sc=1e */ 'a', 'A', 0x01, 0x01, META|'a', META|'A', META|0x01, META|0x01, 0x00, 0x01, /* sc=1f */ 's', 'S', 0x13, 0x13, META|'s', META|'S', META|0x13, META|0x13, 0x00, 0x01, /* sc=20 */ 'd', 'D', 0x04, 0x04, META|'d', META|'D', META|0x04, META|0x04, 0x00, 0x01, /* sc=21 */ 'f', 'F', 0x06, 0x06, META|'f', META|'F', META|0x06, META|0x06, 0x00, 0x01, /* sc=22 */ 'g', 'G', 0x07, 0x07, META|'g', META|'G', META|0x07, META|0x07, 0x00, 0x01, /* sc=23 */ 'h', 'H', 0x08, 0x08, META|'h', META|'H', META|0x08, META|0x08, 0x00, 0x01, /* sc=24 */ 'j', 'J', 0x0A, 0x0A, META|'j', META|'J', META|0x0A, META|0x0A, 0x00, 0x01, /* sc=25 */ 'k', 'K', 0x0B, 0x0B, META|'k', META|'K', META|0x0B, META|0x0B, 0x00, 0x01, /* sc=26 */ 'l', 'L', 0x0C, 0x0C, META|'l', META|'L', META|0x0C, META|0x0C, 0x00, 0x01, /* sc=27 */ ';', ':', NOP, NOP, META|';', META|':', NOP, NOP, 0x33, 0x00, /* sc=28 */ '\'', '"', NOP, NOP, META|'\'', META|'"', NOP, NOP, 0x33, 0x00, /* sc=29 */ '`', '~', NOP, NOP, META|'`', META|'~', NOP, NOP, 0x33, 0x00, /* sc=2a */ LSH, LSH, LSH, LSH, LSH, LSH, LSH, LSH, 0xFF, 0x00, /* sc=2b */ '\\', '|', 0x1C, 0x1C, META|'\\', META|'|', META|0x1C, META|0x1C, 0x00, 0x00, /* sc=2c */ 'z', 'Z', 0x1A, 0x1A, META|'z', META|'Z', META|0x1A, META|0x1A, 0x00, 0x01, /* sc=2d */ 'x', 'X', 0x18, 0x18, META|'x', META|'X', META|0x18, META|0x18, 0x00, 0x01, /* sc=2e */ 'c', 'C', 0x03, 0x03, META|'c', META|'C', META|0x03, META|0x03, 0x00, 0x01, /* sc=2f */ 'v', 'V', 0x16, 0x16, META|'v', META|'V', META|0x16, META|0x16, 0x00, 0x01, /* sc=30 */ 'b', 'B', 0x02, 0x02, META|'b', META|'B', META|0x02, META|0x02, 0x00, 0x01, /* sc=31 */ 'n', 'N', 0x0E, 0x0E, META|'n', META|'N', META|0x0E, META|0x0E, 0x00, 0x01, /* sc=32 */ 'm', 'M', 0x0D, 0x0D, META|'m', META|'M', META|0x0D, META|0x0D, 0x00, 0x01, /* sc=33 */ ',', '<', NOP, NOP, META|',', META|'<', NOP, NOP, 0x33, 0x00, /* sc=34 */ '.', '>', NOP, NOP, META|'.', META|'>', NOP, NOP, 0x33, 0x00, /* sc=35 */ '/', '?', NOP, NOP, META|'/', META|'?', NOP, NOP, 0x33, 0x00, /* sc=36 */ ASH, RSH, RSH, RSH, RSH, RSH, RSH, RSH, 0xFF, 0x00, /* sc=37 */ '*', '*', 0x0A, 0x0A, META|'*', META|'*', META|0x0A, META|0x0A, 0x00, 0x00, /* sc=38 */ LALT, LALT, LALT, LALT, LALT, LALT, LALT, LALT, 0xFF, 0x00, /* sc=39 */ ' ', ' ', ' ', ' ', META|' ', META|' ', META|' ', META|' ', 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', META|'7', META|'7', META|'7', META|'7', 0x80, 0x02, /* sc=48 */ F(50), '8', '8', '8', META|'8', META|'8', META|'8', META|'8', 0x80, 0x02, /* sc=49 */ F(51), '9', '9', '9', META|'9', META|'9', META|'9', META|'9', 0x80, 0x02, /* sc=4a */ F(52), '-', '-', '-', META|'-', META|'-', META|'-', META|'-', 0x80, 0x02, /* sc=4b */ F(53), '4', '4', '4', META|'4', META|'4', META|'4', META|'4', 0x80, 0x02, /* sc=4c */ F(48), '5', '5', '5', META|'5', META|'5', META|'5', META|'5', 0x80, 0x02, /* sc=4d */ F(55), '6', '6', '6', META|'6', META|'6', META|'6', META|'6', 0x80, 0x02, /* sc=4e */ F(56), '+', '+', '+', META|'+', META|'+', META|'+', META|'+', 0x80, 0x02, /* sc=4f */ F(57), '1', '1', '1', META|'1', META|'1', META|'1', META|'1', 0x80, 0x02, /* sc=50 */ F(58), '2', '2', '2', META|'2', META|'2', META|'2', META|'2', 0x80, 0x02, /* sc=51 */ F(59), '3', '3', '3', META|'3', META|'3', META|'3', META|'3', 0x80, 0x02, /* sc=52 */ F(60), '0', '0', '0', META|'0', META|'0', META|'0', META|'0', 0x80, 0x02, /* sc=53 */ F(54), '.', 0x7F, 0x7F, META|0x7F, META|0x7F, META|0x7F, META|0x7F, 0x80, 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, META|0x0D, META|0x0D, META|0x0A, META|0x0A, 0x00, 0x00, /* sc=5a */ RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, 0xFF, 0x00, /* sc=5b */ '/', '/', NOP, NOP, META|'/', META|'/', NOP, NOP, 0x33, 0x00, /* sc=5c */ CLK, ALK, ALK, ALK, ALK, ALK, ALK, ALK, 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, META|0x7F, META|0x7F, META|0x7F, META|0x7F, 0xC0, 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, META|0x1B, META|0x1B, NOP, NOP, 0x33, 0x00, /* sc=02 */ '!', '1', NOP, NOP, META|'1', META|'!', NOP, NOP, 0x33, 0x00, /* sc=03 */ '"', '2', 0x00, 0x00, META|'2', META|'@', META|0x00, META|0x00, 0x00, 0x00, /* sc=04 */ '\'', '3', NOP, NOP, META|'3', META|'#', NOP, NOP, 0x33, 0x00, /* sc=05 */ ';', '4', NOP, NOP, META|'4', META|'$', NOP, NOP, 0x33, 0x00, /* sc=06 */ ':', '5', NOP, NOP, META|'5', META|'%', NOP, NOP, 0x33, 0x00, /* sc=07 */ ',', '6', 0x1E, 0x1E, META|'6', META|'^', META|0x1E, META|0x1E, 0x00, 0x00, /* sc=08 */ '.', '7', NOP, NOP, META|'7', META|'&', NOP, NOP, 0x33, 0x00, /* sc=09 */ '*', '8', NOP, NOP, META|'8', META|'*', NOP, NOP, 0x33, 0x00, /* sc=0a */ '(', '9', NOP, NOP, META|'9', META|'(', NOP, NOP, 0x33, 0x00, /* sc=0b */ ')', '0', NOP, NOP, META|'0', META|')', NOP, NOP, 0x33, 0x00, /* sc=0c */ '_', '-', 0x1F, 0x1F, META|'-', META|'_', META|0x1F, META|0x1F, 0x00, 0x00, /* sc=0d */ '+', '=', NOP, NOP, META|'=', META|'+', NOP, NOP, 0x33, 0x00, /* sc=0e */ 0x08, 0x08, 0x7F, 0x7F, META|0x08, META|0x08, META|0x7F, META|0x7F, 0x00, 0x00, /* sc=0f */ 0x09, F(16), NOP, NOP, META|0x09, F(16), NOP, NOP, 0x77, 0x00, /* sc=10 */ 0xca, 0xea, 0x11, 0x11, META|'q', META|'Q', META|0x11, META|0x11, 0x00, 0x01, /* sc=11 */ 0xc3, 0xe3, 0x17, 0x17, META|'w', META|'W', META|0x17, META|0x17, 0x00, 0x01, /* sc=12 */ 0xd5, 0xf5, 0x05, 0x05, META|'e', META|'E', META|0x05, META|0x05, 0x00, 0x01, /* sc=13 */ 0xcb, 0xeb, 0x12, 0x12, META|'r', META|'R', META|0x12, META|0x12, 0x00, 0x01, /* sc=14 */ 0xc5, 0xe5, 0x14, 0x14, META|'t', META|'T', META|0x14, META|0x14, 0x00, 0x01, /* sc=15 */ 0xce, 0xee, 0x19, 0x19, META|'y', META|'Y', META|0x19, META|0x19, 0x00, 0x01, /* sc=16 */ 0xc7, 0xe7, 0x15, 0x15, META|'u', META|'U', META|0x15, META|0x15, 0x00, 0x01, /* sc=17 */ 0xdb, 0xfb, 0x09, 0x09, META|'i', META|'I', META|0x09, META|0x09, 0x00, 0x01, /* sc=18 */ 0xdd, 0xfd, 0x0F, 0x0F, META|'o', META|'O', META|0x0F, META|0x0F, 0x00, 0x01, /* sc=19 */ 0xda, 0xfa, 0x10, 0x10, META|'p', META|'P', META|0x10, META|0x10, 0x00, 0x01, /* sc=1a */ 0xc8, 0xe8, 0x1B, 0x1B, META|'[', META|'{', META|0x1B, META|0x1B, 0x00, 0x01, /* sc=1b */ 0xdf, 0xff, 0x1D, 0x1D, META|']', META|'}', META|0x1D, META|0x1D, 0x00, 0x01, /* sc=1c */ 0x0D, 0x0D, 0x0A, 0x0A, META|0x0D, META|0x0D, META|0x0A, META|0x0A, 0x00, 0x00, /* sc=1d */ LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, 0xFF, 0x00, /* sc=1e */ 0xc6, 0xe6, 0x01, 0x01, META|'a', META|'A', META|0x01, META|0x01, 0x00, 0x01, /* sc=1f */ 0xd9, 0xf9, 0x13, 0x13, META|'s', META|'S', META|0x13, META|0x13, 0x00, 0x01, /* sc=20 */ 0xd7, 0xf7, 0x04, 0x04, META|'d', META|'D', META|0x04, META|0x04, 0x00, 0x01, /* sc=21 */ 0xc1, 0xe1, 0x06, 0x06, META|'f', META|'F', META|0x06, META|0x06, 0x00, 0x01, /* sc=22 */ 0xd0, 0xf0, 0x07, 0x07, META|'g', META|'G', META|0x07, META|0x07, 0x00, 0x01, /* sc=23 */ 0xd2, 0xf2, 0x08, 0x08, META|'h', META|'H', META|0x08, META|0x08, 0x00, 0x01, /* sc=24 */ 0xcf, 0xef, 0x0A, 0x0A, META|'j', META|'J', META|0x0A, META|0x0A, 0x00, 0x01, /* sc=25 */ 0xcc, 0xec, 0x0B, 0x0B, META|'k', META|'K', META|0x0B, META|0x0B, 0x00, 0x01, /* sc=26 */ 0xc4, 0xe4, 0x0C, 0x0C, META|'l', META|'L', META|0x0C, META|0x0C, 0x00, 0x01, /* sc=27 */ 0xd6, 0xf6, NOP, NOP, META|';', META|':', NOP, NOP, 0x33, 0x01, /* sc=28 */ 0xdc, 0xfc, NOP, NOP, META|'\'', META|'"', NOP, NOP, 0x33, 0x01, /* sc=29 */ 0xa3, 0xb3, NOP, NOP, META|'`', META|'~', NOP, NOP, 0x33, 0x01, /* sc=2a */ LSH, LSH, LSH, LSH, LSH, LSH, LSH, LSH, 0xFF, 0x00, /* sc=2b */ '\\', '|', 0x1C, 0x1C, META|'\\', META|'|', META|0x1C, META|0x1C, 0x00, 0x00, /* sc=2c */ 0xd1, 0xf1, 0x1A, 0x1A, META|'z', META|'Z', META|0x1A, META|0x1A, 0x00, 0x01, /* sc=2d */ 0xde, 0xfe, 0x18, 0x18, META|'x', META|'X', META|0x18, META|0x18, 0x00, 0x01, /* sc=2e */ 0xd3, 0xf3, 0x03, 0x03, META|'c', META|'C', META|0x03, META|0x03, 0x00, 0x01, /* sc=2f */ 0xcd, 0xed, 0x16, 0x16, META|'v', META|'V', META|0x16, META|0x16, 0x00, 0x01, /* sc=30 */ 0xc9, 0xe9, 0x02, 0x02, META|'b', META|'B', META|0x02, META|0x02, 0x00, 0x01, /* sc=31 */ 0xd4, 0xf4, 0x0E, 0x0E, META|'n', META|'N', META|0x0E, META|0x0E, 0x00, 0x01, /* sc=32 */ 0xd8, 0xf8, 0x0D, 0x0D, META|'m', META|'M', META|0x0D, META|0x0D, 0x00, 0x01, /* sc=33 */ 0xc2, 0xe2, NOP, NOP, META|',', META|'<', NOP, NOP, 0x33, 0x01, /* sc=34 */ 0xc0, 0xe0, NOP, NOP, META|'.', META|'>', NOP, NOP, 0x33, 0x01, /* sc=35 */ '/', '?', NOP, NOP, META|'/', META|'?', NOP, NOP, 0x33, 0x00, /* sc=36 */ ASH, RSH, RSH, RSH, RSH, RSH, RSH, RSH, 0xFF, 0x00, /* sc=37 */ '*', '*', 0x0A, 0x0A, META|'*', META|'*', META|0x0A, META|0x0A, 0x00, 0x00, /* sc=38 */ LALT, LALT, LALT, LALT, LALT, LALT, LALT, LALT, 0xFF, 0x00, /* sc=39 */ ' ', ' ', ' ', ' ', META|' ', META|' ', META|' ', META|' ', 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', META|'7', META|'7', META|'7', META|'7', 0x80, 0x02, /* sc=48 */ F(50), '8', '8', '8', META|'8', META|'8', META|'8', META|'8', 0x80, 0x02, /* sc=49 */ F(51), '9', '9', '9', META|'9', META|'9', META|'9', META|'9', 0x80, 0x02, /* sc=4a */ F(52), '-', '-', '-', META|'-', META|'-', META|'-', META|'-', 0x80, 0x02, /* sc=4b */ F(53), '4', '4', '4', META|'4', META|'4', META|'4', META|'4', 0x80, 0x02, /* sc=4c */ F(48), '5', '5', '5', META|'5', META|'5', META|'5', META|'5', 0x80, 0x02, /* sc=4d */ F(55), '6', '6', '6', META|'6', META|'6', META|'6', META|'6', 0x80, 0x02, /* sc=4e */ F(56), '+', '+', '+', META|'+', META|'+', META|'+', META|'+', 0x80, 0x02, /* sc=4f */ F(57), '1', '1', '1', META|'1', META|'1', META|'1', META|'1', 0x80, 0x02, /* sc=50 */ F(58), '2', '2', '2', META|'2', META|'2', META|'2', META|'2', 0x80, 0x02, /* sc=51 */ F(59), '3', '3', '3', META|'3', META|'3', META|'3', META|'3', 0x80, 0x02, /* sc=52 */ F(60), '0', '0', '0', META|'0', META|'0', META|'0', META|'0', 0x80, 0x02, /* sc=53 */ F(54), '.', 0x7F, 0x7F, META|0x7F, META|0x7F, META|0x7F, META|0x7F, 0x80, 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, META|0x0D, META|0x0D, META|0x0A, META|0x0A, 0x00, 0x00, /* sc=5a */ RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, 0xFF, 0x00, /* sc=5b */ '/', '/', NOP, NOP, META|'/', META|'/', NOP, NOP, 0x33, 0x00, /* sc=5c */ CLK, ALK, ALK, ALK, ALK, ALK, ALK, ALK, 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, META|0x7F, META|0x7F, META|0x7F, META|0x7F, 0xC0, 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, NOP, NOP, 0x1B, 0x1B, NOP, NOP, 0x33, 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, 0x7F, 0x7F, 0x00, 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 */ '*', '*', '*', '*', '*', '*', '*', '*', 0x00, 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), F(54), 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} }; Index: head/sys/i386/isa/lpt.c =================================================================== --- head/sys/i386/isa/lpt.c (revision 618) +++ head/sys/i386/isa/lpt.c (revision 619) @@ -1,477 +1,463 @@ /* * Copyright (c) 1990 William F. Jolitz, TeleMuse * 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 software is a component of "386BSD" developed by * William F. Jolitz, TeleMuse. * 4. Neither the name of the developer nor the name "386BSD" * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS A COMPONENT OF 386BSD DEVELOPED BY WILLIAM F. JOLITZ * AND IS INTENDED FOR RESEARCH AND EDUCATIONAL PURPOSES ONLY. THIS * SOFTWARE SHOULD NOT BE CONSIDERED TO BE A COMMERCIAL PRODUCT. * THE DEVELOPER URGES THAT USERS WHO REQUIRE A COMMERCIAL PRODUCT * NOT MAKE USE OF THIS WORK. * * FOR USERS WHO WISH TO UNDERSTAND THE 386BSD SYSTEM DEVELOPED * BY WILLIAM F. JOLITZ, WE RECOMMEND THE USER STUDY WRITTEN * REFERENCES SUCH AS THE "PORTING UNIX TO THE 386" SERIES * (BEGINNING JANUARY 1991 "DR. DOBBS JOURNAL", USA AND BEGINNING * JUNE 1991 "UNIX MAGAZIN", GERMANY) BY WILLIAM F. JOLITZ AND * LYNNE GREER JOLITZ, AS WELL AS OTHER BOOKS ON UNIX AND THE * ON-LINE 386BSD USER MANUAL BEFORE USE. A BOOK DISCUSSING THE INTERNALS * OF 386BSD ENTITLED "386BSD FROM THE INSIDE OUT" WILL BE AVAILABLE LATE 1992. * * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``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 DEVELOPER 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. * - * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE - * -------------------- ----- ---------------------- - * CURRENT PATCH LEVEL: 2 00164 - * -------------------- ----- ---------------------- - * - * 06 Apr 93 Eric Haug Fixed comments and includes. [Ed: I did - * not include the unit-1 thing, that is a - * DOSism, fixed the config file instead] - * 06 Apr 93 Rodney W. Grimes A real probe routine, may even cause on - * interrupt if a printer is attached. - * - * 01 Jun 93 Rodney W. Grimes Made lpflag uniq now is lptflag - * Added timeout loop to lpt_port_test. - * lpt_port_test should move to a common - * routine.. - * + * from: unknown origin, 386BSD 0.1 + * $Id$ */ /* * Device Driver for AT parallel printer port * Written by William Jolitz 12/18/90 */ #include "lpt.h" #if NLPT > 0 #include "param.h" #include "systm.h" #include "proc.h" #include "user.h" #include "buf.h" #include "kernel.h" #include "ioctl.h" #include "tty.h" #include "uio.h" #include "i386/isa/isa.h" #include "i386/isa/isa_device.h" #include "i386/isa/lptreg.h" #define LPINITRDY 4 /* wait up to 4 seconds for a ready */ #define LPTOUTTIME 4 /* wait up to 4 seconds for a ready */ #define LPPRI (PZERO+8) #define BUFSIZE 1024 #ifndef DEBUG #define lprintf #else #define lprintf if (lptflag) printf int lptflag = 1; #endif void lptout(); #ifdef DEBUG int lptflag = 1; #endif int lptprobe(), lptattach(); void lptintr(); struct isa_driver lptdriver = { lptprobe, lptattach, "lpt" }; #define LPTUNIT(s) (((s)>>6)&0x3) #define LPTFLAGS(s) ((s)&0x3f) struct lpt_softc { short sc_port; short sc_state; /* default case: negative prime, negative ack, handshake strobe, prime once */ u_char sc_control; char sc_flags; #define LP_POS_INIT 0x01 /* if we are a postive init signal */ #define LP_POS_ACK 0x02 /* if we are a positive going ack */ #define LP_NO_PRIME 0x04 /* don't prime the printer at all */ #define LP_PRIMEOPEN 0x08 /* prime on every open */ #define LP_AUTOLF 0x10 /* tell printer to do an automatic lf */ #define LP_BYPASS 0x20 /* bypass printer ready checks */ struct buf *sc_inbuf; short sc_xfercnt ; char sc_primed; char *sc_cp ; } lpt_sc[NLPT] ; /* bits for state */ #define OPEN (1<<0) /* device is open */ #define ASLP (1<<1) /* awaiting draining of printer */ #define ERROR (1<<2) /* error was received from printer */ #define OBUSY (1<<3) /* printer is busy doing output */ #define LPTOUT (1<<4) /* timeout while not selected */ #define TOUT (1<<5) /* timeout while not selected */ #define INIT (1<<6) /* waiting to initialize for open */ /* * Internal routine to lptprobe to do port tests of one byte value */ int lpt_port_test(port, data, mask) short port; u_char data; u_char mask; { int temp, timeout; data = data & mask; outb(port, data); timeout = 100; do temp = inb(port) & mask; while (temp != data && --timeout); lprintf("Port 0x%x\tout=%x\tin=%x\n", port, data, temp); return (temp == data); } /* * New lptprobe routine written by Rodney W. Grimes, 3/25/1993 * * Logic: * 1) You should be able to write to and read back the same value * to the data port. Do an alternating zeros, alternating ones, * walking zero, and walking one test to check for stuck bits. * * 2) You should be able to write to and read back the same value * to the control port lower 5 bits, the upper 3 bits are reserved * per the IBM PC technical reference manauls and different boards * do different things with them. Do an alternating zeros, alternating * ones, walking zero, and walking one test to check for stuck bits. * * Some printers drag the strobe line down when the are powered off * so this bit has been masked out of the control port test. * * XXX Some printers may not like a fast pulse on init or strobe, I * don't know at this point, if that becomes a problem these bits * should be turned off in the mask byte for the control port test. * * 3) Set the data and control ports to a value of 0 */ int lptprobe(dvp) struct isa_device *dvp; { int status; short port; u_char data; u_char mask; int i; status = IO_LPTSIZE; port = dvp->id_iobase + lpt_data; mask = 0xff; while (mask != 0) { data = 0x55; /* Alternating zeros */ if (!lpt_port_test(port, data, mask)) status = 0; data = 0xaa; /* Alternating ones */ if (!lpt_port_test(port, data, mask)) status = 0; for (i = 0; i < 8; i++) /* Walking zero */ { data = ~(1 << i); if (!lpt_port_test(port, data, mask)) status = 0; } for (i = 0; i < 8; i++) /* Walking one */ { data = (1 << i); if (!lpt_port_test(port, data, mask)) status = 0; } if (port == dvp->id_iobase + lpt_data) { port = dvp->id_iobase + lpt_control; mask = 0x1e; } else mask = 0; } outb(dvp->id_iobase+lpt_data, 0); outb(dvp->id_iobase+lpt_control, 0); return (status); } int lptattach(isdp) struct isa_device *isdp; { struct lpt_softc *sc; sc = lpt_sc + isdp->id_unit; sc->sc_port = isdp->id_iobase; outb(sc->sc_port+lpt_control, LPC_NINIT); return (1); } /* * lptopen -- reset the printer, then wait until it's selected and not busy. */ int lptopen(dev, flag) dev_t dev; int flag; { struct lpt_softc *sc; int s; int trys, port; u_int unit = LPTUNIT(minor(dev)); if (unit >= NLPT) return (ENXIO); sc = lpt_sc + unit; if (sc->sc_state) { lprintf("lp: still open\n") ; lprintf("still open %x\n", sc->sc_state); return(EBUSY); } else sc->sc_state |= INIT; s = spltty(); sc->sc_flags = LPTFLAGS(minor(dev)); lprintf("lp flags 0x%x\n", sc->sc_flags); port = sc->sc_port; /* init printer */ if((sc->sc_flags & LP_NO_PRIME) == 0) { if((sc->sc_flags & LP_PRIMEOPEN) || sc->sc_primed == 0) { outb(port+lpt_control, 0); sc->sc_primed++; DELAY(500); } } outb(port+lpt_control, LPC_SEL|LPC_NINIT); /* wait till ready (printer running diagnostics) */ trys = 0; do { /* ran out of waiting for the printer */ if (trys++ >= LPINITRDY*4) { splx(s); sc->sc_state = 0; lprintf ("status %x\n", inb(port+lpt_status) ); return (EBUSY); } /* wait 1/4 second, give up if we get a signal */ if (tsleep (sc, LPPRI|PCATCH, "lptinit", hz/4) != EWOULDBLOCK) { sc->sc_state = 0; splx(s); return (EBUSY); } /* is printer online and ready for output */ } while ((inb(port+lpt_status) & (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR)) != (LPS_SEL|LPS_NBSY|LPS_NERR)); if(sc->sc_flags&LP_AUTOLF) { outb(port+lpt_control, LPC_SEL|LPC_NINIT|LPC_ENA|LPC_AUTOL); sc->sc_control = LPC_SEL|LPC_NINIT|LPC_ENA|LPC_AUTOL; } else { outb(port+lpt_control, LPC_SEL|LPC_NINIT|LPC_ENA); sc->sc_control = LPC_SEL|LPC_NINIT|LPC_ENA; } sc->sc_state = OPEN | TOUT; sc->sc_inbuf = geteblk(BUFSIZE); sc->sc_xfercnt = 0; splx(s); timeout (lptout, sc, hz/2); lprintf("opened.\n"); return(0); } void lptout (sc) struct lpt_softc *sc; { int pl; lprintf ("T %x ", inb(sc->sc_port+lpt_status)); if (sc->sc_state&OPEN) timeout (lptout, sc, hz/2); else sc->sc_state &= ~TOUT; if (sc->sc_state & ERROR) sc->sc_state &= ~ERROR; /* * Avoid possible hangs do to missed interrupts */ if (sc->sc_xfercnt) { pl = spltty(); lptintr(sc - lpt_sc); splx(pl); } else { sc->sc_state &= ~OBUSY; wakeup((caddr_t)sc); } } /* * lptclose -- close the device, free the local line buffer. */ int lptclose(dev, flag) dev_t dev; int flag; { struct lpt_softc *sc = lpt_sc + LPTUNIT(minor(dev)); int port = sc->sc_port; sc->sc_state &= ~OPEN; while ((inb(port+lpt_status) & (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR)) != (LPS_SEL|LPS_NBSY|LPS_NERR) || sc->sc_xfercnt) /* wait 1/4 second, give up if we get a signal */ if (tsleep (sc, LPPRI|PCATCH, "lpclose", hz) != EWOULDBLOCK) break; sc->sc_state = 0; sc->sc_xfercnt = 0; outb(sc->sc_port+lpt_control, LPC_NINIT); brelse(sc->sc_inbuf); lprintf("closed.\n"); return(0); } /* * lptwrite --copy a line from user space to a local buffer, then call * putc to get the chars moved to the output queue. */ int lptwrite(dev, uio) dev_t dev; struct uio *uio; { register unsigned n; int pl, err; struct lpt_softc *sc = lpt_sc + LPTUNIT(minor(dev)); while (n = MIN(BUFSIZE, uio->uio_resid)) { sc->sc_cp = sc->sc_inbuf->b_un.b_addr ; uiomove(sc->sc_cp, n, uio); sc->sc_xfercnt = n ; while (sc->sc_xfercnt > 0) { /* if the printer is ready for a char, give it one */ if ((sc->sc_state & OBUSY) == 0){ lprintf("\nC %d. ", sc->sc_xfercnt); pl = spltty(); lptintr(sc - lpt_sc); (void) splx(pl); } lprintf("W "); if (err = tsleep (sc, LPPRI|PCATCH, "lpwrite", 0)) return(err); } } return(0); } /* * lptintr -- handle printer interrupts which occur when the printer is * ready to accept another char. */ void lptintr(unit) int unit; { struct lpt_softc *sc = lpt_sc + unit; int port = sc->sc_port,sts; /* is printer online and ready for output */ if (((sts=inb(port+lpt_status)) & (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR/*|LPS_NACK*/)) == (LPS_SEL|LPS_NBSY|LPS_NERR)) { /* is this a false interrupt ? */ if ((sc->sc_state & OBUSY) && (sts & LPS_NACK) == 0) return; sc->sc_state |= OBUSY; sc->sc_state &= ~ERROR; if (sc->sc_xfercnt) { /* send char */ /*lprintf("%x ", *sc->sc_cp); */ outb(port+lpt_data, *sc->sc_cp++) ; sc->sc_xfercnt-- ; outb(port+lpt_control, sc->sc_control|LPC_STB); /* DELAY(X) */ outb(port+lpt_control, sc->sc_control); } /* any more bytes for the printer? */ if (sc->sc_xfercnt > 0) return; /* none, wake up the top half to get more */ sc->sc_state &= ~OBUSY; wakeup((caddr_t)sc); lprintf("w "); return; } else sc->sc_state |= ERROR; lprintf("sts %x ", sts); } int lptioctl(dev, cmd, data, flag) dev_t dev; int cmd; caddr_t data; int flag; { int error; error = 0; switch (cmd) { #ifdef THISISASAMPLE case XXX: dothis; andthis; andthat; error=x; break; #endif /* THISISASAMPLE */ default: error = ENODEV; } return(error); } #endif /* NLPT */ Index: head/sys/i386/isa/lptreg.h =================================================================== --- head/sys/i386/isa/lptreg.h (revision 618) +++ head/sys/i386/isa/lptreg.h (revision 619) @@ -1,34 +1,33 @@ /*- * 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. * - * %sccs.include.noredist.c% - * - * @(#)lptreg.h 1.1 (Berkeley) 12/19/90 + * form: @(#)lptreg.h 1.1 (Berkeley) 12/19/90 + * $Id$ */ /* * AT Parallel Port (for lineprinter) * Interface port and bit definitions * Written by William Jolitz 12/18/90 * Copyright (C) William Jolitz 1990 */ #define lpt_data 0 /* Data to/from printer (R/W) */ #define lpt_status 1 /* Status of printer (R) */ #define LPS_NERR 0x08 /* printer no error */ #define LPS_SEL 0x10 /* printer selected */ #define LPS_OUT 0x20 /* printer out of paper */ #define LPS_NACK 0x40 /* printer no ack of data */ #define LPS_NBSY 0x80 /* printer no ack of data */ #define lpt_control 2 /* Control printer (R/W) */ #define LPC_STB 0x01 /* strobe data to printer */ #define LPC_AUTOL 0x02 /* automatic linefeed */ #define LPC_NINIT 0x04 /* initialize printer */ #define LPC_SEL 0x08 /* printer selected */ #define LPC_ENA 0x10 /* printer out of paper */ Index: head/sys/i386/isa/mcd.c =================================================================== --- head/sys/i386/isa/mcd.c (revision 618) +++ head/sys/i386/isa/mcd.c (revision 619) @@ -1,1261 +1,1260 @@ /* * Copyright 1993 by Holger Veit (data part) * Copyright 1993 by Brian Moore (audio part) * 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 software was developed by Holger Veit and Brian Moore * for use with "386BSD" and similar operating systems. * "Similar operating systems" includes mainly non-profit oriented * systems for research and education, including but not restricted to * "NetBSD", "FreeBSD", "Mach" (by CMU). * 4. Neither the name of the developer(s) nor the name "386BSD" * may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER(S) ``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 DEVELOPER(S) 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$ + * $Id: mcd.c,v 1.1 1993/10/12 06:08:29 rgrimes Exp $ */ -/*static char rcsid[] = "from: /sys/i386/isa/RCS/mcd.c,v 2.1 1993/09/24 21:23:13 root Exp root";*/ static char COPYRIGHT[] = "mcd-driver (C)1993 by H.Veit & B.Moore"; #include "mcd.h" #if NMCD > 0 #include "types.h" #include "param.h" #include "systm.h" #include "conf.h" #include "file.h" #include "buf.h" #include "stat.h" #include "uio.h" #include "ioctl.h" #include "cdio.h" #include "errno.h" #include "dkbad.h" #include "disklabel.h" #include "i386/isa/isa.h" #include "i386/isa/isa_device.h" #include "mcdreg.h" /* user definable options */ /*#define MCD_TO_WARNING_ON*/ /* define to get timeout messages */ /*#define MCDMINI*/ /* define for a mini configuration for boot kernel */ #ifdef MCDMINI #define MCD_TRACE(fmt,a,b,c,d) #ifdef MCD_TO_WARNING_ON #undef MCD_TO_WARNING_ON #endif #else #define MCD_TRACE(fmt,a,b,c,d) {if (mcd_data[unit].debug) {printf("mcd%d st=%02x: ",unit,mcd_data[unit].status); printf(fmt,a,b,c,d);}} #endif #define mcd_part(dev) ((minor(dev)) & 7) #define mcd_unit(dev) (((minor(dev)) & 0x38) >> 3) #define mcd_phys(dev) (((minor(dev)) & 0x40) >> 6) #define RAW_PART 3 /* flags */ #define MCDOPEN 0x0001 /* device opened */ #define MCDVALID 0x0002 /* parameters loaded */ #define MCDINIT 0x0004 /* device is init'd */ #define MCDWAIT 0x0008 /* waiting for something */ #define MCDLABEL 0x0010 /* label is read */ #define MCDPROBING 0x0020 /* probing */ #define MCDREADRAW 0x0040 /* read raw mode (2352 bytes) */ #define MCDVOLINFO 0x0080 /* already read volinfo */ #define MCDTOC 0x0100 /* already read toc */ #define MCDMBXBSY 0x0200 /* local mbx is busy */ /* status */ #define MCDAUDIOBSY MCD_ST_AUDIOBSY /* playing audio */ #define MCDDSKCHNG MCD_ST_DSKCHNG /* sensed change of disk */ #define MCDDSKIN MCD_ST_DSKIN /* sensed disk in drive */ #define MCDDOOROPEN MCD_ST_DOOROPEN /* sensed door open */ /* toc */ #define MCD_MAXTOCS 104 /* from the Linux driver */ #define MCD_LASTPLUS1 170 /* special toc entry */ struct mcd_mbx { short unit; short port; short retry; short nblk; int sz; u_long skip; struct buf *bp; int p_offset; short count; }; struct mcd_data { short config; short flags; short status; int blksize; u_long disksize; int iobase; struct disklabel dlabel; int partflags[MAXPARTITIONS]; int openflags; struct mcd_volinfo volinfo; #ifndef MCDMINI struct mcd_qchninfo toc[MCD_MAXTOCS]; short audio_status; struct mcd_read2 lastpb; #endif short debug; struct buf head; /* head of buf queue */ struct mcd_mbx mbx; } mcd_data[NMCD]; /* reader state machine */ #define MCD_S_BEGIN 0 #define MCD_S_BEGIN1 1 #define MCD_S_WAITSTAT 2 #define MCD_S_WAITMODE 3 #define MCD_S_WAITREAD 4 /* prototypes */ int mcdopen(dev_t dev); int mcdclose(dev_t dev); int mcdstrategy(struct buf *bp); int mcdioctl(dev_t dev, int cmd, caddr_t addr, int flags); int mcdsize(dev_t dev); static void mcd_done(struct mcd_mbx *mbx); static void mcd_start(int unit); static int mcd_getdisklabel(int unit); static void mcd_configure(struct mcd_data *cd); static int mcd_get(int unit, char *buf, int nmax); static void mcd_setflags(int unit,struct mcd_data *cd); static int mcd_getstat(int unit,int sflg); static int mcd_send(int unit, int cmd,int nretrys); static int bcd2bin(bcd_t b); static bcd_t bin2bcd(int b); static void hsg2msf(int hsg, bcd_t *msf); static int msf2hsg(bcd_t *msf); static int mcd_volinfo(int unit); static int mcd_waitrdy(int port,int dly); static void mcd_doread(int state, struct mcd_mbx *mbxin); #ifndef MCDMINI static int mcd_setmode(int unit, int mode); static int mcd_getqchan(int unit, struct mcd_qchninfo *q); static int mcd_subchan(int unit, struct ioc_read_subchannel *sc); static int mcd_toc_header(int unit, struct ioc_toc_header *th); static int mcd_read_toc(int unit); static int mcd_toc_entry(int unit, struct ioc_read_toc_entry *te); static int mcd_stop(int unit); static int mcd_playtracks(int unit, struct ioc_play_track *pt); static int mcd_play(int unit, struct mcd_read2 *pb); static int mcd_pause(int unit); static int mcd_resume(int unit); #endif extern int hz; extern int mcd_probe(struct isa_device *dev); extern int mcd_attach(struct isa_device *dev); struct isa_driver mcddriver = { mcd_probe, mcd_attach, "mcd" }; #define mcd_put(port,byte) outb(port,byte) #define MCD_RETRYS 5 #define MCD_RDRETRYS 8 #define MCDBLK 2048 /* for cooked mode */ #define MCDRBLK 2352 /* for raw mode */ /* several delays */ #define RDELAY_WAITSTAT 300 #define RDELAY_WAITMODE 300 #define RDELAY_WAITREAD 800 #define DELAY_STATUS 10000l /* 10000 * 1us */ #define DELAY_GETREPLY 200000l /* 200000 * 2us */ #define DELAY_SEEKREAD 20000l /* 20000 * 1us */ #define mcd_delay DELAY int mcd_attach(struct isa_device *dev) { struct mcd_data *cd = mcd_data + dev->id_unit; int i; cd->iobase = dev->id_iobase; cd->flags |= MCDINIT; cd->openflags = 0; for (i=0; ipartflags[i] = 0; #ifdef NOTYET /* wire controller for interrupts and dma */ mcd_configure(cd); #endif return 1; } int mcdopen(dev_t dev) { int unit,part,phys; struct mcd_data *cd; unit = mcd_unit(dev); if (unit >= NMCD) return ENXIO; cd = mcd_data + unit; part = mcd_part(dev); phys = mcd_phys(dev); /* not initialized*/ if (!(cd->flags & MCDINIT)) return ENXIO; /* invalidated in the meantime? mark all open part's invalid */ if (!(cd->flags & MCDVALID) && cd->openflags) return ENXIO; if (mcd_getstat(unit,1) < 0) return ENXIO; /* XXX get a default disklabel */ mcd_getdisklabel(unit); if (mcdsize(dev) < 0) { printf("mcd%d: failed to get disk size\n",unit); return ENXIO; } else cd->flags |= MCDVALID; MCD_TRACE("open: partition=%d, disksize = %d, blksize=%d\n", part,cd->disksize,cd->blksize,0); if (part == RAW_PART || (part < cd->dlabel.d_npartitions && cd->dlabel.d_partitions[part].p_fstype != FS_UNUSED)) { cd->partflags[part] |= MCDOPEN; cd->openflags |= (1<partflags[part] |= MCDREADRAW; return 0; } return ENXIO; } int mcdclose(dev_t dev) { int unit,part,phys; struct mcd_data *cd; unit = mcd_unit(dev); if (unit >= NMCD) return ENXIO; cd = mcd_data + unit; part = mcd_part(dev); phys = mcd_phys(dev); if (!(cd->flags & MCDINIT)) return ENXIO; mcd_getstat(unit,1); /* get status */ /* close channel */ cd->partflags[part] &= ~(MCDOPEN|MCDREADRAW); cd->openflags &= ~(1<b_dev); cd = mcd_data + unit; /* test validity */ /*MCD_TRACE("strategy: buf=0x%lx, unit=%ld, block#=%ld bcount=%ld\n", bp,unit,bp->b_blkno,bp->b_bcount);*/ if (unit >= NMCD || bp->b_blkno < 0) { printf("mcdstrategy: unit = %d, blkno = %d, bcount = %d\n", unit, bp->b_blkno, bp->b_bcount); pg("mcd: mcdstratregy failure"); bp->b_error = EINVAL; bp->b_flags |= B_ERROR; goto bad; } /* if device invalidated (e.g. media change, door open), error */ if (!(cd->flags & MCDVALID)) { MCD_TRACE("strategy: drive not valid\n",0,0,0,0); bp->b_error = EIO; goto bad; } /* read only */ if (!(bp->b_flags & B_READ)) { bp->b_error = EROFS; goto bad; } /* no data to read */ if (bp->b_bcount == 0) goto done; /* for non raw access, check partition limits */ if (mcd_part(bp->b_dev) != RAW_PART) { if (!(cd->flags & MCDLABEL)) { bp->b_error = EIO; goto bad; } /* adjust transfer if necessary */ if (bounds_check_with_label(bp,&cd->dlabel,1) <= 0) { goto done; } } /* queue it */ qp = &cd->head; s = splbio(); disksort(qp,bp); splx(s); /* now check whether we can perform processing */ mcd_start(unit); return; bad: bp->b_flags |= B_ERROR; done: bp->b_resid = bp->b_bcount; biodone(bp); return; } static void mcd_start(int unit) { struct mcd_data *cd = mcd_data + unit; struct buf *bp, *qp = &cd->head; struct partition *p; int part; register s = splbio(); if (cd->flags & MCDMBXBSY) return; if ((bp = qp->b_actf) != 0) { /* block found to process, dequeue */ /*MCD_TRACE("mcd_start: found block bp=0x%x\n",bp,0,0,0);*/ qp->b_actf = bp->av_forw; splx(s); } else { /* nothing to do */ splx(s); return; } /* changed media? */ if (!(cd->flags & MCDVALID)) { MCD_TRACE("mcd_start: drive not valid\n",0,0,0,0); return; } p = cd->dlabel.d_partitions + mcd_part(bp->b_dev); cd->flags |= MCDMBXBSY; cd->mbx.unit = unit; cd->mbx.port = cd->iobase; cd->mbx.retry = MCD_RETRYS; cd->mbx.bp = bp; cd->mbx.p_offset = p->p_offset; /* calling the read routine */ mcd_doread(MCD_S_BEGIN,&(cd->mbx)); /* triggers mcd_start, when successful finished */ return; } int mcdioctl(dev_t dev, int cmd, caddr_t addr, int flags) { struct mcd_data *cd; int unit,part; unit = mcd_unit(dev); part = mcd_part(dev); cd = mcd_data + unit; #ifdef MCDMINI return ENOTTY; #else if (!(cd->flags & MCDVALID)) return EIO; MCD_TRACE("ioctl called 0x%x\n",cmd,0,0,0); switch (cmd) { case DIOCSBAD: return EINVAL; case DIOCGDINFO: case DIOCGPART: case DIOCWDINFO: case DIOCSDINFO: case DIOCWLABEL: return ENOTTY; case CDIOCPLAYTRACKS: return mcd_playtracks(unit, (struct ioc_play_track *) addr); case CDIOCPLAYBLOCKS: return mcd_play(unit, (struct mcd_read2 *) addr); case CDIOCREADSUBCHANNEL: return mcd_subchan(unit, (struct ioc_read_subchannel *) addr); case CDIOREADTOCHEADER: return mcd_toc_header(unit, (struct ioc_toc_header *) addr); case CDIOREADTOCENTRYS: return mcd_toc_entry(unit, (struct ioc_read_toc_entry *) addr); case CDIOCSETPATCH: case CDIOCGETVOL: case CDIOCSETVOL: case CDIOCSETMONO: case CDIOCSETSTERIO: case CDIOCSETMUTE: case CDIOCSETLEFT: case CDIOCSETRIGHT: return EINVAL; case CDIOCRESUME: return mcd_resume(unit); case CDIOCPAUSE: return mcd_pause(unit); case CDIOCSTART: return EINVAL; case CDIOCSTOP: return mcd_stop(unit); case CDIOCEJECT: return EINVAL; case CDIOCSETDEBUG: cd->debug = 1; return 0; case CDIOCCLRDEBUG: cd->debug = 0; return 0; case CDIOCRESET: return EINVAL; default: return ENOTTY; } /*NOTREACHED*/ #endif /*!MCDMINI*/ } /* this could have been taken from scsi/cd.c, but it is not clear * whether the scsi cd driver is linked in */ static int mcd_getdisklabel(int unit) { struct mcd_data *cd = mcd_data + unit; if (cd->flags & MCDLABEL) return -1; bzero(&cd->dlabel,sizeof(struct disklabel)); strncpy(cd->dlabel.d_typename,"Mitsumi CD ROM ",16); strncpy(cd->dlabel.d_packname,"unknown ",16); cd->dlabel.d_secsize = cd->blksize; cd->dlabel.d_nsectors = 100; cd->dlabel.d_ntracks = 1; cd->dlabel.d_ncylinders = (cd->disksize/100)+1; cd->dlabel.d_secpercyl = 100; cd->dlabel.d_secperunit = cd->disksize; cd->dlabel.d_rpm = 300; cd->dlabel.d_interleave = 1; cd->dlabel.d_flags = D_REMOVABLE; cd->dlabel.d_npartitions= 1; cd->dlabel.d_partitions[0].p_offset = 0; cd->dlabel.d_partitions[0].p_size = cd->disksize; cd->dlabel.d_partitions[0].p_fstype = 9; cd->dlabel.d_magic = DISKMAGIC; cd->dlabel.d_magic2 = DISKMAGIC; cd->dlabel.d_checksum = dkcksum(&cd->dlabel); cd->flags |= MCDLABEL; return 0; } int mcdsize(dev_t dev) { int size; int unit = mcd_unit(dev); struct mcd_data *cd = mcd_data + unit; if (mcd_volinfo(unit) >= 0) { cd->blksize = MCDBLK; size = msf2hsg(cd->volinfo.vol_msf); cd->disksize = size * (MCDBLK/DEV_BSIZE); return 0; } return -1; } /*************************************************************** * lower level of driver starts here **************************************************************/ #ifdef NOTDEF static char irqs[] = { 0x00,0x00,0x10,0x20,0x00,0x30,0x00,0x00, 0x00,0x10,0x40,0x50,0x00,0x00,0x00,0x00 }; static char drqs[] = { 0x00,0x01,0x00,0x03,0x00,0x05,0x06,0x07, }; #endif static void mcd_configure(struct mcd_data *cd) { outb(cd->iobase+mcd_config,cd->config); } /* check if there is a cdrom */ /* Heavly hacked by gclarkii@sugar.neosoft.com */ int mcd_probe(struct isa_device *dev) { int port = dev->id_iobase; int unit = dev->id_unit; int i; int st; int check; int junk; mcd_data[unit].flags = MCDPROBING; #ifdef NOTDEF /* get irq/drq configuration word */ mcd_data[unit].config = irqs[dev->id_irq]; /* | drqs[dev->id_drq];*/ #else mcd_data[unit].config = 0; #endif /* send a reset */ outb(port+MCD_FLAGS,0); DELAY(100000); /* get any pending status and throw away...*/ for (i=10; i != 0; i--) { inb(port+MCD_DATA); } DELAY(1000); outb(port+MCD_DATA,MCD_CMDGETSTAT); /* Send get status command */ /* Loop looking for avail of status */ /* XXX May have to increase for fast machinces */ for (i = 1000; i != 0; i--) { if ((inb(port+MCD_FLAGS) & 0xF ) == STATUS_AVAIL) { break; } DELAY(10); } /* get status */ if (i == 0) { #ifdef DEBUG printf ("Mitsumi drive NOT detected\n"); #endif return 0; } /* * The following code uses the 0xDC command, it returns a M from the * second byte and a number in the third. Does anyone know what the * number is for? Better yet, how about someone thats REAL good in * i80x86 asm looking at the Dos driver... Most of this info came * from a friend of mine spending a whole weekend..... */ DELAY (2000); outb(port+MCD_DATA,MCD_CMDCONTINFO); for (i = 0; i < 100000; i++) { if ((inb(port+MCD_FLAGS) & 0xF) == STATUS_AVAIL) break; } if (i > 100000) { #ifdef DEBUG printf ("Mitsumi drive error\n"); #endif return 0; } DELAY (40000); st = inb(port+MCD_DATA); DELAY (500); check = inb(port+MCD_DATA); DELAY (500); junk = inb(port+MCD_DATA); /* What is byte used for?!?!? */ if (check = 'M') { #ifdef DEBUG printf("Mitsumi drive detected\n"); #endif return 4; } else { printf("Mitsumi drive NOT detected\n"); printf("Mitsumi drive error\n"); return 0; } } static int mcd_waitrdy(int port,int dly) { int i; /* wait until xfer port senses data ready */ for (i=0; iiobase; /* wait data to become ready */ if (mcd_waitrdy(port,dly)<0) { #ifdef MCD_TO_WARNING_ON printf("mcd%d: timeout getreply\n",unit); #endif return -1; } /* get the data */ return inb(port+mcd_status) & 0xFF; } static int mcd_getstat(int unit,int sflg) { int i; struct mcd_data *cd = mcd_data + unit; int port = cd->iobase; /* get the status */ if (sflg) outb(port+mcd_command, MCD_CMDGETSTAT); i = mcd_getreply(unit,DELAY_GETREPLY); if (i<0) return -1; cd->status = i; mcd_setflags(unit,cd); return cd->status; } static void mcd_setflags(int unit, struct mcd_data *cd) { /* check flags */ if (cd->status & (MCDDSKCHNG|MCDDOOROPEN)) { MCD_TRACE("getstat: sensed DSKCHNG or DOOROPEN\n",0,0,0,0); cd->flags &= ~MCDVALID; } #ifndef MCDMINI if (cd->status & MCDAUDIOBSY) cd->audio_status = CD_AS_PLAY_IN_PROGRESS; else if (cd->audio_status == CD_AS_PLAY_IN_PROGRESS) cd->audio_status = CD_AS_PLAY_COMPLETED; #endif } static int mcd_get(int unit, char *buf, int nmax) { int port = mcd_data[unit].iobase; int i,k; for (i=0; i> 4) * 10 + (b & 15); } static bcd_t bin2bcd(int b) { return ((b / 10) << 4) | (b % 10); } static void hsg2msf(int hsg, bcd_t *msf) { hsg += 150; M_msf(msf) = bin2bcd(hsg / 4500); hsg %= 4500; S_msf(msf) = bin2bcd(hsg / 75); F_msf(msf) = bin2bcd(hsg % 75); } static int msf2hsg(bcd_t *msf) { return (bcd2bin(M_msf(msf)) * 60 + bcd2bin(S_msf(msf))) * 75 + bcd2bin(F_msf(msf)) - 150; } static int mcd_volinfo(int unit) { struct mcd_data *cd = mcd_data + unit; int i; /*MCD_TRACE("mcd_volinfo: enter\n",0,0,0,0);*/ /* Get the status, in case the disc has been changed */ if (mcd_getstat(unit, 1) < 0) return EIO; /* Just return if we already have it */ if (cd->flags & MCDVOLINFO) return 0; /* send volume info command */ if (mcd_send(unit,MCD_CMDGETVOLINFO,MCD_RETRYS) < 0) return -1; /* get data */ if (mcd_get(unit,(char*) &cd->volinfo,sizeof(struct mcd_volinfo)) < 0) { printf("mcd%d: mcd_volinfo: error read data\n",unit); return -1; } if (cd->volinfo.trk_low != 0 || cd->volinfo.trk_high != 0) { cd->flags |= MCDVOLINFO; /* volinfo is OK */ return 0; } return -1; } int mcdintr(unit) { int port = mcd_data[unit].iobase; u_int i; MCD_TRACE("stray interrupt xfer=0x%x\n",inb(port+mcd_xfer),0,0,0); /* just read out status and ignore the rest */ if ((inb(port+mcd_xfer)&0xFF) != 0xFF) { i = inb(port+mcd_status); } } /* state machine to process read requests * initialize with MCD_S_BEGIN: calculate sizes, and read status * MCD_S_WAITSTAT: wait for status reply, set mode * MCD_S_WAITMODE: waits for status reply from set mode, set read command * MCD_S_WAITREAD: wait for read ready, read data */ static struct mcd_mbx *mbxsave; static void mcd_doread(int state, struct mcd_mbx *mbxin) { struct mcd_mbx *mbx = (state!=MCD_S_BEGIN) ? mbxsave : mbxin; int unit = mbx->unit; int port = mbx->port; struct buf *bp = mbx->bp; struct mcd_data *cd = mcd_data + unit; int rm,i,k; struct mcd_read2 rbuf; int blknum; caddr_t addr; loop: switch (state) { case MCD_S_BEGIN: mbx = mbxsave = mbxin; case MCD_S_BEGIN1: /* get status */ outb(port+mcd_command, MCD_CMDGETSTAT); mbx->count = RDELAY_WAITSTAT; timeout(mcd_doread,MCD_S_WAITSTAT,hz/100); return; case MCD_S_WAITSTAT: untimeout(mcd_doread,MCD_S_WAITSTAT); if (mbx->count-- >= 0) { if (inb(port+mcd_xfer) & MCD_ST_BUSY) { timeout(mcd_doread,MCD_S_WAITSTAT,hz/100); return; } mcd_setflags(unit,cd); MCD_TRACE("got WAITSTAT delay=%d\n",RDELAY_WAITSTAT-mbx->count,0,0,0); /* reject, if audio active */ if (cd->status & MCDAUDIOBSY) { printf("mcd%d: audio is active\n",unit); goto readerr; } /* to check for raw/cooked mode */ if (cd->flags & MCDREADRAW) { rm = MCD_MD_RAW; mbx->sz = MCDRBLK; } else { rm = MCD_MD_COOKED; mbx->sz = cd->blksize; } mbx->count = RDELAY_WAITMODE; mcd_put(port+mcd_command, MCD_CMDSETMODE); mcd_put(port+mcd_command, rm); timeout(mcd_doread,MCD_S_WAITMODE,hz/100); return; } else { #ifdef MCD_TO_WARNING_ON printf("mcd%d: timeout getstatus\n",unit); #endif goto readerr; } case MCD_S_WAITMODE: untimeout(mcd_doread,MCD_S_WAITMODE); if (mbx->count-- < 0) { #ifdef MCD_TO_WARNING_ON printf("mcd%d: timeout set mode\n",unit); #endif goto readerr; } if (inb(port+mcd_xfer) & MCD_ST_BUSY) { timeout(mcd_doread,MCD_S_WAITMODE,hz/100); return; } mcd_setflags(unit,cd); MCD_TRACE("got WAITMODE delay=%d\n",RDELAY_WAITMODE-mbx->count,0,0,0); /* for first block */ mbx->nblk = (bp->b_bcount + (mbx->sz-1)) / mbx->sz; mbx->skip = 0; nextblock: blknum = (bp->b_blkno / (mbx->sz/DEV_BSIZE)) + mbx->p_offset + mbx->skip/mbx->sz; MCD_TRACE("mcd_doread: read blknum=%d for bp=0x%x\n",blknum,bp,0,0); /* build parameter block */ hsg2msf(blknum,rbuf.start_msf); /* send the read command */ mcd_put(port+mcd_command,MCD_CMDREAD2); mcd_put(port+mcd_command,rbuf.start_msf[0]); mcd_put(port+mcd_command,rbuf.start_msf[1]); mcd_put(port+mcd_command,rbuf.start_msf[2]); mcd_put(port+mcd_command,0); mcd_put(port+mcd_command,0); mcd_put(port+mcd_command,1); mbx->count = RDELAY_WAITREAD; timeout(mcd_doread,MCD_S_WAITREAD,hz/100); return; case MCD_S_WAITREAD: untimeout(mcd_doread,MCD_S_WAITREAD); if (mbx->count-- > 0) { k = inb(port+mcd_xfer); if ((k & 2)==0) { MCD_TRACE("got data delay=%d\n",RDELAY_WAITREAD-mbx->count,0,0,0); /* data is ready */ addr = bp->b_un.b_addr + mbx->skip; outb(port+mcd_ctl2,0x04); /* XXX */ for (i=0; isz; i++) *addr++ = inb(port+mcd_rdata); outb(port+mcd_ctl2,0x0c); /* XXX */ if (--mbx->nblk > 0) { mbx->skip += mbx->sz; goto nextblock; } /* return buffer */ bp->b_resid = 0; biodone(bp); cd->flags &= ~MCDMBXBSY; mcd_start(mbx->unit); return; } if ((k & 4)==0) mcd_getstat(unit,0); timeout(mcd_doread,MCD_S_WAITREAD,hz/100); return; } else { #ifdef MCD_TO_WARNING_ON printf("mcd%d: timeout read data\n",unit); #endif goto readerr; } } readerr: if (mbx->retry-- > 0) { #ifdef MCD_TO_WARNING_ON printf("mcd%d: retrying\n",unit); #endif state = MCD_S_BEGIN1; goto loop; } /* invalidate the buffer */ bp->b_flags |= B_ERROR; bp->b_resid = bp->b_bcount; biodone(bp); mcd_start(mbx->unit); return; #ifdef NOTDEF printf("mcd%d: unit timeout, resetting\n",mbx->unit); outb(mbx->port+mcd_reset,MCD_CMDRESET); DELAY(300000); (void)mcd_getstat(mbx->unit,1); (void)mcd_getstat(mbx->unit,1); /*cd->status &= ~MCDDSKCHNG; */ cd->debug = 1; /* preventive set debug mode */ #endif } #ifndef MCDMINI static int mcd_setmode(int unit, int mode) { struct mcd_data *cd = mcd_data + unit; int port = cd->iobase; int retry; printf("mcd%d: setting mode to %d\n", unit, mode); for(retry=0; retrylen = msf2hsg(cd->volinfo.vol_msf); th->starting_track = bcd2bin(cd->volinfo.trk_low); th->ending_track = bcd2bin(cd->volinfo.trk_high); return 0; } static int mcd_read_toc(int unit) { struct mcd_data *cd = mcd_data + unit; struct ioc_toc_header th; struct mcd_qchninfo q; int rc, trk, idx, retry; /* Only read TOC if needed */ if (cd->flags & MCDTOC) return 0; printf("mcd%d: reading toc header\n", unit); if (mcd_toc_header(unit, &th) != 0) return ENXIO; printf("mcd%d: stopping play\n", unit); if ((rc=mcd_stop(unit)) != 0) return rc; /* try setting the mode twice */ if (mcd_setmode(unit, MCD_MD_TOC) != 0) return EIO; if (mcd_setmode(unit, MCD_MD_TOC) != 0) return EIO; printf("mcd%d: get_toc reading qchannel info\n",unit); for(trk=th.starting_track; trk<=th.ending_track; trk++) cd->toc[trk].idx_no = 0; trk = th.ending_track - th.starting_track + 1; for(retry=0; retry<300 && trk>0; retry++) { if (mcd_getqchan(unit, &q) < 0) break; idx = bcd2bin(q.idx_no); if (idx>0 && idx < MCD_MAXTOCS && q.trk_no==0) if (cd->toc[idx].idx_no == 0) { cd->toc[idx] = q; trk--; } } if (mcd_setmode(unit, MCD_MD_COOKED) != 0) return EIO; if (trk != 0) return ENXIO; /* add a fake last+1 */ idx = th.ending_track + 1; cd->toc[idx].ctrl_adr = cd->toc[idx-1].ctrl_adr; cd->toc[idx].trk_no = 0; cd->toc[idx].idx_no = 0xAA; cd->toc[idx].hd_pos_msf[0] = cd->volinfo.vol_msf[0]; cd->toc[idx].hd_pos_msf[1] = cd->volinfo.vol_msf[1]; cd->toc[idx].hd_pos_msf[2] = cd->volinfo.vol_msf[2]; cd->flags |= MCDTOC; return 0; } static int mcd_toc_entry(int unit, struct ioc_read_toc_entry *te) { struct mcd_data *cd = mcd_data + unit; struct ret_toc { struct ioc_toc_header th; struct cd_toc_entry rt; } ret_toc; struct ioc_toc_header th; int rc, i; /* Make sure we have a valid toc */ if ((rc=mcd_read_toc(unit)) != 0) return rc; /* find the toc to copy*/ i = te->starting_track; if (i == MCD_LASTPLUS1) i = bcd2bin(cd->volinfo.trk_high) + 1; /* verify starting track */ if (i < bcd2bin(cd->volinfo.trk_low) || i > bcd2bin(cd->volinfo.trk_high)+1) return EINVAL; /* do we have room */ if (te->data_len < sizeof(struct ioc_toc_header) + sizeof(struct cd_toc_entry)) return EINVAL; /* Copy the toc header */ if (mcd_toc_header(unit, &th) < 0) return EIO; ret_toc.th = th; /* copy the toc data */ ret_toc.rt.control = cd->toc[i].ctrl_adr; ret_toc.rt.addr_type = te->address_format; ret_toc.rt.track = i; if (te->address_format == CD_MSF_FORMAT) { ret_toc.rt.addr[1] = cd->toc[i].hd_pos_msf[0]; ret_toc.rt.addr[2] = cd->toc[i].hd_pos_msf[1]; ret_toc.rt.addr[3] = cd->toc[i].hd_pos_msf[2]; } /* copy the data back */ copyout(&ret_toc, te->data, sizeof(struct cd_toc_entry) + sizeof(struct ioc_toc_header)); return 0; } static int mcd_stop(int unit) { struct mcd_data *cd = mcd_data + unit; if (mcd_send(unit, MCD_CMDSTOPAUDIO, MCD_RETRYS) < 0) return ENXIO; cd->audio_status = CD_AS_PLAY_COMPLETED; return 0; } static int mcd_getqchan(int unit, struct mcd_qchninfo *q) { struct mcd_data *cd = mcd_data + unit; if (mcd_send(unit, MCD_CMDGETQCHN, MCD_RETRYS) < 0) return -1; if (mcd_get(unit, (char *) q, sizeof(struct mcd_qchninfo)) < 0) return -1; if (cd->debug) printf("mcd%d: qchannel ctl=%d, t=%d, i=%d, ttm=%d:%d.%d dtm=%d:%d.%d\n", unit, q->ctrl_adr, q->trk_no, q->idx_no, q->trk_size_msf[0], q->trk_size_msf[1], q->trk_size_msf[2], q->trk_size_msf[0], q->trk_size_msf[1], q->trk_size_msf[2]); return 0; } static int mcd_subchan(int unit, struct ioc_read_subchannel *sc) { struct mcd_data *cd = mcd_data + unit; struct mcd_qchninfo q; struct cd_sub_channel_info data; printf("mcd%d: subchan af=%d, df=%d\n", unit, sc->address_format, sc->data_format); if (sc->address_format != CD_MSF_FORMAT) return EIO; if (sc->data_format != CD_CURRENT_POSITION) return EIO; if (mcd_getqchan(unit, &q) < 0) return EIO; data.header.audio_status = cd->audio_status; data.what.position.data_format = CD_MSF_FORMAT; data.what.position.track_number = bcd2bin(q.trk_no); if (copyout(&data, sc->data, sizeof(struct cd_sub_channel_info))!=0) return EFAULT; return 0; } static int mcd_playtracks(int unit, struct ioc_play_track *pt) { struct mcd_data *cd = mcd_data + unit; struct mcd_read2 pb; int a = pt->start_track; int z = pt->end_track; int rc; if ((rc = mcd_read_toc(unit)) != 0) return rc; printf("mcd%d: playtracks from %d:%d to %d:%d\n", unit, a, pt->start_index, z, pt->end_index); if (a < cd->volinfo.trk_low || a > cd->volinfo.trk_high || a > z || z < cd->volinfo.trk_low || z > cd->volinfo.trk_high) return EINVAL; pb.start_msf[0] = cd->toc[a].hd_pos_msf[0]; pb.start_msf[1] = cd->toc[a].hd_pos_msf[1]; pb.start_msf[2] = cd->toc[a].hd_pos_msf[2]; pb.end_msf[0] = cd->toc[z+1].hd_pos_msf[0]; pb.end_msf[1] = cd->toc[z+1].hd_pos_msf[1]; pb.end_msf[2] = cd->toc[z+1].hd_pos_msf[2]; return mcd_play(unit, &pb); } static int mcd_play(int unit, struct mcd_read2 *pb) { struct mcd_data *cd = mcd_data + unit; int port = cd->iobase; int retry, st; cd->lastpb = *pb; for(retry=0; retrystart_msf[0]); outb(port+mcd_command, pb->start_msf[1]); outb(port+mcd_command, pb->start_msf[2]); outb(port+mcd_command, pb->end_msf[0]); outb(port+mcd_command, pb->end_msf[1]); outb(port+mcd_command, pb->end_msf[2]); if ((st=mcd_getstat(unit, 0)) != -1) break; } if (cd->debug) printf("mcd%d: mcd_play retry=%d, status=%d\n", unit, retry, st); if (st == -1) return ENXIO; cd->audio_status = CD_AS_PLAY_IN_PROGRESS; return 0; } static int mcd_pause(int unit) { struct mcd_data *cd = mcd_data + unit; struct mcd_qchninfo q; int rc; /* Verify current status */ if (cd->audio_status != CD_AS_PLAY_IN_PROGRESS) { printf("mcd%d: pause attempted when not playing\n", unit); return EINVAL; } /* Get the current position */ if (mcd_getqchan(unit, &q) < 0) return EIO; /* Copy it into lastpb */ cd->lastpb.start_msf[0] = q.hd_pos_msf[0]; cd->lastpb.start_msf[1] = q.hd_pos_msf[1]; cd->lastpb.start_msf[2] = q.hd_pos_msf[2]; /* Stop playing */ if ((rc=mcd_stop(unit)) != 0) return rc; /* Set the proper status and exit */ cd->audio_status = CD_AS_PLAY_PAUSED; return 0; } static int mcd_resume(int unit) { struct mcd_data *cd = mcd_data + unit; if (cd->audio_status != CD_AS_PLAY_PAUSED) return EINVAL; return mcd_play(unit, &cd->lastpb); } #endif /*!MCDMINI*/ #endif /* NMCD > 0 */ Index: head/sys/i386/isa/rtc.h =================================================================== --- head/sys/i386/isa/rtc.h (revision 618) +++ head/sys/i386/isa/rtc.h (revision 619) @@ -1,85 +1,86 @@ /*- * 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. * - * @(#)rtc.h 7.1 (Berkeley) 5/12/91 + * from: @(#)rtc.h 7.1 (Berkeley) 5/12/91 + * $Id$ */ /* * 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 RTC_STATUSB 0x0b /* status register B */ #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_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*/ Index: head/sys/i386/isa/sio.c =================================================================== --- head/sys/i386/isa/sio.c (revision 618) +++ head/sys/i386/isa/sio.c (revision 619) @@ -1,1749 +1,1740 @@ /*- * 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 - * - * 27 May 93 Bruce Evans From com-0.2 package, fast interrupt - * com port driver. - * 27 May 93 Guido van Rooij Ported in Chris Demetriou's BIDIR - * code, add multiport support. - * 27 May 93 Rodney W. Grimes I then renamed it to sio.c for putting - * into the patch kit. Added in sioselect - * from com.c. Added port 4 support. + * from: @(#)com.c 7.5 (Berkeley) 5/16/91 + * $Id$ */ -static char rcsid[] = "$Header: /a/cvs/386BSD/src/sys/i386/isa/sio.c,v 1.10 1993/10/12 06:32:28 davidg Exp $"; #include "sio.h" #if NSIO > 0 /* * COM driver, based on HP dca driver. * Mostly rewritten to use pseudo-DMA. * Works for National Semiconductor NS8250-NS16550AF UARTs. */ #include "param.h" #include "systm.h" #include "ioctl.h" #include "tty.h" #include "proc.h" #include "user.h" #include "conf.h" #include "file.h" #include "uio.h" #include "kernel.h" #include "syslog.h" #include "i386/isa/isa.h" #include "i386/isa/isa_device.h" #include "i386/isa/comreg.h" #include "i386/isa/ic/ns16550.h" #undef CRTS_IFLOW #define CRTS_IFLOW CRTSCTS /* XXX, CCTS_OFLOW = CRTSCTS already */ #define LOTS_OF_EVENTS 64 /* helps separate urgent events from input */ #define RB_I_HIGH_WATER (RBSZ - 2 * RS_IBUFSIZE) #define RB_I_LOW_WATER ((RBSZ - 2 * RS_IBUFSIZE) * 7 / 8) #define RS_IBUFSIZE 256 #define TS_RTSBLOCK TS_TBLOCK /* XXX */ #define TTY_BI TTY_FE /* XXX */ #define TTY_OE TTY_PE /* XXX */ #ifndef COM_BIDIR #define UNIT(x) (minor(x)) /* XXX */ #else /* COM_BIDIR */ #define COM_UNITMASK 0x7f #define COM_CALLOUTMASK 0x80 #define UNIT(x) (minor(x) & COM_UNITMASK) #define CALLOUT(x) (minor(x) & COM_CALLOUTMASK) #endif /* COM_BIDIR */ #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) #endif /* COM_MULTIPORT */ #define com_scr 7 /* scratch register for 16450-16550 (R/W) */ #define schedsoftcom() (ipending |= 1 << 4) /* XXX */ /* * 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. * Bug: I think TIOCSETA doesn't clear TS_TTSTOP when it clears IXON. */ #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_ODONE 4 /* output completed */ #define CS_RTS_IFLOW 8 /* use RTS input flow control */ static char *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 int Bool_t; /* promoted boolean */ typedef u_char bool_t; /* boolean */ /* com device structure */ struct com_s { u_char state; /* miscellaneous flag bits */ u_char cfcr_image; /* copy of value written to CFCR */ bool_t hasfifo; /* nonzero for 16550 UARTs */ u_char mcr_image; /* copy of value written to MCR */ bool_t softDCD; /* nonzero for faked carrier detect */ #ifdef COM_BIDIR bool_t bidir; /* is this unit bidirectional? */ bool_t active; /* is the port active _at all_? */ bool_t active_in; /* is the incoming port in use? */ bool_t active_out; /* is the outgoing port in use? */ #endif /* COM_BIDIR */ #ifdef COM_MULTIPORT bool_t multiport; /* is this unit part of a multiport device? */ #endif /* COM_MULTIPORT */ /* * 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 *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 */ int ocount; /* original count for current output */ 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 */ 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]; }; /* * These functions in the com module ought to be declared (with a prototype) * in a com-driver system header. The void ones may need to be int to match * ancient devswitch declarations, but they don't actually return anything. */ #define Dev_t int /* promoted dev_t */ struct consdev; int sioclose __P((Dev_t dev, int fflag, int devtype, struct proc *p)); void siointr __P((int unit)); #ifdef COM_MULTIPORT bool_t comintr1 __P((struct com_s *com)); #endif /* COM_MULTIPORT */ int sioioctl __P((Dev_t dev, int cmd, caddr_t data, int fflag, struct proc *p)); int siocngetc __P((Dev_t dev)); void siocninit __P((struct consdev *cp)); void siocnprobe __P((struct consdev *cp)); void siocnputc __P((Dev_t dev, int c)); int sioopen __P((Dev_t dev, int oflags, int devtype, struct proc *p)); /* * sioopen gets compared to the d_open entry in struct cdevsw. d_open and * other functions are declared in with short types like dev_t * in the prototype. Such declarations are broken because they vary with * __P (significantly in theory - the compiler is allowed to push a short * arg if it has seen the prototype; insignificantly in practice - gcc * doesn't push short args and it would be slower on 386's to do so). * * Also, most of the device switch functions are still declared old-style * so they take a Dev_t arg and shorten it to a dev_t. It would be simpler * and faster if dev_t's were always promoted (to ints or whatever) as * early as possible. * * Until is fixed, we cast sioopen to the following `wrong' type * when comparing it to the d_open entry just to avoid compiler warnings. */ typedef int (*bogus_open_t) __P((dev_t dev, int oflags, int devtype, struct proc *p)); int sioread __P((Dev_t dev, struct uio *uio, int ioflag)); void siostop __P((struct tty *tp, int rw)); int siowrite __P((Dev_t dev, struct uio *uio, int ioflag)); void softsio0 __P((void)); void softsio1 __P((void)); void softsio2 __P((void)); void softsio3 __P((void)); void softsio4 __P((void)); void softsio5 __P((void)); void softsio6 __P((void)); void softsio7 __P((void)); void softsio8 __P((void)); static int sioattach __P((struct isa_device *dev)); static void comflush __P((struct com_s *com)); static void comhardclose __P((struct com_s *com)); static void cominit __P((int unit, int rate)); static int 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 compoll __P((void)); static int comstart __P((struct tty *tp)); static void comwakeup __P((void)); static int tiocm2mcr __P((int)); /* 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]) static struct com_s com_structs[NSIO]; struct isa_driver siodriver = { sioprobe, sioattach, "sio" }; #ifdef COMCONSOLE static int comconsole = COMCONSOLE; #else static int comconsole = -1; #endif static bool_t comconsinit; static speed_t comdefaultrate = TTYDEF_SPEED; static u_int com_events; /* input chars + weighted output completions */ static int commajor; struct tty sio_tty[NSIO]; extern struct tty *constty; extern u_int ipending; /* XXX */ extern int tk_nin; /* XXX */ extern int tk_rawcc; /* 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; Port_t iobase; 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. */ 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; } iobase = dev->id_iobase; result = IO_COMSIZE; /* * 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(); /* * Enable output interrupts (only) and check the following: * 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. */ outb(iobase + com_cfcr, CFCR_8BITS); /* ensure IER is addressed */ outb(iobase + com_mcr, MCR_IENABLE); /* open gate early */ outb(iobase + com_ier, 0); /* ensure edge on next intr */ outb(iobase + com_ier, IER_ETXRDY); /* generate interrupt */ if ( inb(iobase + com_cfcr) != CFCR_8BITS || inb(iobase + com_ier) != IER_ETXRDY || inb(iobase + com_mcr) != MCR_IENABLE || (inb(iobase + com_iir) & IIR_IMASK) != IIR_TXRDY || isa_irq_pending(dev) || (inb(iobase + com_iir) & IIR_IMASK) != IIR_NOPEND) result = 0; /* * Turn off all device interrupts and check that they go off properly. * Leave MCR_IENABLE set. 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_mcr, MCR_IENABLE); /* dummy to avoid bus echo */ if ( inb(iobase + com_ier) != 0 || isa_irq_pending(dev) || (inb(iobase + com_iir) & IIR_IMASK) != IIR_NOPEND) result = 0; enable_intr(); return (result); } static int /* XXX - should be void */ sioattach(isdp) struct isa_device *isdp; { struct com_s *com; static bool_t comwakeup_started = FALSE; Port_t iobase; int s; u_char scr; u_char scr1; u_char scr2; int unit; iobase = isdp->id_iobase; unit = isdp->id_unit; if (unit == comconsole) DELAY(1000); /* XXX */ s = spltty(); /* * 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. * Keeping MCR_DTR and MCR_RTS off might stop the external * device from sending before we are ready. */ com = &com_structs[unit]; com->cfcr_image = CFCR_8BITS; com->mcr_image = MCR_IENABLE; #if 0 com->softDCD = TRUE; #endif 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->line_status_port = iobase + com_lsr; com->modem_status_port = iobase + com_msr; com->tp = &sio_tty[unit]; #ifdef COM_BIDIR /* * if bidirectional ports possible, clear the bidir port info; */ com->bidir = FALSE; com->active = FALSE; com->active_in = com->active_out = FALSE; #endif /* COM_BIDIR */ /* attempt to determine UART type */ 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); printf("sio%d: type", unit); #ifdef COM_MULTIPORT if (0); #else if (scr1 != 0xa5 || scr2 != 0x5a) printf(" <8250>"); #endif else { outb(iobase + com_fifo, FIFO_ENABLE | FIFO_TRIGGER_14); DELAY(100); switch (inb(iobase + com_iir) & 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: com->hasfifo = TRUE; printf(" <16550A>"); break; } outb(iobase + com_fifo, 0); } #ifdef COM_MULTIPORT if (COM_ISMULTIPORT(isdp)) { struct isa_device *masterdev; com->multiport = TRUE; printf(" (multiport)"); /* set the master's common-interrupt-enable reg., * as appropriate. YYY See your manual */ /* enable only common interrupt for port */ outb(iobase + com_mcr, 0); masterdev = find_isadev(isa_devtab_tty, &siodriver, COM_MPMASTER(isdp)); outb(masterdev->id_iobase+com_scr, 0x80); } else com->multiport = FALSE; #endif /* COM_MULTIPORT */ printf("\n"); #ifdef KGDB if (kgdb_dev == makedev(commajor, unit)) { if (comconsole == unit) kgdb_dev = -1; /* can't debug over console port */ else { cominit(unit, kgdb_rate); if (kgdb_debug_init) { /* * Print prefix of device name, * let kgdb_connect print the rest. */ printf("com%d: ", unit); kgdb_connect(1); } else printf("com%d: kgdb enabled\n", unit); } } #endif /* * Need to reset baud rate, etc. of next print so reset comconsinit. * Also make sure console is always "hardwired" */ if (unit == comconsole) { comconsinit = FALSE; com->softDCD = TRUE; } com_addr(unit) = com; splx(s); if (!comwakeup_started) { comwakeup(); 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 = 0; Port_t iobase; int s; struct tty *tp; int unit = UNIT(dev); #ifdef COM_BIDIR bool_t callout = CALLOUT(dev); #endif /* COM_BIDIR */ if ((u_int) unit >= NSIO || (com = com_addr(unit)) == NULL) return (ENXIO); #ifdef COM_BIDIR /* if it's a callout device, and bidir not possible on that dev, die */ if (callout && !(com->bidir)) return (ENXIO); #endif /* COM_BIDIR */ tp = com->tp; s = spltty(); #ifdef COM_BIDIR bidir_open_top: /* if it's bidirectional, we've gotta deal with it... */ if (com->bidir) { if (callout) { if (com->active_in) { /* it's busy. die */ splx(s); return (EBUSY); } else { /* it's ours. lock it down, and set it up */ com->active_out = TRUE; com->softDCD = TRUE; } } else { if (com->active_out) { /* it's busy, outgoing. wait, if possible */ if (flag & O_NONBLOCK) { /* can't wait; bail */ splx(s); return (EBUSY); } else { /* wait for it... */ error = tsleep(&com->active_out, TTIPRI|PCATCH, "comoth", 0); /* if there was an error, take off. */ if (error != 0) { splx(s); return (error); } /* else take it from the top */ goto bidir_open_top; } } else if (com->last_modem_status & MSR_DCD) { /* there's a carrier on the line; we win */ com->active_in = TRUE; com->softDCD = FALSE; } else { /* there is no carrier on the line */ if (flag & O_NONBLOCK) { /* can't wait; let it open */ com->active_in = TRUE; com->softDCD = FALSE; } else { /* put DTR & RTS up */ /* NOTE: cgd'sdriver used the ier register * to enable/disable interrupts. This one * uses both ier and IENABLE in the mcr. */ (void) commctl(com, MCR_DTR | MCR_RTS, DMSET); outb(com->iobase + com_ier, IER_EMSC); /* wait for it... */ error = tsleep(&com->active_in, TTIPRI|PCATCH, "comdcd", 0); /* if not active, turn DTR & RTS off */ if (!com->active) (void) commctl(com, MCR_DTR, DMBIC); /* if there was an error, take off. */ if (error != 0) { splx(s); return (error); } /* else take it from the top */ goto bidir_open_top; } } } } com->active = TRUE; #endif /* COM_BIDIR */ tp->t_oproc = comstart; tp->t_param = comparam; tp->t_dev = dev; if (!(tp->t_state & TS_ISOPEN)) { tp->t_state |= TS_WOPEN; ttychars(tp); if (tp->t_ispeed == 0) { /* * We no longer use the flags from * since those 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. */ tp->t_iflag = 0; tp->t_oflag = 0; tp->t_cflag = CREAD | CS8 | HUPCL; tp->t_lflag = 0; tp->t_ispeed = tp->t_ospeed = comdefaultrate; } (void) commctl(com, MCR_DTR | MCR_RTS, DMSET); error = comparam(tp, &tp->t_termios); if (error != 0) goto out; ttsetwater(tp); iobase = com->iobase; disable_intr(); if (com->hasfifo) /* (re)enable and drain FIFO */ outb(iobase + com_fifo, FIFO_ENABLE | FIFO_TRIGGER_14 | FIFO_RCV_RST | FIFO_XMT_RST); (void) inb(com->line_status_port); (void) inb(com->data_port); com->last_modem_status = com->prev_modem_status = inb(com->modem_status_port); outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC); enable_intr(); if (com->softDCD || com->prev_modem_status & MSR_DCD) tp->t_state |= TS_CARR_ON; } else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) { splx(s); return (EBUSY); } while (!(flag & O_NONBLOCK) && !(tp->t_cflag & CLOCAL) #ifdef COM_BIDIR /* We went through a lot of trouble to open it, * but it's certain we have a carrier now, so * don't spend any time on it now. */ && !(com->bidir) #endif /* COM_BIDIR */ && !(tp->t_state & TS_CARR_ON)) { tp->t_state |= TS_WOPEN; error = ttysleep(tp, (caddr_t)&tp->t_raw, TTIPRI | PCATCH, ttopen, 0); if (error != 0) break; } out: splx(s); if (error == 0) error = (*linesw[tp->t_line].l_open)(dev, tp); #ifdef COM_BIDIR /* wakeup sleepers */ wakeup((caddr_t) &com->active_in); #endif /* COM_BIDIR */ /* * XXX - the next step was once not done, so interrupts, DTR and RTS * remainded hot if the process was killed while it was sleeping * waiting for carrier. Now there is the opposite problem. If several * processes are sleeping waiting for carrier on the same line and one * is killed, interrupts are turned off so the other processes will * never see the carrier rise. */ if (error != 0 && !(tp->t_state & TS_ISOPEN)) { comhardclose(com); } tp->t_state &= ~TS_WOPEN; return (error); } /*ARGSUSED*/ int sioclose(dev, flag, mode, p) dev_t dev; int flag; int mode; struct proc *p; { struct com_s *com; struct tty *tp; com = com_addr(UNIT(dev)); tp = com->tp; (*linesw[tp->t_line].l_close)(tp, flag); comhardclose(com); ttyclose(tp); return (0); } void comhardclose(com) struct com_s *com; { Port_t iobase; int s; struct tty *tp; s = spltty(); iobase = com->iobase; outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK); #ifdef KGDB /* do not disable interrupts if debugging */ if (kgdb_dev != makedev(commajor, com - &com_structs[0])) #endif outb(iobase + com_ier, 0); tp = com->tp; if (tp->t_cflag & HUPCL || tp->t_state & TS_WOPEN || !(tp->t_state & TS_ISOPEN)) (void) commctl(com, MCR_RTS, DMSET); #ifdef COM_BIDIR com->active = com->active_in = com->active_out = FALSE; com->softDCD = FALSE; /* wakeup sleepers who are waiting for out to finish */ wakeup((caddr_t) &com->active_out); #endif /* COM_BIDIR */ splx(s); } int sioread(dev, uio, flag) dev_t dev; struct uio *uio; int flag; { struct tty *tp = com_addr(UNIT(dev))->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 unit = UNIT(dev); struct tty *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)); } void siointr(unit) int unit; { struct com_s *com; #ifndef COM_MULTIPORT u_char line_status; u_char modem_status; u_char *ioptr; u_char recv_data; com = com_addr(unit); #else /* COM_MULTIPORT */ int i; bool_t donesomething; do { donesomething = FALSE; for(i=0;iline_status_port); /* input event? (check first to help avoid overruns) */ while (line_status & LSR_RCV_MASK) { /* break/unnattached error bits or real input? */ #ifdef COM_MULTIPORT donesomething = TRUE; #endif /* COM_MULTIPORT */ if (!(line_status & LSR_RXRDY)) recv_data = 0; else recv_data = inb(com->data_port); ++com->bytes_in; #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; 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); } /* * "& 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. */ #ifdef COM_MULTIPORT donesomething = TRUE; #endif /* COM_MULTIPORT */ com->last_modem_status = modem_status; if (!(com->state & CS_CHECKMSR)) { com_events += LOTS_OF_EVENTS; com->state |= CS_CHECKMSR; schedsoftcom(); } /* 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)) { #ifdef COM_MULTIPORT donesomething = TRUE; #endif /* COM_MULTIPORT */ ioptr = com->optr; 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); schedsoftcom(); /* handle at high level ASAP */ } } /* finished? */ if ((inb(com->int_id_port) & IIR_IMASK) == IIR_NOPEND) #ifdef COM_MULTIPORT return (donesomething); #else return; #endif /* COM_MULTIPORT */ } } static int tiocm2mcr(data) int data; { register m = 0; if (data & TIOCM_DTR) m |= MCR_DTR; if (data & TIOCM_RTS) m |= MCR_RTS; return m; } 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 s; struct tty *tp; com = com_addr(UNIT(dev)); tp = com->tp; error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 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: (void) commctl(com, MCR_DTR, DMBIS); break; case TIOCCDTR: (void) commctl(com, MCR_DTR, DMBIC); break; case TIOCMSET: (void) commctl(com, tiocm2mcr(*(int *)data), DMSET); break; case TIOCMBIS: (void) commctl(com, tiocm2mcr(*(int *)data), DMBIS); break; case TIOCMBIC: (void) commctl(com, tiocm2mcr(*(int *)data), DMBIC); break; case TIOCMGET: { register int bits = 0, mode; mode = commctl(com, 0, DMGET); if (inb(com->iobase+com_ier)) bits |= TIOCM_LE; /* XXX */ if (mode & MSR_DCD) bits |= TIOCM_CD; if (mode & MSR_CTS) bits |= TIOCM_CTS; if (mode & MSR_DSR) bits |= TIOCM_DSR; if (mode & (MCR_DTR<<8)) bits |= TIOCM_DTR; if (mode & (MCR_RTS<<8)) bits |= TIOCM_RTS; if (mode & (MSR_RI|MSR_TERI)) bits |= TIOCM_RI; *(int *)data = bits; } break; #ifdef COM_BIDIR case TIOCMSBIDIR: /* must be root to set bidir. capability */ if (p->p_ucred->cr_uid != 0) return(EPERM); /* if it's the console, can't do it */ if (UNIT(dev) == comconsole) return(ENOTTY); /* can't do the next, for obvious reasons... * but there are problems to be looked at... */ /* if the port is active, don't do it */ /* if (com->active) return(EBUSY); */ com->bidir = *(int *)data; break; case TIOCMGBIDIR: *(int *)data = com->bidir; break; #endif /* COM_BIDIR */ default: splx(s); return (ENOTTY); } splx(s); return (0); } /* cancel pending output */ static void comflush(com) struct com_s *com; { struct ringb *rbp; disable_intr(); if (com->state & CS_ODONE) com_events -= LOTS_OF_EVENTS; com->state &= ~(CS_ODONE | CS_BUSY); enable_intr(); rbp = &com->tp->t_out; rbp->rb_hd += com->ocount; rbp->rb_hd = RB_ROLLOVER(rbp, rbp->rb_hd); com->ocount = 0; com->tp->t_state &= ~TS_BUSY; } static void compoll() { static bool_t awake = FALSE; struct com_s *com; int s; int unit; if (com_events == 0) return; disable_intr(); if (awake) { enable_intr(); return; } awake = TRUE; enable_intr(); s = spltty(); repeat: for (unit = 0; unit < NSIO; ++unit) { u_char *buf; u_char *ibuf; int incc; struct tty *tp; com = com_addr(unit); if (com == NULL) continue; tp = com->tp; /* switch the role of the low-level input buffers */ if (com->iptr == (ibuf = com->ibuf)) incc = 0; else { 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. */ if (!(com->mcr_image & MCR_RTS) && !(tp->t_state & TS_RTSBLOCK)) 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 && unit != comconsole) { #ifdef COM_BIDIR if (com->prev_modem_status & MSR_DCD) { (*linesw[tp->t_line].l_modem)(tp, 1); com->softDCD = FALSE; wakeup((caddr_t) &com->active_in); } #else if (com->prev_modem_status & MSR_DCD) (*linesw[tp->t_line].l_modem)(tp, 1); #endif /* COM_BIDIR */ else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) { disable_intr(); outb(com->modem_ctl_port, com->mcr_image &= ~MCR_DTR); enable_intr(); } } } /* XXX */ if (TRUE) { u_int delta; u_int delta_error_counts[CE_NTYPES]; int errnum; u_long total; disable_intr(); bcopy(com->delta_error_counts, delta_error_counts, sizeof delta_error_counts); bzero(com->delta_error_counts, sizeof delta_error_counts); enable_intr(); for (errnum = 0; errnum < CE_NTYPES; ++errnum) { delta = delta_error_counts[errnum]; if (delta != 0) { total = com->error_counts[errnum] += delta; log(LOG_WARNING, "com%d: %u more %s%s (total %lu)\n", unit, delta, error_desc[errnum], delta == 1 ? "" : "s", total); } } } 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 && RB_LEN(&tp->t_raw) + incc >= RB_I_HIGH_WATER && !(tp->t_state & TS_RTSBLOCK) /* * 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_RTSBLOCK; 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] += incc - rb_write(&tp->t_raw, (char *) buf, incc); 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; splx(s); awake = FALSE; } 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 (divisor < 0 || t->c_ispeed != 0 && t->c_ispeed != t->c_ospeed) return (EINVAL); /* parameters are OK, convert them to the com struct and the device */ unit = UNIT(tp->t_dev); com = com_addr(unit); iobase = com->iobase; s = spltty(); if (divisor == 0) { (void) commctl(com, MCR_RTS, DMSET); /* hang up line */ splx(s); return (0); } 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; /* * 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 siointr() might lose some receiver * error bits, but that is acceptable here. */ disable_intr(); com->state &= ~CS_TTGO; enable_intr(); while ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY)) != (LSR_TSRE | LSR_TXRDY)) { error = ttysleep(tp, (caddr_t)&tp->t_raw, TTIPRI | PCATCH, "comparam", 1); 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 */ 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 16+ msec latency, while CTS flow has 50- usec latency. * Note that DCD flow control stupidly uses the same state flag * (TS_TTSTOP) as XON/XOFF flow control. */ com->state &= ~CS_CTS_OFLOW; com->state |= CS_ODEVREADY; if (cflag & CCTS_OFLOW) { com->state |= CS_CTS_OFLOW; if (!(com->prev_modem_status & MSR_CTS)) com->state &= ~CS_ODEVREADY; } enable_intr(); siointr(unit); /* recover from fiddling with CS_TTGO */ splx(s); return (0); } static int /* XXX - should be void */ comstart(tp) struct tty *tp; { struct com_s *com; int s; int unit; unit = 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_RTSBLOCK) { if (com->mcr_image & MCR_RTS && com->state & CS_RTS_IFLOW) outb(com->modem_ctl_port, com->mcr_image &= ~MCR_RTS); } else { if (!(com->mcr_image & MCR_RTS) && com->iptr < com->ihighwater) { tp->t_state &= ~TS_RTSBLOCK; outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS); } } enable_intr(); if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) goto out; if (RB_LEN(&tp->t_out) <= tp->t_lowat) { if (tp->t_state & TS_ASLEEP) { tp->t_state &= ~TS_ASLEEP; wakeup((caddr_t)&tp->t_out); } if (tp->t_wsel) { selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); tp->t_wsel = 0; tp->t_state &= ~TS_WCOLL; } } if (com->ocount != 0) { disable_intr(); siointr(unit); enable_intr(); } else if (RB_LEN(&tp->t_out) != 0) { tp->t_state |= TS_BUSY; com->ocount = RB_CONTIGGET(&tp->t_out); disable_intr(); com->obufend = (com->optr = (u_char *) tp->t_out.rb_hd) + com->ocount; com->state |= CS_BUSY; siointr(unit); /* fake interrupt to start output */ enable_intr(); } out: splx(s); return (1); } void siostop(tp, rw) struct tty *tp; int rw; { struct com_s *com; com = com_addr(UNIT(tp->t_dev)); if (rw & FWRITE) comflush(com); disable_intr(); if (tp->t_state & TS_TTSTOP) com->state &= ~CS_TTGO; else com->state |= CS_TTGO; enable_intr(); } static int commctl(com, bits, how) struct com_s *com; int bits; int how; { disable_intr(); switch (how) { case DMSET: #ifdef COM_MULTIPORT /* YYY maybe your card doesn't want IENABLE to be reset? */ if(com->multiport) outb(com->modem_ctl_port, com->mcr_image = bits); else #endif /* COM_MULTIPORT */ outb(com->modem_ctl_port, com->mcr_image = bits | MCR_IENABLE); break; case DMBIS: outb(com->modem_ctl_port, com->mcr_image |= bits); break; case DMBIC: #ifdef COM_MULTIPORT /* YYY maybe your card doesn't want IENABLE to be reset? */ if(com->multiport) outb(com->modem_ctl_port, com->mcr_image &= ~(bits)); else #endif /* COM_MULTIPORT */ outb(com->modem_ctl_port, com->mcr_image &= ~(bits & ~MCR_IENABLE)); break; case DMGET: bits = com->prev_modem_status | (com->mcr_image << 8); break; } enable_intr(); return (bits); } static void comwakeup() { struct com_s *com; int unit; timeout((timeout_func_t) comwakeup, (caddr_t) NULL, 1); if (com_events != 0) /* schedule compoll() to run when the cpl allows */ schedsoftcom(); /* recover from lost output interrupts */ for (unit = 0; unit < NSIO; ++unit) { com = com_addr(unit); if (com != NULL && com->state >= (CS_BUSY | CS_TTGO)) { disable_intr(); siointr(unit); enable_intr(); } } } void softsio0() { compoll(); } void softsio1() { compoll(); } void softsio2() { compoll(); } void softsio3() { compoll(); } void softsio4() { compoll(); } void softsio5() { compoll(); } void softsio6() { compoll(); } void softsio7() { compoll(); } void softsio8() { compoll(); } /* * Following are all routines needed for COM to act as console * XXX - not tested in this version * XXX - check that the corresponding serial interrupts are never enabled */ #include "i386/i386/cons.h" void siocnprobe(cp) struct consdev *cp; { int unit; /* locate the major number */ for (commajor = 0; commajor < nchrdev; commajor++) if (cdevsw[commajor].d_open == (bogus_open_t) sioopen) break; /* XXX: ick */ unit = CONUNIT; com_addr(unit) = &com_structs[unit]; com_addr(unit)->iobase = CONADDR; /* make sure hardware exists? XXX */ /* initialize required fields */ cp->cn_dev = makedev(commajor, unit); cp->cn_tp = &sio_tty[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; { int unit; unit = UNIT(cp->cn_dev); cominit(unit, comdefaultrate); comconsole = unit; comconsinit = TRUE; } static void cominit(unit, rate) int unit; int rate; { Port_t iobase; int s; iobase = com_addr(unit)->iobase; s = splhigh(); outb(iobase + com_cfcr, CFCR_DLAB); rate = ttspeedtab(comdefaultrate, comspeedtab); outb(iobase + com_data, rate & 0xFF); outb(iobase + com_ier, rate >> 8); outb(iobase + com_cfcr, CFCR_8BITS); /* * XXX - fishy to enable interrupts and then poll. * It shouldn't be necessary to ready the iir. */ outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC); outb(iobase + com_fifo, FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER_14); (void) inb(iobase + com_iir); splx(s); } int siocngetc(dev) dev_t dev; { int c; Port_t iobase; int s; iobase = com_addr(UNIT(dev))->iobase; s = splhigh(); while (!(inb(iobase + com_lsr) & LSR_RXRDY)) ; c = inb(iobase + com_data); (void) inb(iobase + com_iir); splx(s); return (c); } void siocnputc(dev, c) dev_t dev; int c; { Port_t iobase; int s; int timo; iobase = com_addr(UNIT(dev))->iobase; s = splhigh(); #ifdef KGDB if (dev != kgdb_dev) #endif if (!comconsinit) { (void) cominit(UNIT(dev), comdefaultrate); comconsinit = TRUE; } /* wait for any pending transmission to finish */ timo = 50000; while (!(inb(iobase + com_lsr) & LSR_TXRDY) && --timo) ; outb(iobase + com_data, c); /* wait for this transmission to complete */ timo = 1500000; while (!(inb(iobase + com_lsr) & LSR_TXRDY) && --timo) ; /* clear any interrupts generated by this transmission */ (void) inb(iobase + com_iir); splx(s); } /* * 10 Feb 93 Jordan K. Hubbard Added select code * 27 May 93 Rodney W. Grimes Stole the select code from com.c.pl5 */ int sioselect(dev, rw, p) dev_t dev; int rw; struct proc *p; { register struct tty *tp = &sio_tty[UNIT(dev)]; int nread; int s = spltty(); struct proc *selp; switch (rw) { case FREAD: nread = ttnread(tp); if (nread > 0 || ((tp->t_cflag&CLOCAL) == 0 && (tp->t_state&TS_CARR_ON) == 0)) goto win; if (tp->t_rsel && (selp = pfind(tp->t_rsel)) && selp->p_wchan == (caddr_t)&selwait) tp->t_state |= TS_RCOLL; else tp->t_rsel = p->p_pid; break; case FWRITE: if (RB_LEN(&tp->t_out) <= tp->t_lowat) goto win; if (tp->t_wsel && (selp = pfind(tp->t_wsel)) && selp->p_wchan == (caddr_t)&selwait) tp->t_state |= TS_WCOLL; else tp->t_wsel = p->p_pid; break; } splx(s); return (0); win: splx(s); return (1); } #endif /* NSIO > 0 */ Index: head/sys/i386/isa/spkr.c =================================================================== --- head/sys/i386/isa/spkr.c (revision 618) +++ head/sys/i386/isa/spkr.c (revision 619) @@ -1,521 +1,523 @@ /* * spkr.c -- device driver for console speaker on 80386 * * v1.1 by Eric S. Raymond (esr@snark.thyrsus.com) Feb 1990 * modified for 386bsd by Andrew A. Chernov * 386bsd only clean version, all SYSV stuff removed * use hz value from param.c + * + * $Id$ */ #include "speaker.h" #if NSPEAKER > 0 #include "param.h" #include "systm.h" #include "kernel.h" #include "errno.h" #include "buf.h" #include "uio.h" #include "spkr.h" /**************** MACHINE DEPENDENT PART STARTS HERE ************************* * * This section defines a function tone() which causes a tone of given * frequency and duration from the 80x86's console speaker. * Another function endtone() is defined to force sound off, and there is * also a rest() entry point to do pauses. * * Audible sound is generated using the Programmable Interval Timer (PIT) and * Programmable Peripheral Interface (PPI) attached to the 80x86's speaker. The * PPI controls whether sound is passed through at all; the PIT's channel 2 is * used to generate clicks (a square wave) of whatever frequency is desired. */ /* * PIT and PPI port addresses and control values * * Most of the magic is hidden in the TIMER_PREP value, which selects PIT * channel 2, frequency LSB first, square-wave mode and binary encoding. * The encoding is as follows: * * +----------+----------+---------------+-----+ * | 1 0 | 1 1 | 0 1 1 | 0 | * | SC1 SC0 | RW1 RW0 | M2 M1 M0 | BCD | * +----------+----------+---------------+-----+ * Counter Write Mode 3 Binary * Channel 2 LSB first, (Square Wave) Encoding * MSB second */ #define PPI 0x61 /* port of Programmable Peripheral Interface */ #define PPI_SPKR 0x03 /* turn these PPI bits on to pass sound */ #define PIT_CTRL 0x43 /* PIT control address */ #define PIT_COUNT 0x42 /* PIT count address */ #define PIT_MODE 0xB6 /* set timer mode for sound generation */ /* * Magic numbers for timer control. */ #define TIMER_CLK 1193180L /* corresponds to 18.2 MHz tick rate */ static int endtone() /* turn off the speaker, ending current tone */ { wakeup((caddr_t)endtone); outb(PPI, inb(PPI) & ~PPI_SPKR); } static void tone(hz, ticks) /* emit tone of frequency hz for given number of ticks */ unsigned int hz, ticks; { unsigned int divisor = TIMER_CLK / hz; int sps; #ifdef DEBUG printf("tone: hz=%d ticks=%d\n", hz, ticks); #endif /* DEBUG */ /* set timer to generate clicks at given frequency in Hertz */ sps = spltty(); outb(PIT_CTRL, PIT_MODE); /* prepare timer */ outb(PIT_COUNT, (unsigned char) divisor); /* send lo byte */ outb(PIT_COUNT, (divisor >> 8)); /* send hi byte */ splx(sps); /* turn the speaker on */ outb(PPI, inb(PPI) | PPI_SPKR); /* * Set timeout to endtone function, then give up the timeslice. * This is so other processes can execute while the tone is being * emitted. */ timeout((caddr_t)endtone, (caddr_t)NULL, ticks); sleep((caddr_t)endtone, PZERO - 1); } static int endrest() /* end a rest */ { wakeup((caddr_t)endrest); } static void rest(ticks) /* rest for given number of ticks */ int ticks; { /* * Set timeout to endrest function, then give up the timeslice. * This is so other processes can execute while the rest is being * waited out. */ #ifdef DEBUG printf("rest: %d\n", ticks); #endif /* DEBUG */ timeout((caddr_t)endrest, (caddr_t)NULL, ticks); sleep((caddr_t)endrest, PZERO - 1); } /**************** PLAY STRING INTERPRETER BEGINS HERE ********************** * * Play string interpretation is modelled on IBM BASIC 2.0's PLAY statement; * M[LNS] are missing and the ~ synonym and octave-tracking facility is added. * Requires tone(), rest(), and endtone(). String play is not interruptible * except possibly at physical block boundaries. */ typedef int bool; #define TRUE 1 #define FALSE 0 #define toupper(c) ((c) - ' ' * (((c) >= 'a') && ((c) <= 'z'))) #define isdigit(c) (((c) >= '0') && ((c) <= '9')) #define dtoi(c) ((c) - '0') static int octave; /* currently selected octave */ static int whole; /* whole-note time at current tempo, in ticks */ static int value; /* whole divisor for note time, quarter note = 1 */ static int fill; /* controls spacing of notes */ static bool octtrack; /* octave-tracking on? */ static bool octprefix; /* override current octave-tracking state? */ /* * Magic number avoidance... */ #define SECS_PER_MIN 60 /* seconds per minute */ #define WHOLE_NOTE 4 /* quarter notes per whole note */ #define MIN_VALUE 64 /* the most we can divide a note by */ #define DFLT_VALUE 4 /* default value (quarter-note) */ #define FILLTIME 8 /* for articulation, break note in parts */ #define STACCATO 6 /* 6/8 = 3/4 of note is filled */ #define NORMAL 7 /* 7/8ths of note interval is filled */ #define LEGATO 8 /* all of note interval is filled */ #define DFLT_OCTAVE 4 /* default octave */ #define MIN_TEMPO 32 /* minimum tempo */ #define DFLT_TEMPO 120 /* default tempo */ #define MAX_TEMPO 255 /* max tempo */ #define NUM_MULT 3 /* numerator of dot multiplier */ #define DENOM_MULT 2 /* denominator of dot multiplier */ /* letter to half-tone: A B C D E F G */ static int notetab[8] = {9, 11, 0, 2, 4, 5, 7}; /* * This is the American Standard A440 Equal-Tempered scale with frequencies * rounded to nearest integer. Thank Goddess for the good ol' CRC Handbook... * our octave 0 is standard octave 2. */ #define OCTAVE_NOTES 12 /* semitones per octave */ static int pitchtab[] = { /* C C# D D# E F F# G G# A A# B*/ /* 0 */ 65, 69, 73, 78, 82, 87, 93, 98, 103, 110, 117, 123, /* 1 */ 131, 139, 147, 156, 165, 175, 185, 196, 208, 220, 233, 247, /* 2 */ 262, 277, 294, 311, 330, 349, 370, 392, 415, 440, 466, 494, /* 3 */ 523, 554, 587, 622, 659, 698, 740, 784, 831, 880, 932, 988, /* 4 */ 1047, 1109, 1175, 1245, 1319, 1397, 1480, 1568, 1661, 1760, 1865, 1975, /* 5 */ 2093, 2217, 2349, 2489, 2637, 2794, 2960, 3136, 3322, 3520, 3729, 3951, /* 6 */ 4186, 4435, 4698, 4978, 5274, 5588, 5920, 6272, 6644, 7040, 7459, 7902, }; static void playinit() { octave = DFLT_OCTAVE; whole = (hz * SECS_PER_MIN * WHOLE_NOTE) / DFLT_TEMPO; fill = NORMAL; value = DFLT_VALUE; octtrack = FALSE; octprefix = TRUE; /* act as though there was an initial O(n) */ } static void playtone(pitch, value, sustain) /* play tone of proper duration for current rhythm signature */ int pitch, value, sustain; { register int sound, silence, snum = 1, sdenom = 1; /* this weirdness avoids floating-point arithmetic */ for (; sustain; sustain--) { snum *= NUM_MULT; sdenom *= DENOM_MULT; } if (pitch == -1) rest(whole * snum / (value * sdenom)); else { sound = (whole * snum) / (value * sdenom) - (whole * (FILLTIME - fill)) / (value * FILLTIME); silence = whole * (FILLTIME-fill) * snum / (FILLTIME * value * sdenom); #ifdef DEBUG printf("playtone: pitch %d for %d ticks, rest for %d ticks\n", pitch, sound, silence); #endif /* DEBUG */ tone(pitchtab[pitch], sound); if (fill != LEGATO) rest(silence); } } static int abs(n) int n; { if (n < 0) return(-n); else return(n); } static void playstring(cp, slen) /* interpret and play an item from a notation string */ char *cp; size_t slen; { int pitch, lastpitch = OCTAVE_NOTES * DFLT_OCTAVE; #define GETNUM(cp, v) for(v=0; isdigit(cp[1]) && slen > 0; ) \ {v = v * 10 + (*++cp - '0'); slen--;} for (; slen--; cp++) { int sustain, timeval, tempo; register char c = toupper(*cp); #ifdef DEBUG printf("playstring: %c (%x)\n", c, c); #endif /* DEBUG */ switch (c) { case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': /* compute pitch */ pitch = notetab[c - 'A'] + octave * OCTAVE_NOTES; /* this may be followed by an accidental sign */ if (cp[1] == '#' || cp[1] == '+') { ++pitch; ++cp; slen--; } else if (cp[1] == '-') { --pitch; ++cp; slen--; } /* * If octave-tracking mode is on, and there has been no octave- * setting prefix, find the version of the current letter note * closest to the last regardless of octave. */ if (octtrack && !octprefix) { if (abs(pitch-lastpitch) > abs(pitch+OCTAVE_NOTES-lastpitch)) { ++octave; pitch += OCTAVE_NOTES; } if (abs(pitch-lastpitch) > abs((pitch-OCTAVE_NOTES)-lastpitch)) { --octave; pitch -= OCTAVE_NOTES; } } octprefix = FALSE; lastpitch = pitch; /* ...which may in turn be followed by an override time value */ GETNUM(cp, timeval); if (timeval <= 0 || timeval > MIN_VALUE) timeval = value; /* ...and/or sustain dots */ for (sustain = 0; cp[1] == '.'; cp++) { slen--; sustain++; } /* time to emit the actual tone */ playtone(pitch, timeval, sustain); break; case 'O': if (cp[1] == 'N' || cp[1] == 'n') { octprefix = octtrack = FALSE; ++cp; slen--; } else if (cp[1] == 'L' || cp[1] == 'l') { octtrack = TRUE; ++cp; slen--; } else { GETNUM(cp, octave); if (octave >= sizeof(pitchtab) / OCTAVE_NOTES) octave = DFLT_OCTAVE; octprefix = TRUE; } break; case '>': if (octave < sizeof(pitchtab) / OCTAVE_NOTES - 1) octave++; octprefix = TRUE; break; case '<': if (octave > 0) octave--; octprefix = TRUE; break; case 'N': GETNUM(cp, pitch); for (sustain = 0; cp[1] == '.'; cp++) { slen--; sustain++; } playtone(pitch - 1, value, sustain); break; case 'L': GETNUM(cp, value); if (value <= 0 || value > MIN_VALUE) value = DFLT_VALUE; break; case 'P': case '~': /* this may be followed by an override time value */ GETNUM(cp, timeval); if (timeval <= 0 || timeval > MIN_VALUE) timeval = value; for (sustain = 0; cp[1] == '.'; cp++) { slen--; sustain++; } playtone(-1, timeval, sustain); break; case 'T': GETNUM(cp, tempo); if (tempo < MIN_TEMPO || tempo > MAX_TEMPO) tempo = DFLT_TEMPO; whole = (hz * SECS_PER_MIN * WHOLE_NOTE) / tempo; break; case 'M': if (cp[1] == 'N' || cp[1] == 'n') { fill = NORMAL; ++cp; slen--; } else if (cp[1] == 'L' || cp[1] == 'l') { fill = LEGATO; ++cp; slen--; } else if (cp[1] == 'S' || cp[1] == 's') { fill = STACCATO; ++cp; slen--; } break; } } } /******************* UNIX DRIVER HOOKS BEGIN HERE ************************** * * This section implements driver hooks to run playstring() and the tone(), * endtone(), and rest() functions defined above. */ static int spkr_active; /* exclusion flag */ static struct buf *spkr_inbuf; /* incoming buf */ int spkropen(dev) dev_t dev; { #ifdef DEBUG printf("spkropen: entering with dev = %x\n", dev); #endif /* DEBUG */ if (minor(dev) != 0) return(ENXIO); else if (spkr_active) return(EBUSY); else { playinit(); spkr_inbuf = geteblk(DEV_BSIZE); spkr_active = 1; } return(0); } int spkrwrite(dev, uio) dev_t dev; struct uio *uio; { register unsigned n; char *cp; int error; #ifdef DEBUG printf("spkrwrite: entering with dev = %x, count = %d\n", dev, uio->uio_resid); #endif /* DEBUG */ if (minor(dev) != 0) return(ENXIO); else { n = MIN(DEV_BSIZE, uio->uio_resid); cp = spkr_inbuf->b_un.b_addr; error = uiomove(cp, n, uio); if (!error) playstring(cp, n); return(error); } } int spkrclose(dev) dev_t dev; { #ifdef DEBUG printf("spkrclose: entering with dev = %x\n", dev); #endif /* DEBUG */ if (minor(dev) != 0) return(ENXIO); else { endtone(); brelse(spkr_inbuf); spkr_active = 0; } return(0); } int spkrioctl(dev, cmd, cmdarg) dev_t dev; int cmd; caddr_t cmdarg; { #ifdef DEBUG printf("spkrioctl: entering with dev = %x, cmd = %x\n", dev, cmd); #endif /* DEBUG */ if (minor(dev) != 0) return(ENXIO); else if (cmd == SPKRTONE) { tone_t *tp = (tone_t *)cmdarg; if (tp->frequency == 0) rest(tp->duration); else tone(tp->frequency, tp->duration); } else if (cmd == SPKRTUNE) { tone_t *tp = (tone_t *)(*(caddr_t *)cmdarg); tone_t ttp; int error; for (; ; tp++) { error = copyin(tp, &ttp, sizeof(tone_t)); if (error) return(error); if (ttp.duration == 0) break; if (ttp.frequency == 0) rest(ttp.duration); else tone(ttp.frequency, ttp.duration); } } else return(EINVAL); return(0); } #endif /* NSPEAKER > 0 */ /* spkr.c ends here */ Index: head/sys/i386/isa/syscons.c =================================================================== --- head/sys/i386/isa/syscons.c (revision 618) +++ head/sys/i386/isa/syscons.c (revision 619) @@ -1,2416 +1,2414 @@ /*- * 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: @(#)pccons.c 5.11 (Berkeley) 5/21/91 + * from: @(#)syscons.c 1.0 930928 + * $Id$ + * * Heavily modified by Søren Schmidt (sos@login.dkuug.dk) to provide: * * virtual consoles, SYSV ioctl's, ANSI emulation - * - * @(#)syscons.c 1.0 930928 - * Derived from: - * @(#)pccons.c 5.11 (Berkeley) 5/21/91 */ #define STAR_SAVER /* #define FAT_CURSOR /* This breaks on some CGA displays */ #include "param.h" #include "conf.h" #include "ioctl.h" #include "proc.h" #include "user.h" #include "tty.h" #include "uio.h" #include "callout.h" #include "systm.h" #include "kernel.h" #include "syslog.h" #include "errno.h" #include "machine/console.h" #include "malloc.h" #include "i386/isa/icu.h" #include "i386/isa/isa.h" #include "i386/isa/isa_device.h" #include "machine/pc/display.h" #include "i386/i386/cons.h" #include "machine/psl.h" #include "machine/frame.h" #include "sc.h" #include "ddb.h" #include "iso8859.font" #include "kbdtables.h" #if NSC > 0 #ifndef NCONS #define NCONS 12 #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 /* virtual video memory addresses */ #define MONO_BUF (KERNBASE + 0xB0000) #define CGA_BUF (KERNBASE + 0xB8000) #define VGA_BUF (KERNBASE + 0xA0000) #define VIDEOMEM 0x000A0000 #define MEMSIZE 0x00020000 /* misc defines */ #define MAX_ESC_PAR 3 #define TEXT80x25 1 #define TEXT80x50 2 #define COL 80 #define ROW 25 #ifndef XTALSPEED #define XTALSPEED 1193182 /* should be in isa.h */ #endif /* 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 */ typedef struct term_stat { int esc; /* processing escape sequence */ int n_par; /* # of parameters to ESC */ int last_par; /* last parameter # */ int par[MAX_ESC_PAR]; /* contains ESC parameters */ int 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; /* buffer when off screen */ u_short *crtat; /* cursor address */ int posx; /* current X position */ int posy; /* current Y position */ int max_posx; /* X size */ int max_posy; /* X size */ term_stat term; /* terminal emulation stuff */ char cursor_start; /* cursor start line # */ char cursor_end; /* cursor start end # */ 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 default_attr *current_default; static scr_stat cons_scr_stat[NCONS]; static scr_stat *cur_scr_stat = &cons_scr_stat[0]; static scr_stat *new_scp, *old_scp; static term_stat kernel_console; static int switch_in_progress = 0; u_short *Crtat = (u_short *)MONO_BUF; 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; static u_char nlkcnt = 0, clkcnt = 0, slkcnt = 0, alkcnt = 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, nx_scr; static char saved_console = -1; /* saved console number */ static long scrn_blank_time = 0; /* screen saver timout value */ static int scrn_blanked = 0; /* screen saver active flag */ static long scrn_time_stamp; static u_char scr_map[256]; struct tty pccons[NCONS]; struct tty *cur_pccons = &pccons[0]; struct tty *new_pccons; extern int hz; extern struct timeval time; #define CSF_ACTIVE 0x1 /* timeout active */ #define CSF_POLLING 0x2 /* polling for input */ struct pcconsoftc { char cs_flags; char cs_lastc; /* last char sent */ int cs_timo; /* timeouts since interrupt */ u_long cs_wedgecnt; /* times restarted */ } pcconsoftc = {0, 0, 0, 0}; /* special characters */ #define bs 8 #define lf 10 #define cr 13 #define cntlc 3 #define del 0177 #define cntld 4 /* 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); int pcxint(dev_t dev); int pcstart(struct tty *tp); int pccnprobe(struct consdev *cp); int pccninit(struct consdev *cp); int pccnputc(dev_t dev, char c); int pccngetc(dev_t dev); int scintr(dev_t dev, int irq, int cpl); void scrn_saver(int test); static struct tty *get_pccons(dev_t dev); static scr_stat *get_scr_stat(dev_t dev); static int get_scr_num(scr_stat *scp); static void cursor_shape(int start, int end); static void get_cursor_shape(int *start, int *end); static void cursor_pos(void); static void clear_screen(scr_stat *scp); static 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); void consinit(void); static void sput(u_char c); static u_char *get_fstr(u_int c, u_int *len); static update_leds(int which); void reset_cpu(void); u_int sgetc(int noblock); int pcmmap(dev_t dev, int offset, int nprot); int getchar(void); 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 load_font(int segment, int size, char* font); static void save_palette(void); static void load_palette(void); static change_winsize(struct tty *tp, int x, int y); struct isa_driver scdriver = { pcprobe, pcattach, "sc", }; int pcprobe(struct isa_device *dev) { u_char c; int again = 0; /* Enable interrupts and keyboard controller */ kbd_wait(); outb(KB_STAT, KB_WRITE); kbd_cmd(0x4D); /* Start keyboard stuff RESET */ kbd_cmd(KB_RESET); while ((c=inb(KB_DATA)) != KB_ACK) { if ((c == 0xFE) || (c == 0xFF)) { if (!again) printf("KEYBOARD disconnected: RECONNECT \n"); kbd_cmd(KB_RESET); again = 1; } } kbd_wait(); return (IO_KBDSIZE); } int pcattach(struct isa_device *dev) { scr_stat *scp; int start = -1, end = -1, i; 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 (crtc_vga) { #ifdef FAT_CURSOR start = 0; end = 18; #else get_cursor_shape(&start, &end); #endif save_palette(); load_font(0, 16, font_8x16); load_font(1, 8, font_8x8); load_font(2, 14, font_8x14); } current_default = &user_default; for (i = 0; i < NCONS; i++) { scp = &cons_scr_stat[i]; scp->scr = (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.attr = scp->term.std_attr; scp->border = BG_BLACK; scp->cursor_start = start; scp->cursor_end = end; scp->max_posx = COL; scp->max_posy = ROW; scp->bell_pitch = 800; scp->bell_duration = 10; scp->status = 0; scp->pid = 0; scp->proc = NULL; scp->smode.mode = VT_AUTO; if (i > 0) { scp->crt_base = scp->crtat = scp->scr; fillw(scp->term.attr|scr_map[0x20], scp->scr, COL*ROW); } } /* get cursor going */ #ifdef FAT_CURSOR cursor_shape(cons_scr_stat[0].cursor_start, cons_scr_stat[0].cursor_end); #endif cursor_pos(); } static struct tty *get_pccons(dev_t dev) { int i = minor(dev); if (i >= NCONS) return(NULL); return(&pccons[i]); } static scr_stat *get_scr_stat(dev_t dev) { int i = minor(dev); if (i >= NCONS) return(NULL); return(&cons_scr_stat[i]); } static int get_scr_num(scr_stat *scp) /* allways call with legal scp !! */ { int i = 0; while ((i < NCONS) && (cur_scr_stat != &cons_scr_stat[i])) i++; return i; } pcopen(dev_t dev, int flag, int mode, struct proc *p) { struct tty *tp = get_pccons(dev); if (!tp) return(ENXIO); tp->t_oproc = pcstart; tp->t_param = pcparam; tp->t_dev = dev; if ((tp->t_state & TS_ISOPEN) == 0) { tp->t_state |= TS_WOPEN; ttychars(tp); tp->t_iflag = TTYDEF_IFLAG; tp->t_oflag = TTYDEF_OFLAG; tp->t_cflag = TTYDEF_CFLAG; tp->t_lflag = TTYDEF_LFLAG; tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; pcparam(tp, &tp->t_termios); ttsetwater(tp); } else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0) return(EBUSY); tp->t_state |= TS_CARR_ON; return((*linesw[tp->t_line].l_open)(dev, tp)); } pcclose(dev_t dev, int flag, int mode, struct proc *p) { struct tty *tp = get_pccons(dev); struct scr_stat *scp; if (!tp) return(ENXIO); scp = get_scr_stat(tp->t_dev); scp->pid = 0; scp->proc = NULL; scp->smode.mode = VT_AUTO; (*linesw[tp->t_line].l_close)(tp, flag); ttyclose(tp); return(0); } pcread(dev_t dev, struct uio *uio, int flag) { struct tty *tp = get_pccons(dev); if (!tp) return(ENXIO); return((*linesw[tp->t_line].l_read)(tp, uio, flag)); } pcwrite(dev_t dev, struct uio *uio, int flag) { struct tty *tp = get_pccons(dev); if (!tp) return(ENXIO); return((*linesw[tp->t_line].l_write)(tp, uio, flag)); } /* * Got a console interrupt, keyboard action ! * Catch the character, and see who it goes to. */ scintr(dev_t dev, int irq, int cpl) { int c, len; u_char *cp; /* make screensaver happy */ scrn_time_stamp = time.tv_sec; if (scrn_blanked) scrn_saver(0); c = sgetc(1); if (c & 0x100) return; if ((cur_pccons->t_state & TS_ISOPEN) == 0) return; if (pcconsoftc.cs_flags & CSF_POLLING) return; if (c < 0x100) (*linesw[cur_pccons->t_line].l_rint)(c & 0xFF, cur_pccons); else if (cp = get_fstr((u_int)c, (u_int *)&len)) { while (len-- > 0) (*linesw[cur_pccons->t_line].l_rint) (*cp++ & 0xFF, cur_pccons); } } /* * Set line parameters */ 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); } pcioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) { int i, error; struct tty *tp; struct syscframe *fp; scr_stat *scp; tp = get_pccons(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_80x25TEXT: /* set 80x25 text mode */ if (!crtc_vga) return ENXIO; scp->mode = TEXT80x25; scp->max_posy = 25; free(scp->scr, M_DEVBUF); scp->scr = (u_short *)malloc(scp->max_posx*scp->max_posy*2, M_DEVBUF, M_NOWAIT); if (scp != cur_scr_stat) scp->crt_base = scp->scr; set_mode(scp); clear_screen(scp); change_winsize(tp, scp->max_posx, scp->max_posy); return 0; case CONS_80x50TEXT: /* set 80x50 text mode */ if (!crtc_vga) return ENXIO; scp->mode = TEXT80x50; scp->max_posy = 50; free(scp->scr, M_DEVBUF); scp->scr = (u_short *)malloc(scp->max_posx*scp->max_posy*2, M_DEVBUF, M_NOWAIT); if (scp != cur_scr_stat) scp->crt_base = scp->scr; set_mode(scp); clear_screen(scp); change_winsize(tp, scp->max_posx, scp->max_posy); return 0; case CONS_GETVERS: /* get version number */ *(int*)data = 0x100; /* version 1.0 */ return 0; case CONS_GETINFO: /* get current (virtual) console info */ if (*data == sizeof(struct vid_info)) { vid_info_t *ptr = (vid_info_t*)data; ptr->m_num = get_scr_num(scp); ptr->mv_col = scp->posx; ptr->mv_row = scp->posy; ptr->mv_csz = scp->max_posx; ptr->mv_rsz = scp->max_posy; 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++) if (!(pccons[i].t_state & TS_ISOPEN)) { *data = i + 1; return 0; } return EINVAL; /* NOT REACHED */ case VT_GETACTIVE: /* return number of active virtual console */ *data = get_scr_num(scp) + 1; return 0; 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_scr_stat) return 0; while ((error=tsleep(&scp->smode, PZERO|PCATCH, "waitvt", 0)) == ERESTART) ; } else while ((error=tsleep(&cons_scr_stat[*data].smode, PZERO|PCATCH, "waitvt", 0)) == ERESTART) ; return error; case KDENABIO: /* allow io operations */ fp = (struct syscframe *)p->p_regs; fp->sf_eflags |= PSL_IOPL; return 0; case KDDISABIO: /* disallow io operations (default) */ fp = (struct syscframe *)p->p_regs; fp->sf_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) { load_font(0, 16, font_8x16); load_font(1, 8, font_8x8); load_font(2, 14, font_8x14); 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_scr_stat) 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_scr_stat) update_leds(scp->status & LED_MASK); 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 (*(u_char*)data < 0x80) { kbd_cmd(KB_SETRAD); kbd_cmd(*data & 0x7f); return 0; } return EINVAL; 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 */ 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_scr_stat) sysbeep(scp->bell_pitch, scp->bell_duration); return 0; case KIOCSOUND: /* make tone (*data) hz */ if (scp == cur_scr_stat) { if (*(int*)data) { int pitch = XTALSPEED/(*(int*)data); /* enable counter 2 */ outb(0x61, inb(0x61) | 3); /* set command for counter 2, 2 byte write */ outb(0x43, 0xb6); /* set pitch */ outb(0x42, pitch); outb(0x42, (pitch>>8)); } else { /* disable counter 2 */ outb(0x61, inb(0x61) & 0xFC); } } 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_scr_stat) update_leds(scp->status & LED_MASK); 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_8x8, sizeof(font_8x8)); load_font(1, 8, font_8x8); return 0; case GIO_FONT8x8: /* get 8x8 dot font */ if (!crtc_vga) return ENXIO; bcopy(&font_8x8, data, sizeof(font_8x8)); return 0; case PIO_FONT8x14: /* set 8x14 dot font */ if (!crtc_vga) return ENXIO; bcopy(data, &font_8x14, sizeof(font_8x14)); load_font(2, 14, font_8x14); return 0; case GIO_FONT8x14: /* get 8x14 dot font */ if (!crtc_vga) return ENXIO; bcopy(&font_8x14, data, sizeof(font_8x14)); return 0; case PIO_FONT8x16: /* set 8x16 dot font */ if (!crtc_vga) return ENXIO; bcopy(data, &font_8x16, sizeof(font_8x16)); load_font(0, 16, font_8x16); return 0; case GIO_FONT8x16: /* get 8x16 dot font */ if (!crtc_vga) return ENXIO; bcopy(&font_8x16, data, sizeof(font_8x16)); return 0; case CONSOLE_X_MODE_ON: /* just to be compatible */ if (saved_console < 0) { saved_console = get_scr_num(cur_scr_stat); switch_scr(minor(dev)); fp = (struct syscframe *)p->p_regs; fp->sf_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 syscframe *)p->p_regs; fp->sf_eflags &= ~PSL_IOPL; if (crtc_vga) { load_font(0, 16, font_8x16); load_font(1, 8, font_8x8); load_font(2, 14, font_8x14); 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(XTALSPEED/((int*)data)[0], ((int*)data)[1]*hz/3000); else sysbeep(0x31b, hz/4); return 0; default: break; } error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); if (error >= 0) return(error); error = ttioctl(tp, cmd, data, flag); if (error >= 0) return(error); return(ENOTTY); } pcxint(dev_t dev) { pccons[minor(dev)].t_state &= ~TS_BUSY; pcconsoftc.cs_timo = 0; if (pccons[minor(dev)].t_line) (*linesw[pccons[minor(dev)].t_line].l_start) (&pccons[minor(dev)]); else pcstart(&pccons[minor(dev)]); } pcstart(struct tty *tp) { int c, s; scr_stat *scp = get_scr_stat(tp->t_dev); s = spltty(); if (!(tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))) for (;;) { if (RB_LEN(&tp->t_out) <= tp->t_lowat) { if (tp->t_state & TS_ASLEEP) { tp->t_state &= ~TS_ASLEEP; wakeup((caddr_t)&tp->t_out); } if (tp->t_wsel) { selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); tp->t_wsel = 0; tp->t_state &= ~TS_WCOLL; } } if (RB_LEN(&tp->t_out) == 0) break; if (scp->status & SLKED) break; c = getc(&tp->t_out); tp->t_state |= TS_BUSY; splx(s); ansi_put(scp, c); s = spltty(); tp->t_state &= ~TS_BUSY; } splx(s); } pccnprobe(struct consdev *cp) { int maj; /* locate the major number */ for (maj = 0; maj < nchrdev; maj++) if (cdevsw[maj].d_open == pcopen) break; /* initialize required fields */ cp->cn_dev = makedev(maj, 0); cp->cn_tp = &pccons[0]; cp->cn_pri = CN_INTERNAL; } pccninit(struct consdev *cp) { } pccnputc(dev_t dev, char c) { int pos; if (cur_scr_stat->status & UNKNOWN_MODE) return; if (c == '\n') sput('\r'); sput(c); pos = cur_scr_stat->crtat - cur_scr_stat->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); } } pccngetc(dev_t dev) { int c, s; s = spltty(); /* block scintr while we poll */ c = sgetc(0); splx(s); if (c == '\r') c = '\n'; return(c); } #if !defined(STAR_SAVER) && !defined(SNAKE_SAVER) void scrn_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); } } #endif #if defined(STAR_SAVER) || defined(SNAKE_SAVER) static u_long rand_next = 1; static rand() { return ((rand_next = rand_next * 1103515245 + 12345) & 0x7FFFFFFF); } #endif #ifdef STAR_SAVER /* * Alternate saver that got its inspiration from a well known utility * package for an unfamous OS. */ #define NUM_STARS 50 void scrn_saver(int test) { scr_stat *scp = cur_scr_stat; 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, scp->max_posx * scp->max_posy * 2); fillw((FG_LIGHTGREY|BG_BLACK)<<8 | scr_map[0x20], Crtat, scp->max_posx * scp->max_posy); set_border(0); i = scp->max_posy * scp->max_posx + 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; imax_posx*scp->max_posy); stars[i][1] = 0; } } cell = rand() % NUM_STARS; *((u_short*)(Crtat + stars[cell][0])) = scr_map[pattern[stars[cell][1]]] | colors[rand()%sizeof(colors)] << 8; if ((stars[cell][1]+=(rand()%4)) >= sizeof(pattern)-1) { stars[cell][0] = rand() % (scp->max_posx*scp->max_posy); stars[cell][1] = 0; } } else { if (scrn_blanked) { bcopy(scp->scr, Crtat, scp->max_posx*scp->max_posy*2); cur_cursor_pos = -1; set_border(scp->border); scrn_blanked = 0; } } } #endif #ifdef SNAKE_SAVER /* * alternative screen saver for cards that do not like blanking */ void scrn_saver(int test) { const char saves[] = {"FreeBSD"}; static u_char *savs[sizeof(saves)-1]; static int dirx, diry; int f; scr_stat *scp = cur_scr_stat; if (test) { if (!scrn_blanked) { bcopy(Crtat, scp->scr, scp->max_posx * scp->max_posy * 2); fillw((FG_LIGHTGREY|BG_BLACK)<<8 | scr_map[0x20], Crtat, scp->max_posx * scp->max_posy); set_border(0); dirx = (scp->posx ? 1 : -1); diry = (scp->posy ? scp->max_posx : -scp->max_posx); for (f=0; f< sizeof(saves)-1; f++) savs[f] = (u_char *)Crtat + 2 * (scp->posx+scp->posy*scp->max_posx); *(savs[0]) = scr_map[*saves]; f = scp->max_posy * scp->max_posx + 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->max_posx) == 0 || (f % scp->max_posx) == scp->max_posx - 1 || (rand() % 50) == 0) dirx = -dirx; if ((f / scp->max_posx) == 0 || (f / scp->max_posx) == scp->max_posy - 1 || (rand() % 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, Crtat, scp->max_posx * scp->max_posy * 2); cur_cursor_pos = -1; set_border(scp->border); scrn_blanked = 0; } } } #endif 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); } 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; } static void cursor_pos(void) { int pos; if (cur_scr_stat->status & UNKNOWN_MODE) return; if (scrn_blank_time && (time.tv_sec > scrn_time_stamp+scrn_blank_time)) scrn_saver(1); pos = cur_scr_stat->crtat - cur_scr_stat->crt_base; if (!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(cursor_pos, 0, hz/20); } static void clear_screen(scr_stat *scp) { move_crsr(scp, 0, 0); fillw(scp->term.attr | scr_map[0x20], scp->crt_base, scp->max_posx * scp->max_posy); } static switch_scr(u_int next_scr) { if (in_putc) { /* don't switch if in putc */ nx_scr = next_scr+1; return 0; } if (switch_in_progress && (cur_scr_stat->proc != pfind(cur_scr_stat->pid))) switch_in_progress = 0; if (next_scr >= NCONS || switch_in_progress) { sysbeep(800, hz/4); return -1; } switch_in_progress = 1; old_scp = cur_scr_stat; new_scp = &cons_scr_stat[next_scr]; wakeup(&new_scp->smode); if (new_scp == old_scp) { switch_in_progress = 0; return 0; } new_pccons = &pccons[next_scr]; /* 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) { bcopy(Crtat, old_scp->scr, old_scp->max_posx * old_scp->max_posy * 2); old_scp->crt_base = old_scp->scr; move_crsr(old_scp, old_scp->posx, old_scp->posy); cur_scr_stat = new_scp; cur_pccons = new_pccons; if (old_scp->status & KBD_RAW_MODE || new_scp->status & KBD_RAW_MODE) shfts = ctls = alts = 0; update_leds(new_scp->status & LED_MASK); set_mode(new_scp); new_scp->crt_base = Crtat; move_crsr(new_scp, new_scp->posx, new_scp->posy); bcopy(new_scp->scr, Crtat, new_scp->max_posx * new_scp->max_posy * 2); nx_scr = 0; } static void move_crsr(scr_stat *scp, int x, int y) { if (x < 0 || y < 0 || x >= scp->max_posx || y >= scp->max_posy) return; scp->posx = x; scp->posy = y; scp->crtat = scp->crt_base + scp->posy * scp->max_posx + scp->posx; } 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_par = -1; for (i = scp->term.n_par; i < MAX_ESC_PAR; i++) scp->term.par[i] = 1; scp->term.n_par = 0; return; case 'M': /* Move cursor up 1 line, scroll if at top */ if (scp->posy > 0) move_crsr(scp, scp->posx, scp->posy - 1); else { move_up(scp->crt_base, scp->crt_base + scp->max_posx, (scp->max_posy - 1) * scp->max_posx); fillw(scp->term.attr | scr_map[0x20], scp->crt_base, scp->max_posx); } 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.n_par < MAX_ESC_PAR) { if (scp->term.last_par != scp->term.n_par) { scp->term.last_par = scp->term.n_par; scp->term.par[scp->term.n_par] = 0; } else scp->term.par[scp->term.n_par] *= 10; scp->term.par[scp->term.n_par] += c - '0'; return; } } scp->term.n_par = scp->term.last_par + 1; switch (c) { case ';': if (scp->term.n_par < MAX_ESC_PAR) return; break; case '=': scp->term.esc = 3; scp->term.last_par = -1; for (i = scp->term.n_par; i < MAX_ESC_PAR; i++) scp->term.par[i] = 1; scp->term.n_par = 0; return; case 'A': /* up n rows */ n = scp->term.par[0]; if (n < 1) n = 1; move_crsr(scp, scp->posx, scp->posy - n); break; case 'B': /* down n rows */ n = scp->term.par[0]; if (n < 1) n = 1; move_crsr(scp, scp->posx, scp->posy + n); break; case 'C': /* right n columns */ n = scp->term.par[0]; if (n < 1) n = 1; move_crsr(scp, scp->posx + n, scp->posy); break; case 'D': /* left n columns */ n = scp->term.par[0]; if (n < 1) n = 1; move_crsr(scp, scp->posx - n, scp->posy); break; case 'E': /* cursor to start of line n lines down */ n = scp->term.par[0]; if (n < 1) n = 1; move_crsr(scp, 0, scp->posy + n); break; case 'F': /* cursor to start of line n lines up */ n = scp->term.par[0]; if (n < 1) n = 1; move_crsr(scp, 0, scp->posy - n); break; case 'f': /* System V consoles .. */ case 'H': /* Cursor move */ if (scp->term.n_par == 0) move_crsr(scp, 0, 0); else if (scp->term.n_par == 2) move_crsr(scp, scp->term.par[1] - 1, scp->term.par[0] - 1); break; case 'J': /* Clear all or part of display */ if (scp->term.n_par == 0) n = 0; else n = scp->term.par[0]; switch (n) { case 0: /* clear form cursor to end of display */ fillw(scp->term.attr | scr_map[0x20], scp->crtat, scp->crt_base + scp->max_posx * scp->max_posy - scp->crtat); break; case 1: /* clear from beginning of display to cursor */ fillw(scp->term.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.n_par == 0) n = 0; else n = scp->term.par[0]; switch (n) { case 0: /* clear form cursor to end of line */ fillw(scp->term.attr | scr_map[0x20], scp->crtat, scp->max_posx - scp->posx); break; case 1: /* clear from beginning of line to cursor */ fillw(scp->term.attr|scr_map[0x20], scp->crtat - (scp->max_posx - scp->posx), (scp->max_posx - scp->posx) + 1); break; case 2: /* clear entire line */ fillw(scp->term.attr|scr_map[0x20], scp->crtat - (scp->max_posx - scp->posx), scp->max_posx); break; } break; case 'L': /* Insert n lines */ n = scp->term.par[0]; if (n < 1) n = 1; if (n > scp->max_posy - scp->posy) n = scp->max_posy - scp->posy; src = scp->crt_base + scp->posy * scp->max_posx; dst = src + n * scp->max_posx; count = scp->max_posy - (scp->posy + n); move_up(src, dst, count * scp->max_posx); fillw(scp->term.attr | scr_map[0x20], src, n * scp->max_posx); break; case 'M': /* Delete n lines */ n = scp->term.par[0]; if (n < 1) n = 1; if (n > scp->max_posy - scp->posy) n = scp->max_posy - scp->posy; dst = scp->crt_base + scp->posy * scp->max_posx; src = dst + n * scp->max_posx; count = scp->max_posy - (scp->posy + n); move_down(src, dst, count * scp->max_posx); src = dst + count * scp->max_posx; fillw(scp->term.attr | scr_map[0x20], src, n * scp->max_posx); break; case 'P': /* Delete n chars */ n = scp->term.par[0]; if (n < 1) n = 1; if (n > scp->max_posx - scp->posx) n = scp->max_posx - scp->posx; dst = scp->crtat; src = dst + n; count = scp->max_posx - (scp->posx + n); move_down(src, dst, count); src = dst + count; fillw(scp->term.attr | scr_map[0x20], src, n); break; case '@': /* Insert n chars */ n = scp->term.par[0]; if (n < 1) n = 1; if (n > scp->max_posx - scp->posx) n = scp->max_posx - scp->posx; src = scp->crtat; dst = src + n; count = scp->max_posx - (scp->posx + n); move_up(src, dst, count); fillw(scp->term.attr | scr_map[0x20], src, n); break; case 'S': /* scroll up n lines */ n = scp->term.par[0]; if (n < 1) n = 1; bcopy(scp->crt_base + (scp->max_posx * n), scp->crt_base, scp->max_posx * (scp->max_posy - n) * sizeof(u_short)); fillw(scp->term.attr | scr_map[0x20], scp->crt_base + scp->max_posx * (scp->max_posy - 1), scp->max_posx); break; case 'T': /* scroll down n lines */ n = scp->term.par[0]; if (n < 1) n = 1; bcopy(scp->crt_base, scp->crt_base + (scp->max_posx * n), scp->max_posx * (scp->max_posy - n) * sizeof(u_short)); fillw(scp->term.attr | scr_map[0x20], scp->crt_base, scp->max_posx); break; case 'X': /* delete n characters in line */ n = scp->term.par[0]; if (n < 1) n = 1; fillw(scp->term.attr | scr_map[0x20], scp->crt_base + scp->posx + ((scp->max_posx*scp->posy) * sizeof(u_short)), n); break; case 'Z': /* move n tabs backwards */ n = scp->term.par[0]; if (n < 1) n = 1; if ((i = scp->posx & 0xf8) == scp->posx) i -= 8*n; else i -= 8*(n-1); if (i < 0) i = 0; move_crsr(scp, i, scp->posy); break; case '`': /* move cursor to column n */ n = scp->term.par[0]; if (n < 1) n = 1; move_crsr(scp, n, scp->posy); break; case 'a': /* move cursor n columns to the right */ n = scp->term.par[0]; if (n < 1) n = 1; move_crsr(scp, scp->posx + n, scp->posy); break; case 'd': /* move cursor to row n */ n = scp->term.par[0]; if (n < 1) n = 1; move_crsr(scp, scp->posx, n); break; case 'e': /* move cursor n rows down */ n = scp->term.par[0]; if (n < 1) n = 1; move_crsr(scp, scp->posx, scp->posy + n); break; case 'm': /* change attribute */ if (scp->term.n_par == 0) n = 0; else n = scp->term.par[0]; switch (n) { case 0: /* back to normal */ scp->term.attr = scp->term.std_attr; break; case 1: /* highlight (bold) */ scp->term.attr &= 0xFF00; scp->term.attr |= 0x0800; break; case 4: /* highlight (underline) */ scp->term.attr &= 0x0F00; scp->term.attr |= 0x0800; break; case 5: /* blink */ scp->term.attr &= 0xFF00; scp->term.attr |= 0x8000; break; case 7: /* reverse video */ scp->term.attr = scp->term.rev_attr; break; case 30: case 31: case 32: case 33: /* set fg color */ case 34: case 35: case 36: case 37: scp->term.attr = (scp->term.attr & 0xF0FF) | (ansi_col[(n - 30) & 7] << 8); break; case 40: case 41: case 42: case 43: /* set bg color */ case 44: case 45: case 46: case 47: scp->term.attr = (scp->term.attr & 0x0FFF) | (ansi_col[(n - 40) & 7] << 12); break; } break; case 'x': if (scp->term.n_par == 0) n = 0; else n = scp->term.par[0]; switch (n) { case 0: /* reset attributes */ scp->term.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.attr = scp->term.std_attr = (scp->term.std_attr & 0x0F00) | (ansi_col[(scp->term.par[1])&0x0F]<<12); break; case 2: /* set ansi foreground */ scp->term.attr = scp->term.std_attr = (scp->term.std_attr & 0xF000) | (ansi_col[(scp->term.par[1])&0x0F]<<8); break; case 3: /* set ansi attribute directly */ scp->term.attr = scp->term.std_attr = (scp->term.par[1]&0xFF)<<8; break; case 5: /* set ansi reverse video background */ scp->term.rev_attr = (scp->term.rev_attr & 0x0F00) | (ansi_col[(scp->term.par[1])&0x0F]<<12); break; case 6: /* set ansi reverse video foreground */ scp->term.rev_attr = (scp->term.rev_attr & 0xF000) | (ansi_col[(scp->term.par[1])&0x0F]<<8); break; case 7: /* set ansi reverse video directly */ scp->term.rev_attr = (scp->term.par[1]&0xFF)<<8; break; } break; case 'z': /* switch to (virtual) console n */ if (scp->term.n_par == 1) switch_scr(scp->term.par[0]); break; } } else if (scp->term.esc == 3) { if (c >= '0' && c <= '9') { if (scp->term.n_par < MAX_ESC_PAR) { if (scp->term.last_par != scp->term.n_par) { scp->term.last_par = scp->term.n_par; scp->term.par[scp->term.n_par] = 0; } else scp->term.par[scp->term.n_par] *= 10; scp->term.par[scp->term.n_par] += c - '0'; return; } } scp->term.n_par = scp->term.last_par + 1; switch (c) { case ';': if (scp->term.n_par < MAX_ESC_PAR) return; break; case 'A': /* set display border color */ if (scp->term.n_par == 1) scp->border=scp->term.par[0] & 0xff; if (scp == cur_scr_stat) set_border(scp->border); break; case 'B': /* set bell pitch and duration */ if (scp->term.n_par == 2) { scp->bell_pitch = scp->term.par[0]; scp->bell_duration = scp->term.par[1]*10; } break; case 'C': /* set cursor shape (start & end line) */ if (scp->term.n_par == 2) { scp->cursor_start = scp->term.par[0] & 0x1F; scp->cursor_end = scp->term.par[1] & 0x1F; if (scp == cur_scr_stat) cursor_shape(scp->cursor_start, scp->cursor_end); } break; case 'F': /* set ansi foreground */ if (scp->term.n_par == 1) scp->term.attr = scp->term.std_attr = (scp->term.std_attr & 0xF000) | ((scp->term.par[0] & 0x0F) << 8); break; case 'G': /* set ansi background */ if (scp->term.n_par == 1) scp->term.attr = scp->term.std_attr = (scp->term.std_attr & 0x0F00) | ((scp->term.par[0] & 0x0F) << 12); break; case 'H': /* set ansi reverse video foreground */ if (scp->term.n_par == 1) scp->term.rev_attr = (scp->term.rev_attr & 0xF000) | ((scp->term.par[0] & 0x0F) << 8); break; case 'I': /* set ansi reverse video background */ if (scp->term.n_par == 1) scp->term.rev_attr = (scp->term.rev_attr & 0x0F00) | ((scp->term.par[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_scr_stat) { 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.n_par = 0; break; case 0x07: if (scp == cur_scr_stat) sysbeep(scp->bell_pitch, scp->bell_duration); break; case '\t': /* non-destructive tab */ scp->crtat += (8 - scp->posx % 8); scp->posx += (8 - scp->posx % 8); break; case '\b': /* non-destructive backspace */ if (scp->crtat > scp->crt_base) { scp->crtat--; if (scp->posx > 0) scp->posx--; else { scp->posx += scp->max_posx - 1; scp->posy--; } } break; case '\r': /* return to pos 0 */ move_crsr(scp, 0, scp->posy); break; case '\n': /* newline, same pos */ scp->crtat += scp->max_posx; scp->posy++; break; case '\f': /* form feed, clears screen */ clear_screen(scp); break; default: /* Print only printables */ *scp->crtat = (scp->term.attr | scr_map[c]); scp->crtat++; if (++scp->posx >= scp->max_posx) { scp->posx = 0; scp->posy++; } break; } if (scp->crtat >= scp->crt_base + scp->max_posy * scp->max_posx) { bcopy(scp->crt_base + scp->max_posx, scp->crt_base, scp->max_posx * (scp->max_posy - 1) * sizeof(u_short)); fillw(scp->term.attr | scr_map[0x20], scp->crt_base + scp->max_posx * (scp->max_posy - 1), scp->max_posx); scp->crtat -= scp->max_posx; scp->posy--; } in_putc--; if (nx_scr) switch_scr(nx_scr - 1); } void consinit(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 consinit 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; cons_scr_stat[0].crtat = crtat; cons_scr_stat[0].crt_base = Crtat; cons_scr_stat[0].term.esc = 0; cons_scr_stat[0].term.std_attr = current_default->std_attr; cons_scr_stat[0].term.rev_attr = current_default->rev_attr; cons_scr_stat[0].term.attr = current_default->std_attr; cons_scr_stat[0].posx = cursorat % COL; cons_scr_stat[0].posy = cursorat / COL; cons_scr_stat[0].border = BG_BLACK;; cons_scr_stat[0].max_posx = COL; cons_scr_stat[0].max_posy = ROW; cons_scr_stat[0].status = 0; cons_scr_stat[0].pid = 0; cons_scr_stat[0].proc = NULL; cons_scr_stat[0].smode.mode = VT_AUTO; cons_scr_stat[0].bell_pitch = 800; cons_scr_stat[0].bell_duration = 10; kernel_console.esc = 0; kernel_console.std_attr = kernel_default.std_attr; kernel_console.rev_attr = kernel_default.rev_attr; kernel_console.attr = kernel_default.std_attr; /* initialize mapscrn array to */ for (i=0; iterm; scp->term = kernel_console; current_default = &kernel_default; ansi_put(scp, c); kernel_console = scp->term; current_default = &user_default; scp->term = save; } 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 update_leds(int which) { u_char xlate_leds[8] = { 0, 4, 2, 6, 1, 5, 3, 7 }; kbd_cmd(KB_SETLEDS); /* LED Command */ kbd_cmd(xlate_leds[which & LED_MASK]); kbd_wait(); } volatile void reset_cpu(void) { while (1) { kbd_cmd(KB_RESET_CPU); /* Reset Command */ DELAY(4000000); kbd_cmd(KB_RESET); /* Keyboard Reset Command */ } } /* * sgetc(noblock) : get a character from the keyboard. * If noblock = 0 wait until a key is gotten. Otherwise return a 0x100. */ u_int sgetc(int noblock) { u_char val, code, release; 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) val = inb(KB_DATA); else if (noblock) return(0x100); else goto next_code; if (cur_scr_stat->status & KBD_RAW_MODE) return val; code = val & 0x7F; release = val & 0x80; /* Check for cntl-alt-del */ if ((code == 83) && ctls && alts) cpu_reset(); #if NDDB > 0 /* Check for cntl-alt-esc */ if ((val == 1) && ctls && alts) { /* if debugger called, try to switch to console 0 */ if (cur_scr_stat->smode.mode == VT_AUTO && cons_scr_stat[0].smode.mode == VT_AUTO) switch_scr(0); Debugger(); return(0x100); } #endif switch (esc_flag) { case 0x00: /* normal scancode */ switch(code) { case 0x38: /* left alt (compose key) */ if (release && compose) { compose = 0; if (chr > 255) { sysbeep(500, hz/4); chr = 0; } } else { if (!compose) { compose = 1; chr = 0; } } break; case 0x60: case 0x61: esc_flag = code; goto next_code; } break; case 0x60: /* 0xE0 prefix */ esc_flag = 0; switch (code) { case 0x1c: /* right enter key */ code = 0x59; break; case 0x1d: /* right ctrl key */ code = 0x5a; break; case 0x35: /* keypad divide key */ code = 0x5b; break; case 0x37: /* print scrn key */ code = 0x5c; break; case 0x38: /* right alt key (alt gr) */ code = 0x5d; break; case 0x47: /* grey home key */ code = 0x5e; break; case 0x48: /* grey up arrow key */ code = 0x5f; break; case 0x49: /* grey page up key */ code = 0x60; break; case 0x4b: /* grey left arrow key */ code = 0x61; break; case 0x4d: /* grey right arrow key */ code = 0x62; break; case 0x4f: /* grey end key */ code = 0x63; break; case 0x50: /* grey down arrow key */ code = 0x64; break; case 0x51: /* grey page down key */ code = 0x65; break; case 0x52: /* grey insert key */ code = 0x66; break; case 0x53: /* grey delete key */ code = 0x67; break; default: /* ignore everything else */ goto next_code; } break; case 0x61: /* 0xE1 prefix */ esc_flag = 0; if (code == 0x1D) esc_flag = 0x1D; goto next_code; /* NOT REACHED */ case 0x1D: /* pause / break */ esc_flag = 0; if (code != 0x45) goto next_code; code = 0x68; break; } if (compose) { switch (code) { case 0x47: case 0x48: /* keypad 7,8,9 */ case 0x49: if (!release) chr = (code - 0x40) + chr*10; goto next_code; case 0x4b: case 0x4c: /* keypad 4,5,6 */ case 0x4d: if (!release) chr = (code - 0x47) + chr*10; goto next_code; case 0x4f: case 0x50: /* keypad 1,2,3 */ case 0x51: if (!release) chr = (code - 0x4e) + chr*10; goto next_code; case 0x52: /* keypad 0 */ if (!release) chr *= 10; goto next_code; case 0x38: /* left alt key */ break; default: if (chr) { compose = chr = 0; sysbeep(500, hz/4); goto next_code; } break; } } state = (shfts ? 1 : 0 ) | (2 * (ctls ? 1 : 0)) | (4 * (alts ? 1 : 0)); if ((!agrs && (cur_scr_stat->status & ALKED)) || (agrs && !(cur_scr_stat->status & ALKED))) code += ALTGR_OFFSET; key = &key_map.key[code]; if ( ((key->flgs & FLAG_LOCK_C) && (cur_scr_stat->status & CLKED)) || ((key->flgs & FLAG_LOCK_N) && (cur_scr_stat->status & NLKED)) ) state ^= 1; /* Check for make/break */ action = key->map[state]; if (release) { /* 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; } } 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_scr_stat->status & NLKED) cur_scr_stat->status &= ~NLKED; else cur_scr_stat->status |= NLKED; update_leds(cur_scr_stat->status & LED_MASK); } break; case CLK: if (!clkcnt) { clkcnt++; if (cur_scr_stat->status & CLKED) cur_scr_stat->status &= ~CLKED; else cur_scr_stat->status |= CLKED; update_leds(cur_scr_stat->status & LED_MASK); } break; case SLK: if (!slkcnt) { slkcnt++; if (cur_scr_stat->status & SLKED) { cur_scr_stat->status &= ~SLKED; pcstart(&pccons[get_scr_num(cur_scr_stat)]); } else cur_scr_stat->status |= SLKED; update_leds(cur_scr_stat->status & LED_MASK); } break; case ALK: if (!alkcnt) { alkcnt++; if (cur_scr_stat->status & ALKED) cur_scr_stat->status &= ~ALKED; else cur_scr_stat->status |= ALKED; } break; /* NON-LOCKING KEYS */ 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 NOP: break; default: if (action >= F_SCR && action <= L_SCR) { switch_scr(action - F_SCR); break; } if (action >= F_FN && action <= L_FN) { return(action | FKEY); } return(action); } } else return(action); } goto next_code; } /* July '93, jkh. Added in for init_main.c */ void cons_highlight() { cons_scr_stat[0].term.attr &= 0xFF00; cons_scr_stat[0].term.attr |= 0x0800; } void cons_normal() { cons_scr_stat[0].term.attr = cons_scr_stat[0].term.std_attr; } int getchar(void) { char thechar; int s; pcconsoftc.cs_flags |= CSF_POLLING; s = splhigh(); sput('>'); thechar = (char) sgetc(0); pcconsoftc.cs_flags &= ~CSF_POLLING; splx(s); switch (thechar) { default: if (thechar >= scr_map[0x20]) sput(thechar); return(thechar); case cr: case lf: sput(cr); sput(lf); return(lf); case bs: case del: sput(bs); sput(scr_map[0x20]); sput(bs); return(thechar); case cntld: sput('^'); sput('D'); sput('\r'); sput('\n'); return(0); } } 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; for (i=0; i<10000; i++) if ((inb(KB_STAT) & KB_READY) == 0) break; } static void kbd_cmd(u_char command) { kbd_wait(); outb(KB_DATA, command); } static void set_mode(scr_stat *scp) { u_char byte; int s; if (scp != cur_scr_stat) return; /* (re)activate cursor */ untimeout(cursor_pos, 0); cursor_pos(); /* 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: return; } 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 load_font(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++) *((char *)atdevbase+(segment*0x4000)+(ch*32)+line) = font[(ch*size)+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 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 */ Index: head/sys/i386/isa/timerreg.h =================================================================== --- head/sys/i386/isa/timerreg.h (revision 618) +++ head/sys/i386/isa/timerreg.h (revision 619) @@ -1,89 +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. * - * $Header: timerreg.h,v 1.2 93/02/28 15:08:58 mccanne Exp $ + * 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 */ Index: head/sys/i386/isa/vector.s =================================================================== --- head/sys/i386/isa/vector.s (revision 618) +++ head/sys/i386/isa/vector.s (revision 619) @@ -1,376 +1,368 @@ -/* vector.s */ /* - * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE - * -------------------- ----- ---------------------- - * CURRENT PATCH LEVEL: 1 00167 - * -------------------- ----- ---------------------- - * - * 04 Jun 93 Bruce Evans Fixed irq_num vs id_num for multiple - * devices configed on the same irq with - * respect to ipending. - * + * from: vector.s, 386BSD 0.1 unknown origin + * $Id$ */ #include "i386/isa/icu.h" #include "i386/isa/isa.h" #include "vector.h" #define ICU_EOI 0x20 /* XXX - define elsewhere */ #define IRQ_BIT(irq_num) (1 << ((irq_num) % 8)) #define IRQ_BYTE(irq_num) ((irq_num) / 8) #define ENABLE_ICU1 \ movb $ICU_EOI,%al ; /* as soon as possible send EOI ... */ \ FASTER_NOP ; /* ... ASAP ... */ \ outb %al,$IO_ICU1 /* ... to clear in service bit */ #ifdef AUTO_EOI_1 #undef ENABLE_ICU1 /* we now use auto-EOI to reduce i/o */ #define ENABLE_ICU1 #endif #define ENABLE_ICU1_AND_2 \ movb $ICU_EOI,%al ; /* as above */ \ FASTER_NOP ; \ outb %al,$IO_ICU2 ; /* but do second icu first */ \ FASTER_NOP ; \ outb %al,$IO_ICU1 /* then first icu */ #ifdef AUTO_EOI_2 #undef ENABLE_ICU1_AND_2 /* data sheet says no auto-EOI on slave ... */ #define ENABLE_ICU1_AND_2 /* ... but it works */ #endif /* * Macros for interrupt interrupt entry, call to handler, and exit. * * XXX - the interrupt frame is set up to look like a trap frame. This is * usually a waste of time. The only interrupt handlers that want a frame * are the clock handler (it wants a clock frame), the npx handler (it's * easier to do right all in assembler). The interrupt return routine * needs a trap frame for rare AST's (it could easily convert the frame). * The direct costs of setting up a trap frame are two pushl's (error * code and trap number), an addl to get rid of these, and pushing and * popping the call-saved regs %esi, %edi and %ebp twice, The indirect * costs are making the driver interface nonuniform so unpending of * interrupts is more complicated and slower (call_driver(unit) would * be easier than ensuring an interrupt frame for all handlers. Finally, * there are some struct copies in the npx handler and maybe in the clock * handler that could be avoided by working more with pointers to frames * instead of frames. * * XXX - should we do a cld on every system entry to avoid the requirement * for scattered cld's? * * Coding notes for *.s: * * If possible, avoid operations that involve an operand size override. * Word-sized operations might be smaller, but the operand size override * makes them slower on on 486's and no faster on 386's unless perhaps * the instruction pipeline is depleted. E.g., * * Use movl to seg regs instead of the equivalent but more descriptive * movw - gas generates an irelevant (slower) operand size override. * * Use movl to ordinary regs in preference to movw and especially * in preference to movz[bw]l. Use unsigned (long) variables with the * top bits clear instead of unsigned short variables to provide more * opportunities for movl. * * If possible, use byte-sized operations. They are smaller and no slower. * * Use (%reg) instead of 0(%reg) - gas generates larger code for the latter. * * If the interrupt frame is made more flexible, INTR can push %eax first * and decide the ipending case with less overhead, e.g., by avoiding * loading segregs. */ #define FAST_INTR(unit, irq_num, id_num, handler, enable_icus) \ pushl %eax ; /* save only call-used registers */ \ pushl %ecx ; \ pushl %edx ; \ pushl %ds ; \ /* pushl %es ; know compiler doesn't do string insns */ \ movl $KDSEL,%eax ; \ movl %ax,%ds ; \ /* movl %ax,%es ; */ \ SHOW_CLI ; /* although it interferes with "ASAP" */ \ pushl $unit ; \ call handler ; /* do the work ASAP */ \ enable_icus ; /* (re)enable ASAP (helps edge trigger?) */ \ addl $4,%esp ; \ incl _cnt+V_INTR ; /* book-keeping can wait */ \ COUNT_EVENT(_intrcnt_actv, id_num) ; \ SHOW_STI ; \ /* popl %es ; */ \ popl %ds ; \ popl %edx; \ popl %ecx; \ popl %eax; \ iret #define INTR(unit, irq_num, id_num, mask, handler, icu, enable_icus, reg, stray) \ pushl $0 ; /* dummy error code */ \ pushl $T_ASTFLT ; \ pushal ; \ pushl %ds ; /* save our data and extra segments ... */ \ pushl %es ; \ movl $KDSEL,%eax ; /* ... and reload with kernel's own ... */ \ movl %ax,%ds ; /* ... early in case SHOW_A_LOT is on */ \ movl %ax,%es ; \ SHOW_CLI ; /* interrupt did an implicit cli */ \ movb _imen + IRQ_BYTE(irq_num),%al ; \ orb $IRQ_BIT(irq_num),%al ; \ movb %al,_imen + IRQ_BYTE(irq_num) ; \ SHOW_IMEN ; \ FASTER_NOP ; \ outb %al,$icu+1 ; \ enable_icus ; \ incl _cnt+V_INTR ; /* tally interrupts */ \ movl _cpl,%eax ; \ testb $IRQ_BIT(irq_num),%reg ; \ jne 2f ; \ 1: ; \ COUNT_EVENT(_intrcnt_actv, id_num) ; \ movl _cpl,%eax ; \ pushl %eax ; \ pushl $unit ; \ orl mask,%eax ; \ movl %eax,_cpl ; \ SHOW_CPL ; \ SHOW_STI ; \ sti ; \ call handler ; \ movb _imen + IRQ_BYTE(irq_num),%al ; \ andb $~IRQ_BIT(irq_num),%al ; \ movb %al,_imen + IRQ_BYTE(irq_num) ; \ SHOW_IMEN ; \ FASTER_NOP ; \ outb %al,$icu+1 ; \ jmp doreti ; \ ; \ ALIGN_TEXT ; \ 2: ; \ COUNT_EVENT(_intrcnt_pend, id_num) ; \ movl $1b,%eax ; /* register resume address */ \ /* XXX - someday do it at attach time */ \ movl %eax,Vresume + (irq_num) * 4 ; \ orb $IRQ_BIT(irq_num),_ipending + IRQ_BYTE(irq_num) ; \ SHOW_IPENDING ; \ popl %es ; \ popl %ds ; \ popal ; \ addl $4+4,%esp ; \ iret /* * vector.h has defined a macro 'BUILD_VECTORS' containing a big list of info * about vectors, including a submacro 'BUILD_VECTOR' that operates on the * info about each vector. We redefine 'BUILD_VECTOR' to expand the info * in different ways. Here we expand it to a list of interrupt handlers. * This order is of course unimportant. Elsewhere we expand it to inline * linear search code for which the order is a little more important and * concatenating the code with no holes is very important. * * XXX - now there is BUILD_FAST_VECTOR as well as BUILD_VECTOR. * * The info consists of the following items for each vector: * * name (identifier): name of the vector; used to build labels * unit (expression): unit number to call the device driver with * irq_num (number): number of the IRQ to handled (0-15) * id_num (number): uniq numeric id for handler (assigned by config) * mask (blank-ident): priority mask used * handler (blank-ident): interrupt handler to call * icu_num (number): (1 + irq_num / 8) converted for label building * icu_enables (number): 1 for icu_num == 1, 1_AND_2 for icu_num == 2 * reg (blank-ident): al for icu_num == 1, ah for icu_num == 2 * * 'irq_num' is converted in several ways at config time to get around * limitations in cpp. The macros have blanks after commas iff they would * not mess up identifiers and numbers. */ #undef BUILD_FAST_VECTOR #define BUILD_FAST_VECTOR(name, unit, irq_num, id_num, mask, handler, \ icu_num, icu_enables, reg) \ .globl handler ; \ .text ; \ .globl _V/**/name ; \ SUPERALIGN_TEXT ; \ _V/**/name: ; \ FAST_INTR(unit, irq_num, id_num, handler, ENABLE_ICU/**/icu_enables) #undef BUILD_VECTOR #define BUILD_VECTOR(name, unit, irq_num, id_num, mask, handler, \ icu_num, icu_enables, reg) \ .globl handler ; \ .text ; \ .globl _V/**/name ; \ SUPERALIGN_TEXT ; \ _V/**/name: ; \ INTR(unit,irq_num,id_num, mask, handler, IO_ICU/**/icu_num, \ ENABLE_ICU/**/icu_enables, reg,) BUILD_VECTORS /* hardware interrupt catcher (IDT 32 - 47) */ .globl _isa_strayintr #define STRAYINTR(irq_num, icu_num, icu_enables, reg) \ IDTVEC(intr/**/irq_num) ; \ INTR(irq_num,irq_num,irq_num, _highmask, _isa_strayintr, \ IO_ICU/**/icu_num, ENABLE_ICU/**/icu_enables, reg,stray) /* * XXX - the mask (1 << 2) == IRQ_SLAVE will be generated for IRQ 2, instead * of the mask IRQ2 (defined as IRQ9 == (1 << 9)). But IRQ 2 "can't happen". * In fact, all stray interrupts "can't happen" except for bugs. The * "stray" IRQ 7 is documented behaviour of the 8259. It happens when there * is a glitch on any of its interrupt inputs. Does it really interrupt when * IRQ 7 is masked? * * XXX - unpend doesn't work for these, it sends them to the real handler. * * XXX - the race bug during initialization may be because I changed the * order of switching from the stray to the real interrupt handler to before * enabling interrupts. The old order looked unsafe but maybe it is OK with * the stray interrupt handler installed. But these handlers only reduce * the window of vulnerability - it is still open at the end of * isa_configure(). * * XXX - many comments are stale. */ STRAYINTR(0,1,1, al) STRAYINTR(1,1,1, al) STRAYINTR(2,1,1, al) STRAYINTR(3,1,1, al) STRAYINTR(4,1,1, al) STRAYINTR(5,1,1, al) STRAYINTR(6,1,1, al) STRAYINTR(8,2,1_AND_2, ah) STRAYINTR(9,2,1_AND_2, ah) STRAYINTR(10,2,1_AND_2, ah) STRAYINTR(11,2,1_AND_2, ah) STRAYINTR(12,2,1_AND_2, ah) STRAYINTR(13,2,1_AND_2, ah) STRAYINTR(14,2,1_AND_2, ah) STRAYINTR(15,2,1_AND_2, ah) IDTVEC(intrdefault) STRAYINTR(7,1,1, al) /* XXX */ #if 0 INTRSTRAY(255, _highmask, 255) ; call _isa_strayintr ; INTREXIT2 #endif /* * These are the interrupt counters, I moved them here from icu.s so that * they are with the name table. rgrimes * * There are now lots of counters, this has been redone to work with * Bruce Evans intr-0.1 code, which I modified some more to make it all * work with vmstat. */ .data Vresume: .space 16 * 4 /* where to resume intr handler after unpend */ .globl _intrcnt _intrcnt: /* used by vmstat to calc size of table */ .globl _intrcnt_bad7 _intrcnt_bad7: .space 4 /* glitches on irq 7 */ .globl _intrcnt_bad15 _intrcnt_bad15: .space 4 /* glitches on irq 15 */ .globl _intrcnt_stray _intrcnt_stray: .space 4 /* total count of stray interrupts */ .globl _intrcnt_actv _intrcnt_actv: .space NR_REAL_INT_HANDLERS * 4 /* active interrupts */ .globl _intrcnt_pend _intrcnt_pend: .space NR_REAL_INT_HANDLERS * 4 /* pending interrupts */ .globl _eintrcnt _eintrcnt: /* used by vmstat to calc size of table */ .globl _intrcnt_spl _intrcnt_spl: .space 32 * 4 /* XXX 32 should not be hard coded ? */ .globl _intrcnt_show _intrcnt_show: .space 8 * 4 /* XXX 16 should not be hard coded ? */ /* * Build the interrupt name table for vmstat */ #undef BUILD_FAST_VECTOR #define BUILD_FAST_VECTOR BUILD_VECTOR #undef BUILD_VECTOR #define BUILD_VECTOR(name, unit, irq_num, id_num, mask, handler, \ icu_num, icu_enables, reg) \ .ascii "name irq" ; \ .asciz "irq_num" /* * XXX - use the STRING and CONCAT macros from to stringize * and concatenate names above and elsewhere. */ .text .globl _intrnames, _eintrnames _intrnames: BUILD_VECTOR(bad,,7,,,,,,) BUILD_VECTOR(bad,,15,,,,,,) BUILD_VECTOR(stray,,,,,,,,) BUILD_VECTORS #undef BUILD_FAST_VECTOR #define BUILD_FAST_VECTOR BUILD_VECTOR #undef BUILD_VECTOR #define BUILD_VECTOR(name, unit, irq_num, id_num, mask, handler, \ icu_num, icu_enables, reg) \ .asciz "name pend" BUILD_VECTORS _eintrnames: /* * now the spl names */ .asciz "unpend_v" .asciz "doreti" .asciz "p0!ni" .asciz "!p0!ni" .asciz "p0ni" .asciz "netisr_raw" .asciz "netisr_ip" .asciz "netisr_imp" .asciz "netisr_ns" .asciz "netisr_iso" .asciz "softclock" /* 10 */ .asciz "trap" .asciz "doreti_exit2" .asciz "splbio" .asciz "splclock" .asciz "splhigh" .asciz "splimp" .asciz "splnet" .asciz "splsoftclock" .asciz "spltty" .asciz "spl0" /* 20 */ .asciz "netisr_raw2" .asciz "netisr_ip2" .asciz "netisr_imp2" .asciz "netisr_ns2" .asciz "netisr_iso2" .asciz "splx" .asciz "splx!0" .asciz "unpend_V" .asciz "spl29" /* spl29-spl31 are spares */ .asciz "spl30" .asciz "spl31" /* * now the mask names */ .asciz "cli" .asciz "cpl" .asciz "imen" .asciz "ipending" .asciz "sti" .asciz "mask5" /* mask5-mask7 are spares */ .asciz "mask6" .asciz "mask7" Index: head/sys/i386/isa/wd.c =================================================================== --- head/sys/i386/isa/wd.c (revision 618) +++ head/sys/i386/isa/wd.c (revision 619) @@ -1,1362 +1,1341 @@ /*- * 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:@(#)wd.c 7.2 (Berkeley) 5/9/91 - * - * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE - * -------------------- ----- ---------------------- - * CURRENT PATCH LEVEL: 6 00155 - * -------------------- ----- ---------------------- - * - * 17 Sep 92 Frank Maclachlan Fixed I/O error reporting on raw device - * 31 Jul 92 Christoph Robitschko Fixed second disk recognition, - * bzero of malloced memory for warm - * boot problem. - * 19 Aug 92 Frank Maclachlan Fixed bug when first sector of a - * multisector read is in bad144 table. - * 17 Jan 93 B. Evans & A.Chernov Fixed bugs from previous patches, - * driver initialization, and cylinder - * boundary conditions. - * 28 Mar 93 Charles Hannum Add missing splx calls. - * 20 Apr 93 Terry Lee Always report disk errors - * 20 Apr 93 Brett Lymn Change infinite while loops to - * timeouts - * 17 May 93 Rodney W. Grimes Fixed all 1000000 to use WDCTIMEOUT, - * and increased to 1000000*10 for new - * intr-0.1 code. + * from: @(#)wd.c 7.2 (Berkeley) 5/9/91 + * $Id$ */ /* TODO:peel out buffer at low ipl, speed improvement */ #include "wd.h" #if NWD > 0 #include "param.h" #include "dkbad.h" #include "systm.h" #include "conf.h" #include "file.h" #include "stat.h" #include "ioctl.h" #include "disklabel.h" #include "buf.h" #include "uio.h" #include "malloc.h" #include "machine/cpu.h" #include "i386/isa/isa.h" #include "i386/isa/isa_device.h" #include "i386/isa/icu.h" #include "i386/isa/wdreg.h" #include "syslog.h" #include "vm/vm.h" #define _NWD (NWD - 1) /* One is for the controller XXX 31 Jul 92*/ #ifndef WDCTIMEOUT #define WDCTIMEOUT 10000000 /* arbitrary timeout for drive ready waits */ #endif #define RETRIES 5 /* number of retries before giving up */ #define MAXTRANSFER 32 /* max size of transfer in page clusters */ #define wdnoreloc(dev) (minor(dev) & 0x80) /* ignore partition table */ #define wddospart(dev) (minor(dev) & 0x40) /* use dos partitions */ #define wdunit(dev) ((minor(dev) & 0x38) >> 3) #define wdpart(dev) (minor(dev) & 0x7) #define makewddev(maj, unit, part) (makedev(maj,((unit<<3)+part))) #define WDRAW 3 /* 'd' partition isn't a partition! */ #define b_cylin b_resid /* cylinder number for doing IO to */ /* shares an entry in the buf struct */ /* * Drive states. Used to initialize drive. */ #define CLOSED 0 /* disk is closed. */ #define WANTOPEN 1 /* open requested, not started */ #define RECAL 2 /* doing restore */ #define OPEN 3 /* done with open */ /* * The structure of a disk drive. */ struct disk { long dk_bc; /* byte count left */ short dk_skip; /* blocks already transferred */ char dk_unit; /* physical unit number */ char dk_state; /* control state */ u_char dk_status; /* copy of status reg. */ u_char dk_error; /* copy of error reg. */ short dk_port; /* i/o port base */ u_long dk_copenpart; /* character units open on this drive */ u_long dk_bopenpart; /* block units open on this drive */ u_long dk_openpart; /* all units open on this drive */ short dk_wlabel; /* label writable? */ short dk_flags; /* drive characteistics found */ #define DKFL_DOSPART 0x00001 /* has DOS partition table */ #define DKFL_QUIET 0x00002 /* report errors back, but don't complain */ #define DKFL_SINGLE 0x00004 /* sector at a time mode */ #define DKFL_ERROR 0x00008 /* processing a disk error */ #define DKFL_BSDLABEL 0x00010 /* has a BSD disk label */ #define DKFL_BADSECT 0x00020 /* has a bad144 badsector table */ #define DKFL_WRITEPROT 0x00040 /* manual unit write protect */ struct wdparams dk_params; /* ESDI/IDE drive/controller parameters */ struct disklabel dk_dd; /* device configuration data */ struct dos_partition dk_dospartitions[NDOSPART]; /* DOS view of disk */ struct dkbad dk_bad; /* bad sector table */ }; struct disk *wddrives[_NWD]; /* table of units */ struct buf wdtab; struct buf wdutab[_NWD]; /* head of queue per drive */ struct buf rwdbuf[_NWD]; /* buffers for raw IO */ long wdxfer[_NWD]; /* count of transfers */ #ifdef WDDEBUG int wddebug; #endif struct isa_driver wddriver = { wdprobe, wdattach, "wd", }; static void wdustart(struct disk *); static void wdstart(); static int wdcommand(struct disk *, int); static int wdcontrol(struct buf *); static int wdsetctlr(dev_t, struct disk *); static int wdgetctlr(int, struct disk *); /* * Probe for controller. */ int wdprobe(struct isa_device *dvp) { int unit = dvp->id_unit; struct disk *du; int wdc; if (unit >= _NWD) /* 31 Jul 92*/ return(0); if ((du = wddrives[unit]) == 0) { du = wddrives[unit] = (struct disk *) malloc (sizeof(struct disk), M_TEMP, M_NOWAIT); bzero (du, sizeof(struct disk)); /* 31 Jul 92*/ du->dk_unit = unit; } wdc = du->dk_port = dvp->id_iobase; /* check if we have registers that work */ outb(wdc+wd_cyl_lo, 0xa5) ; /* wd_cyl_lo is read/write */ if(inb(wdc+wd_cyl_lo) != 0xa5) goto nodevice; /* reset the device */ outb(wdc+wd_ctlr, (WDCTL_RST|WDCTL_IDS)); DELAY(1000); outb(wdc+wd_ctlr, WDCTL_IDS); DELAY(1000); /* execute a controller only command */ if (wdcommand(du, WDCC_DIAGNOSE) < 0) goto nodevice; (void) inb(wdc+wd_error); /* XXX! */ outb(wdc+wd_ctlr, WDCTL_4BIT); return (IO_WDCSIZE); nodevice: free(du, M_TEMP); wddrives[unit] = 0; return (0); } /* * Attach each drive if possible. */ int wdattach(struct isa_device *dvp) { int unit; /* int unit = dvp->id_unit;*/ for (unit=0; unit< _NWD; unit++) { struct disk *du; if ((du = wddrives[unit]) == 0) { du = wddrives[unit] = (struct disk *) malloc (sizeof(struct disk), M_TEMP, M_NOWAIT); bzero (du, sizeof(struct disk)); du->dk_unit = unit; du->dk_port = dvp->id_iobase; } /* print out description of drive, suppressing multiple blanks*/ if(wdgetctlr(unit, du) == 0) { int i, blank; char c; printf("wd%d: unit %d type ", unit, unit); for (i = blank = 0 ; i < sizeof(du->dk_params.wdp_model); i++) { char c = du->dk_params.wdp_model[i]; if (blank && c == ' ') continue; if (blank && c != ' ') { printf(" %c", c); blank = 0; continue; } if (c == ' ') blank = 1; else printf("%c", c); } printf("\n"); du->dk_unit = unit; } } return(1); } /* Read/write routine for a buffer. Finds the proper unit, range checks * arguments, and schedules the transfer. Does not wait for the transfer * to complete. Multi-page transfers are supported. All I/O requests must * be a multiple of a sector in length. */ int wdstrategy(register struct buf *bp) { register struct buf *dp; struct disklabel *lp; register struct partition *p; struct disk *du; /* Disk unit to do the IO. */ long maxsz, sz; int unit = wdunit(bp->b_dev); int s; /* valid unit, controller, and request? */ if (unit >= _NWD || bp->b_blkno < 0 || (du = wddrives[unit]) == 0) { bp->b_error = EINVAL; bp->b_flags |= B_ERROR; goto done; } /* "soft" write protect check */ if ((du->dk_flags & DKFL_WRITEPROT) && (bp->b_flags & B_READ) == 0) { bp->b_error = EROFS; bp->b_flags |= B_ERROR; goto done; } /* have partitions and want to use them? */ if ((du->dk_flags & DKFL_BSDLABEL) != 0 && wdpart(bp->b_dev) != WDRAW) { /* * do bounds checking, adjust transfer. if error, process. * if end of partition, just return */ if (bounds_check_with_label(bp, &du->dk_dd, du->dk_wlabel) <= 0) goto done; /* otherwise, process transfer request */ } q: /* queue transfer on drive, activate drive and controller if idle */ dp = &wdutab[unit]; s = splbio(); disksort(dp, bp); if (dp->b_active == 0) wdustart(du); /* start drive */ if (wdtab.b_active == 0) wdstart(s); /* start controller */ splx(s); return; done: /* toss transfer, we're done early */ biodone(bp); } /* * Routine to queue a command to the controller. The unit's * request is linked into the active list for the controller. * If the controller is idle, the transfer is started. */ static void wdustart(register struct disk *du) { register struct buf *bp, *dp = &wdutab[du->dk_unit]; /* unit already active? */ if (dp->b_active) return; /* anything to start? */ bp = dp->b_actf; if (bp == NULL) return; /* link onto controller queue */ dp->b_forw = NULL; if (wdtab.b_actf == NULL) wdtab.b_actf = dp; else wdtab.b_actl->b_forw = dp; wdtab.b_actl = dp; /* mark the drive unit as busy */ dp->b_active = 1; } /* * Controller startup routine. This does the calculation, and starts * a single-sector read or write operation. Called to start a transfer, * or from the interrupt routine to continue a multi-sector transfer. * RESTRICTIONS: * 1. The transfer length must be an exact multiple of the sector size. */ static void wdstart() { register struct disk *du; /* disk unit for IO */ register struct buf *bp; struct disklabel *lp; struct buf *dp; register struct bt_bad *bt_ptr; long blknum, pagcnt, cylin, head, sector; long secpertrk, secpercyl, addr, i, timeout; int unit, s, wdc; loop: /* is there a drive for the controller to do a transfer with? */ dp = wdtab.b_actf; if (dp == NULL) return; /* is there a transfer to this drive ? if so, link it on the controller's queue */ bp = dp->b_actf; if (bp == NULL) { wdtab.b_actf = dp->b_forw; goto loop; } /* obtain controller and drive information */ unit = wdunit(bp->b_dev); du = wddrives[unit]; /* if not really a transfer, do control operations specially */ if (du->dk_state < OPEN) { (void) wdcontrol(bp); return; } /* calculate transfer details */ blknum = bp->b_blkno + du->dk_skip; /*if(wddebug)printf("bn%d ", blknum);*/ #ifdef WDDEBUG if (du->dk_skip == 0) printf("\nwdstart %d: %s %d@%d; map ", unit, (bp->b_flags & B_READ) ? "read" : "write", bp->b_bcount, blknum); else printf(" %d)%x", du->dk_skip, inb(wdc+wd_altsts)); #endif addr = (int) bp->b_un.b_addr; if (du->dk_skip == 0) du->dk_bc = bp->b_bcount; lp = &du->dk_dd; secpertrk = lp->d_nsectors; secpercyl = lp->d_secpercyl; if ((du->dk_flags & DKFL_BSDLABEL) != 0 && wdpart(bp->b_dev) != WDRAW) blknum += lp->d_partitions[wdpart(bp->b_dev)].p_offset; cylin = blknum / secpercyl; head = (blknum % secpercyl) / secpertrk; sector = blknum % secpertrk; /* * See if the current block is in the bad block list. * (If we have one, and not formatting.) */ if ((du->dk_flags & (DKFL_SINGLE|DKFL_BADSECT)) /* 19 Aug 92*/ == (DKFL_SINGLE|DKFL_BADSECT)) /* XXX * BAD144END was done to clean up some old bad code that was * attempting to compare a u_short to -1. This makes the compilers * happy and clearly shows what is going on. * rgrimes 93/06/17 */ #define BAD144END (u_short)(-1) for (bt_ptr = du->dk_bad.bt_bad; bt_ptr->bt_cyl != BAD144END; bt_ptr++) { if (bt_ptr->bt_cyl > cylin) /* Sorted list, and we passed our cylinder. quit. */ break; if (bt_ptr->bt_cyl == cylin && bt_ptr->bt_trksec == (head << 8) + sector) { /* * Found bad block. Calculate new block addr. * This starts at the end of the disk (skip the * last track which is used for the bad block list), * and works backwards to the front of the disk. */ #ifdef WDDEBUG printf("--- badblock code -> Old = %d; ", blknum); #endif blknum = lp->d_secperunit - lp->d_nsectors - (bt_ptr - du->dk_bad.bt_bad) - 1; cylin = blknum / secpercyl; head = (blknum % secpercyl) / secpertrk; sector = blknum % secpertrk; #ifdef WDDEBUG printf("new = %d\n", blknum); #endif break; } } /*if(wddebug)pg("c%d h%d s%d ", cylin, head, sector);*/ sector += 1; /* sectors begin with 1, not 0 */ wdtab.b_active = 1; /* mark controller active */ wdc = du->dk_port; RETRY: /* if starting a multisector transfer, or doing single transfers */ if (du->dk_skip == 0 || (du->dk_flags & DKFL_SINGLE)) { if (wdtab.b_errcnt && (bp->b_flags & B_READ) == 0) du->dk_bc += DEV_BSIZE; /* controller idle? */ timeout = 0; while (inb(wdc+wd_status) & WDCS_BUSY) { if (++timeout > WDCTIMEOUT) { printf("wd.c: Controller busy too long!\n"); /* reset the device */ outb(wdc+wd_ctlr, (WDCTL_RST|WDCTL_IDS)); DELAY(1000); outb(wdc+wd_ctlr, WDCTL_IDS); DELAY(1000); (void) inb(wdc+wd_error); /* XXX! */ outb(wdc+wd_ctlr, WDCTL_4BIT); break; } } /* stuff the task file */ outb(wdc+wd_precomp, lp->d_precompcyl / 4); #ifdef B_FORMAT if (bp->b_flags & B_FORMAT) { outb(wdc+wd_sector, lp->d_gap3); outb(wdc+wd_seccnt, lp->d_nsectors); } else { #endif if (du->dk_flags & DKFL_SINGLE) outb(wdc+wd_seccnt, 1); else outb(wdc+wd_seccnt, howmany(du->dk_bc, DEV_BSIZE)); outb(wdc+wd_sector, sector); #ifdef B_FORMAT } #endif outb(wdc+wd_cyl_lo, cylin); outb(wdc+wd_cyl_hi, cylin >> 8); /* set up the SDH register (select drive) */ outb(wdc+wd_sdh, WDSD_IBM | (unit<<4) | (head & 0xf)); /* wait for drive to become ready */ timeout = 0; while ((inb(wdc+wd_status) & WDCS_READY) == 0) { if (++timeout > WDCTIMEOUT) { printf("wd.c: Drive busy too long!\n"); /* reset the device */ outb(wdc+wd_ctlr, (WDCTL_RST|WDCTL_IDS)); DELAY(1000); outb(wdc+wd_ctlr, WDCTL_IDS); DELAY(1000); (void) inb(wdc+wd_error); /* XXX! */ outb(wdc+wd_ctlr, WDCTL_4BIT); goto RETRY; } } /* initiate command! */ #ifdef B_FORMAT if (bp->b_flags & B_FORMAT) outb(wdc+wd_command, WDCC_FORMAT); else #endif outb(wdc+wd_command, (bp->b_flags & B_READ)? WDCC_READ : WDCC_WRITE); #ifdef WDDEBUG printf("sector %d cylin %d head %d addr %x sts %x\n", sector, cylin, head, addr, inb(wdc+wd_altsts)); #endif } /* if this is a read operation, just go away until it's done. */ if (bp->b_flags & B_READ) return; /* ready to send data? */ timeout = 0; while ((inb(wdc+wd_status) & WDCS_DRQ) == 0) { if (++timeout > WDCTIMEOUT) { printf("wd.c: Drive not ready for too long!\n"); /* reset the device */ outb(wdc+wd_ctlr, (WDCTL_RST|WDCTL_IDS)); DELAY(1000); outb(wdc+wd_ctlr, WDCTL_IDS); DELAY(1000); (void) inb(wdc+wd_error); /* XXX! */ outb(wdc+wd_ctlr, WDCTL_4BIT); goto RETRY; } } /* then send it! */ outsw (wdc+wd_data, addr+du->dk_skip * DEV_BSIZE, DEV_BSIZE/sizeof(short)); du->dk_bc -= DEV_BSIZE; } /* Interrupt routine for the controller. Acknowledge the interrupt, check for * errors on the current operation, mark it done if necessary, and start * the next request. Also check for a partially done transfer, and * continue with the next chunk if so. */ void wdintr(struct intrframe wdif) { register struct disk *du; register struct buf *bp, *dp; int status, wdc; char partch ; if (!wdtab.b_active) { #ifdef nyet printf("wd: extra interrupt\n"); #endif return; } dp = wdtab.b_actf; bp = dp->b_actf; du = wddrives[wdunit(bp->b_dev)]; wdc = du->dk_port; #ifdef WDDEBUG printf("I "); #endif while ((status = inb(wdc+wd_status)) & WDCS_BUSY) ; /* is it not a transfer, but a control operation? */ if (du->dk_state < OPEN) { if (wdcontrol(bp)) wdstart(); return; } /* have we an error? */ if (status & (WDCS_ERR | WDCS_ECCCOR)) { du->dk_status = status; du->dk_error = inb(wdc + wd_error); #ifdef WDDEBUG printf("status %x error %x\n", status, du->dk_error); #endif if((du->dk_flags & DKFL_SINGLE) == 0) { du->dk_flags |= DKFL_ERROR; goto outt; } #ifdef B_FORMAT if (bp->b_flags & B_FORMAT) { bp->b_error = EIO; /* 17 Sep 92*/ bp->b_flags |= B_ERROR; goto done; } #endif /* error or error correction? */ if (status & WDCS_ERR) { if (++wdtab.b_errcnt < RETRIES) { wdtab.b_active = 0; } else { diskerr(bp, "wd", "hard error", LOG_PRINTF, du->dk_skip, &du->dk_dd); #ifdef WDDEBUG printf( "status %b error %b\n", status, WDCS_BITS, inb(wdc+wd_error), WDERR_BITS); #endif bp->b_error = EIO; /* 17 Sep 92*/ bp->b_flags |= B_ERROR; /* flag the error */ } } else { diskerr(bp, "wd", "soft ecc", 0, du->dk_skip, &du->dk_dd); } } outt: /* * If this was a successful read operation, fetch the data. */ if (((bp->b_flags & (B_READ | B_ERROR)) == B_READ) && wdtab.b_active) { int chk, dummy; chk = min(DEV_BSIZE / sizeof(short), du->dk_bc / sizeof(short)); /* ready to receive data? */ while ((inb(wdc+wd_status) & WDCS_DRQ) == 0) ; /* suck in data */ insw (wdc+wd_data, (int)bp->b_un.b_addr + du->dk_skip * DEV_BSIZE, chk); du->dk_bc -= chk * sizeof(short); /* for obselete fractional sector reads */ while (chk++ < 256) insw (wdc+wd_data, &dummy, 1); } wdxfer[du->dk_unit]++; if (wdtab.b_active) { if ((bp->b_flags & B_ERROR) == 0) { du->dk_skip++; /* Add to successful sectors. */ if (wdtab.b_errcnt) diskerr(bp, "wd", "soft error", 0, du->dk_skip, &du->dk_dd); wdtab.b_errcnt = 0; /* see if more to transfer */ if (du->dk_bc > 0 && (du->dk_flags & DKFL_ERROR) == 0) { wdstart(); return; /* next chunk is started */ } else if ((du->dk_flags & (DKFL_SINGLE|DKFL_ERROR)) == DKFL_ERROR) { du->dk_skip = 0; du->dk_flags &= ~DKFL_ERROR; du->dk_flags |= DKFL_SINGLE; wdstart(); return; /* redo xfer sector by sector */ } } done: /* done with this transfer, with or without error */ du->dk_flags &= ~DKFL_SINGLE; wdtab.b_actf = dp->b_forw; wdtab.b_errcnt = 0; du->dk_skip = 0; dp->b_active = 0; dp->b_actf = bp->av_forw; dp->b_errcnt = 0; bp->b_resid = 0; biodone(bp); } /* controller idle */ wdtab.b_active = 0; /* anything more on drive queue? */ if (dp->b_actf) wdustart(du); /* anything more for controller to do? */ if (wdtab.b_actf) wdstart(); } /* * Initialize a drive. */ int wdopen(dev_t dev, int flags, int fmt, struct proc *p) { register unsigned int unit; register struct disk *du; int part = wdpart(dev), mask = 1 << part; struct partition *pp; struct dkbad *db; int i, error = 0; char *msg; unit = wdunit(dev); if (unit >= _NWD) return (ENXIO) ; du = wddrives[unit]; if (du == 0) return (ENXIO) ; if ((du->dk_flags & DKFL_BSDLABEL) == 0) { du->dk_flags |= DKFL_WRITEPROT; wdutab[unit].b_actf = NULL; /* * Use the default sizes until we've read the label, * or longer if there isn't one there. */ bzero(&du->dk_dd, sizeof(du->dk_dd)); #undef d_type /* fix goddamn segments.h! XXX */ du->dk_dd.d_type = DTYPE_ST506; du->dk_dd.d_ncylinders = 1024; du->dk_dd.d_secsize = DEV_BSIZE; du->dk_dd.d_ntracks = 8; du->dk_dd.d_nsectors = 17; du->dk_dd.d_secpercyl = 17*8; du->dk_state = WANTOPEN; du->dk_unit = unit; /* read label using "c" partition */ if (msg = readdisklabel(makewddev(major(dev), wdunit(dev), WDRAW), wdstrategy, &du->dk_dd, du->dk_dospartitions, &du->dk_bad, 0)) { log(LOG_WARNING, "wd%d: cannot find label (%s)\n", unit, msg); if (part != WDRAW) error = EINVAL; /* XXX needs translation */ goto done; } else { wdsetctlr(dev, du); du->dk_flags |= DKFL_BSDLABEL; du->dk_flags &= ~DKFL_WRITEPROT; if (du->dk_dd.d_flags & D_BADSECT) du->dk_flags |= DKFL_BADSECT; } done: if (error) return(error); } /* * Warn if a partion is opened * that overlaps another partition which is open * unless one is the "raw" partition (whole disk). */ if ((du->dk_openpart & mask) == 0 /*&& part != RAWPART*/ && part != WDRAW) { int start, end; pp = &du->dk_dd.d_partitions[part]; start = pp->p_offset; end = pp->p_offset + pp->p_size; for (pp = du->dk_dd.d_partitions; pp < &du->dk_dd.d_partitions[du->dk_dd.d_npartitions]; pp++) { if (pp->p_offset + pp->p_size <= start || pp->p_offset >= end) continue; /*if (pp - du->dk_dd.d_partitions == RAWPART) continue; */ if (pp - du->dk_dd.d_partitions == WDRAW) continue; if (du->dk_openpart & (1 << (pp - du->dk_dd.d_partitions))) log(LOG_WARNING, "wd%d%c: overlaps open partition (%c)\n", unit, part + 'a', pp - du->dk_dd.d_partitions + 'a'); } } if (part >= du->dk_dd.d_npartitions && part != WDRAW) return (ENXIO); /* insure only one open at a time */ du->dk_openpart |= mask; switch (fmt) { case S_IFCHR: du->dk_copenpart |= mask; break; case S_IFBLK: du->dk_bopenpart |= mask; break; } return (0); } /* * Implement operations other than read/write. * Called from wdstart or wdintr during opens and formats. * Uses finite-state-machine to track progress of operation in progress. * Returns 0 if operation still in progress, 1 if completed. */ static int wdcontrol(register struct buf *bp) { register struct disk *du; register unit; unsigned char stat; int s, cnt; extern int bootdev; int cyl, trk, sec, i, wdc; struct wdparams foo; du = wddrives[wdunit(bp->b_dev)]; unit = du->dk_unit; wdc = du->dk_port; switch (du->dk_state) { tryagainrecal: case WANTOPEN: /* set SDH, step rate, do restore */ #ifdef WDDEBUG printf("wd%d: recal ", unit); #endif s = splbio(); /* not called from intr level ... */ wdgetctlr(unit, du); outb(wdc+wd_sdh, WDSD_IBM | (unit << 4)); wdtab.b_active = 1; /* wait for drive and controller to become ready */ for (i = WDCTIMEOUT; (inb(wdc+wd_status) & (WDCS_READY|WDCS_BUSY)) != WDCS_READY && i-- != 0; ) ; outb(wdc+wd_command, WDCC_RESTORE | WD_STEP); du->dk_state++; splx(s); return(0); case RECAL: if ((stat = inb(wdc+wd_status)) & WDCS_ERR) { printf("wd%d: recal", du->dk_unit); printf(": status %b error %b\n", stat, WDCS_BITS, inb(wdc+wd_error), WDERR_BITS); if (++wdtab.b_errcnt < RETRIES) { du->dk_state = WANTOPEN; goto tryagainrecal; } bp->b_error = ENXIO; /* XXX needs translation */ goto badopen; } /* some controllers require this ... */ wdsetctlr(bp->b_dev, du); wdtab.b_errcnt = 0; du->dk_state = OPEN; /* * The rest of the initialization can be done * by normal means. */ return(1); default: panic("wdcontrol"); } /* NOTREACHED */ badopen: printf(": status %b error %b\n", stat, WDCS_BITS, inb(wdc + wd_error), WDERR_BITS); bp->b_flags |= B_ERROR; return(1); } /* * send a command and wait uninterruptibly until controller is finished. * return -1 if controller busy for too long, otherwise * return status. intended for brief controller commands at critical points. * assumes interrupts are blocked. */ static int wdcommand(struct disk *du, int cmd) { int timeout = WDCTIMEOUT, stat, wdc; /* controller ready for command? */ wdc = du->dk_port; while (((stat = inb(wdc + wd_status)) & WDCS_BUSY) && timeout > 0) timeout--; if (timeout <= 0) return(-1); /* send command, await results */ outb(wdc+wd_command, cmd); while (((stat = inb(wdc+wd_status)) & WDCS_BUSY) && timeout > 0) timeout--; if (timeout <= 0) return(-1); if (cmd != WDCC_READP) return (stat); /* is controller ready to return data? */ while (((stat = inb(wdc+wd_status)) & (WDCS_ERR|WDCS_DRQ)) == 0 && timeout > 0) timeout--; if (timeout <= 0) return(-1); return (stat); } /* * issue IDC to drive to tell it just what geometry it is to be. */ static int wdsetctlr(dev_t dev, struct disk *du) { int stat, x, wdc; /*printf("C%dH%dS%d ", du->dk_dd.d_ncylinders, du->dk_dd.d_ntracks, du->dk_dd.d_nsectors);*/ x = splbio(); wdc = du->dk_port; outb(wdc+wd_cyl_lo, du->dk_dd.d_ncylinders+1); outb(wdc+wd_cyl_hi, (du->dk_dd.d_ncylinders+1)>>8); outb(wdc+wd_sdh, WDSD_IBM | (wdunit(dev) << 4) + du->dk_dd.d_ntracks-1); outb(wdc+wd_seccnt, du->dk_dd.d_nsectors); stat = wdcommand(du, WDCC_IDC); if (stat < 0) { splx(x); return(stat); } if (stat & WDCS_ERR) printf("wdsetctlr: status %b error %b\n", stat, WDCS_BITS, inb(wdc+wd_error), WDERR_BITS); splx(x); return(stat); } /* * issue READP to drive to ask it what it is. */ static int wdgetctlr(int u, struct disk *du) { int stat, x, i, wdc; char tb[DEV_BSIZE]; struct wdparams *wp; x = splbio(); /* not called from intr level ... */ wdc = du->dk_port; outb(wdc+wd_sdh, WDSD_IBM | (u << 4)); stat = wdcommand(du, WDCC_READP); if (stat < 0) { splx(x); return(stat); } /* * If WDCC_READP fails then we might have an old ST506 type drive * so we try a seek to 0; if that passes then the * drive is there but it's OLD AND KRUSTY */ if (stat & WDCS_ERR) { stat = wdcommand(du, WDCC_RESTORE | WD_STEP); if (stat & WDCS_ERR) { stat = inb(wdc+wd_error); splx(x); return(stat); } strncpy(du->dk_dd.d_typename, "ST506", sizeof du->dk_dd.d_typename); strncpy(du->dk_params.wdp_model, "Unknown Type", sizeof du->dk_params.wdp_model); du->dk_dd.d_type = DTYPE_ST506; splx(x); return(0); } /* obtain parameters */ wp = &du->dk_params; insw(wdc+wd_data, tb, sizeof(tb)/sizeof(short)); bcopy(tb, wp, sizeof(struct wdparams)); /* shuffle string byte order */ for (i=0; i < sizeof(wp->wdp_model) ;i+=2) { u_short *p; p = (u_short *) (wp->wdp_model + i); *p = ntohs(*p); } /*printf("gc %x cyl %d trk %d sec %d type %d sz %d model %s\n", wp->wdp_config, wp->wdp_fixedcyl+wp->wdp_removcyl, wp->wdp_heads, wp->wdp_sectors, wp->wdp_cntype, wp->wdp_cnsbsz, wp->wdp_model);*/ /* update disklabel given drive information */ du->dk_dd.d_ncylinders = wp->wdp_fixedcyl + wp->wdp_removcyl /*+- 1*/; du->dk_dd.d_ntracks = wp->wdp_heads; du->dk_dd.d_nsectors = wp->wdp_sectors; du->dk_dd.d_secpercyl = du->dk_dd.d_ntracks * du->dk_dd.d_nsectors; du->dk_dd.d_partitions[1].p_size = du->dk_dd.d_secpercyl * wp->wdp_sectors; du->dk_dd.d_partitions[1].p_offset = 0; /* dubious ... */ bcopy("ESDI/IDE", du->dk_dd.d_typename, 9); bcopy(wp->wdp_model+20, du->dk_dd.d_packname, 14-1); /* better ... */ du->dk_dd.d_type = DTYPE_ESDI; du->dk_dd.d_subtype |= DSTYPE_GEOMETRY; /* XXX sometimes possibly needed */ (void) inb(wdc+wd_status); return (0); } /* ARGSUSED */ int wdclose(dev_t dev, int flags, int fmt) { register struct disk *du; int part = wdpart(dev), mask = 1 << part; du = wddrives[wdunit(dev)]; /* insure only one open at a time */ du->dk_openpart &= ~mask; switch (fmt) { case S_IFCHR: du->dk_copenpart &= ~mask; break; case S_IFBLK: du->dk_bopenpart &= ~mask; break; } return(0); } int wdioctl(dev_t dev, int cmd, caddr_t addr, int flag) { int unit = wdunit(dev); register struct disk *du; int error = 0; struct uio auio; struct iovec aiov; du = wddrives[unit]; switch (cmd) { case DIOCSBAD: if ((flag & FWRITE) == 0) error = EBADF; else du->dk_bad = *(struct dkbad *)addr; break; case DIOCGDINFO: *(struct disklabel *)addr = du->dk_dd; break; case DIOCGPART: ((struct partinfo *)addr)->disklab = &du->dk_dd; ((struct partinfo *)addr)->part = &du->dk_dd.d_partitions[wdpart(dev)]; break; case DIOCSDINFO: if ((flag & FWRITE) == 0) error = EBADF; else error = setdisklabel(&du->dk_dd, (struct disklabel *)addr, /*(du->dk_flags & DKFL_BSDLABEL) ? du->dk_openpart : */0, du->dk_dospartitions); if (error == 0) { du->dk_flags |= DKFL_BSDLABEL; wdsetctlr(dev, du); } break; case DIOCWLABEL: du->dk_flags &= ~DKFL_WRITEPROT; if ((flag & FWRITE) == 0) error = EBADF; else du->dk_wlabel = *(int *)addr; break; case DIOCWDINFO: du->dk_flags &= ~DKFL_WRITEPROT; if ((flag & FWRITE) == 0) error = EBADF; else if ((error = setdisklabel(&du->dk_dd, (struct disklabel *)addr, /*(du->dk_flags & DKFL_BSDLABEL) ? du->dk_openpart :*/ 0, du->dk_dospartitions)) == 0) { int wlab; du->dk_flags |= DKFL_BSDLABEL; wdsetctlr(dev, du); /* simulate opening partition 0 so write succeeds */ du->dk_openpart |= (1 << 0); /* XXX */ wlab = du->dk_wlabel; du->dk_wlabel = 1; error = writedisklabel(dev, wdstrategy, &du->dk_dd, du->dk_dospartitions); du->dk_openpart = du->dk_copenpart | du->dk_bopenpart; du->dk_wlabel = wlab; } break; #ifdef notyet case DIOCGDINFOP: *(struct disklabel **)addr = &(du->dk_dd); break; case DIOCWFORMAT: if ((flag & FWRITE) == 0) error = EBADF; else { register struct format_op *fop; fop = (struct format_op *)addr; aiov.iov_base = fop->df_buf; aiov.iov_len = fop->df_count; auio.uio_iov = &aiov; auio.uio_iovcnt = 1; auio.uio_resid = fop->df_count; auio.uio_segflg = 0; auio.uio_offset = fop->df_startblk * du->dk_dd.d_secsize; error = physio(wdformat, &rwdbuf[unit], dev, B_WRITE, minphys, &auio); fop->df_count -= auio.uio_resid; fop->df_reg[0] = du->dk_status; fop->df_reg[1] = du->dk_error; } break; #endif default: error = ENOTTY; break; } return (error); } #ifdef B_FORMAT int wdformat(struct buf *bp) { bp->b_flags |= B_FORMAT; return (wdstrategy(bp)); } #endif int wdsize(dev_t dev) { int unit = wdunit(dev), part = wdpart(dev), val = 0; struct disk *du; if (unit >= _NWD) /* 31 Jul 92*/ return(-1); du = wddrives[unit]; if (du == 0 || du->dk_state == 0) val = wdopen (makewddev(major(dev), unit, WDRAW), FREAD, S_IFBLK, 0); if (du == 0 || val != 0 || du->dk_flags & DKFL_WRITEPROT) return (-1); return((int)du->dk_dd.d_partitions[part].p_size); } extern char *vmmap; /* poor name! */ int wddump(dev_t dev) /* dump core after a system crash */ { register struct disk *du; /* disk unit to do the IO */ register struct bt_bad *bt_ptr; long num; /* number of sectors to write */ int unit, part, wdc; long blkoff, blknum, blkcnt; long cylin, head, sector, stat; long secpertrk, secpercyl, nblocks, i; char *addr; extern int Maxmem; static wddoingadump = 0 ; extern caddr_t CADDR1; addr = (char *) 0; /* starting address */ /* toss any characters present prior to dump */ while (sgetc(1)) ; /* size of memory to dump */ num = Maxmem; unit = wdunit(dev); /* eventually support floppies? */ part = wdpart(dev); /* file system */ /* check for acceptable drive number */ if (unit >= _NWD) return(ENXIO); /* 31 Jul 92*/ du = wddrives[unit]; if (du == 0) return(ENXIO); /* was it ever initialized ? */ if (du->dk_state < OPEN) return (ENXIO) ; if (du->dk_flags & DKFL_WRITEPROT) return(ENXIO); wdc = du->dk_port; /* Convert to disk sectors */ num = (u_long) num * NBPG / du->dk_dd.d_secsize; /* check if controller active */ /*if (wdtab.b_active) return(EFAULT); */ if (wddoingadump) return(EFAULT); secpertrk = du->dk_dd.d_nsectors; secpercyl = du->dk_dd.d_secpercyl; nblocks = du->dk_dd.d_partitions[part].p_size; blkoff = du->dk_dd.d_partitions[part].p_offset; /*pg("xunit %x, nblocks %d, dumplo %d num %d\n", part,nblocks,dumplo,num);*/ /* check transfer bounds against partition size */ if ((dumplo < 0) || ((dumplo + num) > nblocks)) return(EINVAL); /*wdtab.b_active = 1; /* mark controller active for if we panic during the dump */ wddoingadump = 1 ; i = 100000 ; while ((inb(wdc+wd_status) & WDCS_BUSY) && (i-- > 0)) ; outb(wdc+wd_sdh, WDSD_IBM | (unit << 4)); outb(wdc+wd_command, WDCC_RESTORE | WD_STEP); while (inb(wdc+wd_status) & WDCS_BUSY) ; /* some compaq controllers require this ... */ wdsetctlr(dev, du); blknum = dumplo + blkoff; while (num > 0) { #ifdef notdef if (blkcnt > MAXTRANSFER) blkcnt = MAXTRANSFER; if ((blknum + blkcnt - 1) / secpercyl != blknum / secpercyl) blkcnt = secpercyl - (blknum % secpercyl); /* keep transfer within current cylinder */ #endif pmap_enter(kernel_pmap, CADDR1, trunc_page(addr), VM_PROT_READ, TRUE); /* compute disk address */ cylin = blknum / secpercyl; head = (blknum % secpercyl) / secpertrk; sector = blknum % secpertrk; #ifdef notyet /* * See if the current block is in the bad block list. * (If we have one.) */ for (bt_ptr = du->dk_bad.bt_bad; bt_ptr->bt_cyl != -1; bt_ptr++) { if (bt_ptr->bt_cyl > cylin) /* Sorted list, and we passed our cylinder. quit. */ break; if (bt_ptr->bt_cyl == cylin && bt_ptr->bt_trksec == (head << 8) + sector) { /* * Found bad block. Calculate new block addr. * This starts at the end of the disk (skip the * last track which is used for the bad block list), * and works backwards to the front of the disk. */ blknum = (du->dk_dd.d_secperunit) - du->dk_dd.d_nsectors - (bt_ptr - du->dk_bad.bt_bad) - 1; cylin = blknum / secpercyl; head = (blknum % secpercyl) / secpertrk; sector = blknum % secpertrk; break; } #endif sector++; /* origin 1 */ /* select drive. */ outb(wdc+wd_sdh, WDSD_IBM | (unit<<4) | (head & 0xf)); while ((inb(wdc+wd_status) & WDCS_READY) == 0) ; /* transfer some blocks */ outb(wdc+wd_sector, sector); outb(wdc+wd_seccnt,1); outb(wdc+wd_cyl_lo, cylin); outb(wdc+wd_cyl_hi, cylin >> 8); #ifdef notdef /* lets just talk about this first...*/ pg ("sdh 0%o sector %d cyl %d addr 0x%x", inb(wdc+wd_sdh), inb(wdc+wd_sector), inb(wdc+wd_cyl_hi)*256+inb(wdc+wd_cyl_lo), addr) ; #endif outb(wdc+wd_command, WDCC_WRITE); /* Ready to send data? */ while ((inb(wdc+wd_status) & WDCS_DRQ) == 0) ; if (inb(wdc+wd_status) & WDCS_ERR) return(EIO) ; outsw (wdc+wd_data, CADDR1+((int)addr&(NBPG-1)), 256); if (inb(wdc+wd_status) & WDCS_ERR) return(EIO) ; /* Check data request (should be done). */ if (inb(wdc+wd_status) & WDCS_DRQ) return(EIO) ; /* wait for completion */ for ( i = WDCTIMEOUT ; inb(wdc+wd_status) & WDCS_BUSY ; i--) { if (i < 0) return (EIO) ; } /* error check the xfer */ if (inb(wdc+wd_status) & WDCS_ERR) return(EIO) ; if ((unsigned)addr % (1024*1024) == 0) printf("%d ", num/2048) ; /* update block count */ num--; blknum++ ; (int) addr += 512; /* operator aborting dump? */ if (sgetc(1)) return(EINTR); } return(0); } #endif Index: head/sys/i386/isa/wdreg.h =================================================================== --- head/sys/i386/isa/wdreg.h (revision 618) +++ head/sys/i386/isa/wdreg.h (revision 619) @@ -1,143 +1,144 @@ /*- * Copyright (c) 1991 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. * - * @(#)wdreg.h 7.1 (Berkeley) 5/9/91 + * from: @(#)wdreg.h 7.1 (Berkeley) 5/9/91 + * $Id$ */ /* * Disk Controller register definitions. */ #define wd_data 0x0 /* data register (R/W - 16 bits) */ #define wd_error 0x1 /* error register (R) */ #define wd_precomp wd_error /* write precompensation (W) */ #define wd_seccnt 0x2 /* sector count (R/W) */ #define wd_sector 0x3 /* first sector number (R/W) */ #define wd_cyl_lo 0x4 /* cylinder address, low byte (R/W) */ #define wd_cyl_hi 0x5 /* cylinder address, high byte (R/W)*/ #define wd_sdh 0x6 /* sector size/drive/head (R/W)*/ #define wd_command 0x7 /* command register (W) */ #define wd_status wd_command /* immediate status (R) */ #define wd_altsts 0x206 /*alternate fixed disk status(via 1015) (R)*/ #define wd_ctlr 0x206 /*fixed disk controller control(via 1015) (W)*/ #define WDCTL_4BIT 0x8 /* use four head bits (wd1003) */ #define WDCTL_RST 0x4 /* reset the controller */ #define WDCTL_IDS 0x2 /* disable controller interrupts */ #define wd_digin 0x207 /* disk controller input(via 1015) (R)*/ /* * Status Bits. */ #define WDCS_BUSY 0x80 /* Controller busy bit. */ #define WDCS_READY 0x40 /* Selected drive is ready */ #define WDCS_WRTFLT 0x20 /* Write fault */ #define WDCS_SEEKCMPLT 0x10 /* Seek complete */ #define WDCS_DRQ 0x08 /* Data request bit. */ #define WDCS_ECCCOR 0x04 /* ECC correction made in data */ #define WDCS_INDEX 0x02 /* Index pulse from selected drive */ #define WDCS_ERR 0x01 /* Error detect bit. */ #define WDCS_BITS "\020\010busy\006rdy\006wrtflt\005seekdone\004drq\003ecc_cor\002index\001err" #define WDERR_BITS "\020\010badblk\007uncorr\006id_crc\005no_id\003abort\002tr000\001no_dam" /* * Commands for Disk Controller. */ #define WDCC_RESTORE 0x10 /* disk restore code -- resets cntlr */ #define WDCC_READ 0x20 /* disk read code */ #define WDCC_WRITE 0x30 /* disk write code */ #define WDCC__LONG 0x02 /* modifier -- access ecc bytes */ #define WDCC__NORETRY 0x01 /* modifier -- no retrys */ #define WDCC_FORMAT 0x50 /* disk format code */ #define WDCC_DIAGNOSE 0x90 /* controller diagnostic */ #define WDCC_IDC 0x91 /* initialize drive command */ #define WDCC_EXTDCMD 0xE0 /* send extended command */ #define WDCC_READP 0xEC /* read parameters from controller */ #define WDCC_CACHEC 0xEF /* cache control */ #define WD_STEP 0 /* winchester- default 35us step */ #define WDSD_IBM 0xa0 /* forced to 512 byte sector, ecc */ #ifdef KERNEL /* * read parameters command returns this: */ struct wdparams { /* drive info */ short wdp_config; /* general configuration */ short wdp_fixedcyl; /* number of non-removable cylinders */ short wdp_removcyl; /* number of removable cylinders */ short wdp_heads; /* number of heads */ short wdp_unfbytespertrk; /* number of unformatted bytes/track */ short wdp_unfbytes; /* number of unformatted bytes/sector */ short wdp_sectors; /* number of sectors */ short wdp_minisg; /* minimum bytes in inter-sector gap*/ short wdp_minplo; /* minimum bytes in postamble */ short wdp_vendstat; /* number of words of vendor status */ /* controller info */ char wdp_cnsn[20]; /* controller serial number */ short wdp_cntype; /* controller type */ #define WDTYPE_SINGLEPORTSECTOR 1 /* single port, single sector buffer */ #define WDTYPE_DUALPORTMULTI 2 /* dual port, multiple sector buffer */ #define WDTYPE_DUALPORTMULTICACHE 3 /* above plus track cache */ short wdp_cnsbsz; /* sector buffer size, in sectors */ short wdp_necc; /* ecc bytes appended */ char wdp_rev[8]; /* firmware revision */ char wdp_model[40]; /* model name */ short wdp_nsecperint; /* sectors per interrupt */ short wdp_usedmovsd; /* can use double word read/write? */ }; /* * wd driver entry points */ int wdprobe(struct isa_device *); int wdattach(struct isa_device *); int wdstrategy(struct buf *); void wdintr(struct intrframe); int wdopen(dev_t, int, int, struct proc *); int wdclose(dev_t dev, int flags, int fmt); int wdioctl(dev_t, int, caddr_t, int); /* int wdformat(struct buf *bp); */ int wdsize(dev_t); int wddump(dev_t); #endif KERNEL Index: head/sys/i386/isa/wt.c =================================================================== --- head/sys/i386/isa/wt.c (revision 618) +++ head/sys/i386/isa/wt.c (revision 619) @@ -1,820 +1,821 @@ /* * Streamer tape driver for 386bsd and FreeBSD. * Supports Archive QIC-02 and Wangtek QIC-02/QIC-36 boards. * * Copyright (C) 1993 by: * Sergey Ryzhkov * Serge Vakulenko * - * Version 1.1, Fri Sep 24 02:14:31 MSD 1993 - * * Placed in the public domain with NO WARRANTIES, not even the implied * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * Authors grant any other persons or organisations permission to use * or modify this software as long as this message is kept with the software, * all derivative works or modified versions. * * This driver is derived from the old 386bsd Wangtek streamer tape driver, * made by Robert Baron at CMU, based on Intel sources. * Authors thank Robert Baron, CMU and Intel and retain here * the original CMU copyright notice. + * + * from: Version 1.1, Fri Sep 24 02:14:31 MSD 1993 + * $Id$ */ /* * Copyright (c) 1989 Carnegie-Mellon University. * All rights reserved. * * Authors: Robert Baron * * Permission to use, copy, modify and distribute this software and * its documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. */ #include "wt.h" #if NWT > 0 #include "sys/param.h" #include "sys/buf.h" #include "sys/fcntl.h" #include "sys/malloc.h" #include "sys/ioctl.h" #include "sys/mtio.h" #include "vm/vm_param.h" #include "i386/include/pio.h" #include "i386/isa/isa_device.h" #include "i386/isa/wtreg.h" #define WTPRI (PZERO+10) /* sleep priority */ #define BLKSIZE 512 /* streamer tape block size */ /* * Wangtek controller ports */ #define WT_CTLPORT(base) ((base)+0) /* control, write only */ #define WT_STATPORT(base) ((base)+0) /* status, read only */ #define WT_CMDPORT(base) ((base)+1) /* command, write only */ #define WT_DATAPORT(base) ((base)+1) /* data, read only */ #define WT_NPORT 2 /* 2 i/o ports */ /* status port bits */ #define WT_BUSY 0x01 /* not ready bit define */ #define WT_NOEXCEP 0x02 /* no exception bit define */ #define WT_RESETMASK 0x07 /* to check after reset */ #define WT_RESETVAL 0x05 /* state after reset */ /* control port bits */ #define WT_ONLINE 0x01 /* device selected */ #define WT_RESET 0x02 /* reset command */ #define WT_REQUEST 0x04 /* request command */ #define WT_IEN(chan) ((chan)>2 ? 0x10 : 0x8) /* enable intr */ /* * Archive controller ports */ #define AV_DATAPORT(base) ((base)+0) /* data, read only */ #define AV_CMDPORT(base) ((base)+0) /* command, write only */ #define AV_STATPORT(base) ((base)+1) /* status, read only */ #define AV_CTLPORT(base) ((base)+1) /* control, write only */ #define AV_SDMAPORT(base) ((base)+2) /* start dma */ #define AV_RDMAPORT(base) ((base)+3) /* reset dma */ #define AV_NPORT 4 /* 4 i/o ports */ /* status port bits */ #define AV_BUSY 0x40 /* not ready bit define */ #define AV_NOEXCEP 0x20 /* no exception bit define */ #define AV_RESETMASK 0xf8 /* to check after reset */ #define AV_RESETVAL 0x50 /* state after reset */ /* control port bits */ #define AV_RESET 0x80 /* reset command */ #define AV_REQUEST 0x40 /* request command */ #define AV_IEN 0x20 /* enable interrupts */ #define DMA_STATUSREG 0x8 #define DMA_DONE(chan) (1 << (chan)) typedef struct { unsigned short err; /* code for error encountered */ unsigned short ercnt; /* number of error blocks */ unsigned short urcnt; /* number of underruns */ } wtstatus_t; typedef struct { unsigned unit; /* unit number */ unsigned port; /* base i/o port */ unsigned chan; /* dma channel number, 1..3 */ unsigned flags; /* state of tape drive */ unsigned dens; /* tape density */ void *buf; /* internal i/o buffer */ void *dmavaddr; /* virtual address of dma i/o buffer */ unsigned dmatotal; /* size of i/o buffer */ unsigned dmaflags; /* i/o direction, B_READ or B_WRITE */ unsigned dmacount; /* resulting length of dma i/o */ wtstatus_t error; /* status of controller */ unsigned short DATAPORT, CMDPORT, STATPORT, CTLPORT, SDMAPORT, RDMAPORT; unsigned char BUSY, NOEXCEP, RESETMASK, RESETVAL; unsigned char ONLINE, RESET, REQUEST, IEN; } wtinfo_t; wtinfo_t wttab[NWT]; /* tape info by unit number */ extern int hz; /* number of ticks per second */ static int wtwait (wtinfo_t *t, int catch, char *msg); static int wtcmd (wtinfo_t *t, int cmd); static int wtstart (wtinfo_t *t, unsigned mode, void *vaddr, unsigned len); static void wtdma (wtinfo_t *t); static void wtimer (wtinfo_t *t); static void wtclock (wtinfo_t *t); static int wtreset (wtinfo_t *t); static int wtsense (wtinfo_t *t, int ignor); static int wtstatus (wtinfo_t *t); static void wtrewind (wtinfo_t *t); static int wtreadfm (wtinfo_t *t); static int wtwritefm (wtinfo_t *t); static int wtpoll (wtinfo_t *t); extern void DELAY (int usec); extern void bcopy (void *from, void *to, unsigned len); extern void isa_dmastart (int flags, void *addr, unsigned len, unsigned chan); extern void isa_dmadone (int flags, void *addr, unsigned len, int chan); extern void printf (char *str, ...); extern int splbio (void); extern int splx (int level); extern void timeout (void (*func) (), void *arg, int timo); extern int tsleep (void *chan, int priority, char *msg, int timo); extern void wakeup (void *chan); /* * Probe for the presence of the device. */ int wtprobe (struct isa_device *id) { wtinfo_t *t = wttab + id->id_unit; t->unit = id->id_unit; t->chan = id->id_drq; t->port = 0; /* Mark it as not configured. */ if (t->chan<1 || t->chan>3) { printf ("wt%d: Bad drq=%d, should be 1..3\n", t->unit, t->chan); return (0); } t->port = id->id_iobase; /* Try Wangtek. */ t->CTLPORT = WT_CTLPORT (t->port); t->STATPORT = WT_STATPORT (t->port); t->CMDPORT = WT_CMDPORT (t->port); t->DATAPORT = WT_DATAPORT (t->port); t->SDMAPORT = 0; t->RDMAPORT = 0; t->BUSY = WT_BUSY; t->NOEXCEP = WT_NOEXCEP; t->RESETMASK = WT_RESETMASK; t->RESETVAL = WT_RESETVAL; t->ONLINE = WT_ONLINE; t->RESET = WT_RESET; t->REQUEST = WT_REQUEST; t->IEN = WT_IEN (t->chan); if (wtreset (t)) return (WT_NPORT); /* Try Archive. */ t->CTLPORT = AV_CTLPORT (t->port); t->STATPORT = AV_STATPORT (t->port); t->CMDPORT = AV_CMDPORT (t->port); t->DATAPORT = AV_DATAPORT (t->port); t->SDMAPORT = AV_SDMAPORT (t->port); t->RDMAPORT = AV_RDMAPORT (t->port); t->BUSY = AV_BUSY; t->NOEXCEP = AV_NOEXCEP; t->RESETMASK = AV_RESETMASK; t->RESETVAL = AV_RESETVAL; t->ONLINE = 0; t->RESET = AV_RESET; t->REQUEST = AV_REQUEST; t->IEN = AV_IEN; if (wtreset (t)) return (AV_NPORT); /* Tape controller not found. */ t->port = 0; return (0); } /* * Device is found, configure it. */ int wtattach (struct isa_device *id) { wtinfo_t *t = wttab + id->id_unit; if (t->RDMAPORT) { printf ("wt%d: type \n", t->unit); outb (t->RDMAPORT, 0); /* reset dma */ } else printf ("wt%d: type \n", t->unit); t->flags = TPSTART; /* tape is rewound */ t->dens = -1; /* unknown density */ t->buf = malloc (BLKSIZE, M_TEMP, M_NOWAIT); return (1); } struct isa_driver wtdriver = { wtprobe, wtattach, "wt", }; int wtdump (int dev) { /* Not implemented */ return (EINVAL); } int wtsize (int dev) { /* Not implemented */ return (-1); } /* * Open routine, called on every device open. */ int wtopen (int dev, int flag) { int u = minor (dev) & T_UNIT; wtinfo_t *t = wttab + u; int error; if (u >= NWT || !t->port) return (ENXIO); /* Check that device is not in use */ if (t->flags & TPINUSE) return (EBUSY); /* If the tape is in rewound state, check the status and set density. */ if (t->flags & TPSTART) { /* If rewind is going on, wait */ error = wtwait (t, PCATCH, "wtrew"); if (error) return (error); if (! wtsense (t, (flag & FWRITE) ? 0 : TP_WRP)) { /* Bad status. Reset the controller. */ if (! wtreset (t)) return (ENXIO); if (! wtsense (t, (flag & FWRITE) ? 0 : TP_WRP)) return (ENXIO); } /* Set up tape density. */ if (t->dens != (minor (dev) & T_DENSEL)) { int d; switch (minor (dev) & T_DENSEL) { default: case T_800BPI: d = QIC_FMT150; break; /* minor 000 */ case T_1600BPI: d = QIC_FMT120; break; /* minor 010 */ case T_6250BPI: d = QIC_FMT24; break; /* minor 020 */ case T_BADBPI: d = QIC_FMT11; break; /* minor 030 */ } if (! wtcmd (t, d)) return (ENXIO); /* Check the status of the controller. */ if (! wtsense (t, (flag & FWRITE) ? 0 : TP_WRP)) return (ENXIO); t->dens = minor (dev) & T_DENSEL; } t->flags &= ~TPSTART; } else if (t->dens != (minor (dev) & T_DENSEL)) return (ENXIO); t->flags = TPINUSE; if (flag & FREAD) t->flags |= TPREAD; if (flag & FWRITE) t->flags |= TPWRITE; return (0); } /* * Close routine, called on last device close. */ int wtclose (int dev) { int u = minor (dev) & T_UNIT; wtinfo_t *t = wttab + u; if (u >= NWT || !t->port) return (ENXIO); /* If rewind is pending, do nothing */ if (t->flags & TPREW) goto done; /* If seek forward is pending and no rewind on close, do nothing */ if ((t->flags & TPRMARK) && (minor (dev) & T_NOREWIND)) goto done; /* If file mark read is going on, wait */ wtwait (t, 0, "wtrfm"); if (t->flags & TPWANY) /* Tape was written. Write file mark. */ wtwritefm (t); if (! (minor (dev) & T_NOREWIND)) { /* Rewind tape to beginning of tape. */ /* Don't wait until rewind, though. */ wtrewind (t); goto done; } if ((t->flags & TPRANY) && ! (t->flags & (TPVOL | TPWANY))) /* Space forward to after next file mark if no writing done. */ /* Don't wait for completion. */ wtreadfm (t); done: t->flags &= TPREW | TPRMARK | TPSTART | TPTIMER; return (0); } /* * Ioctl routine. Compatible with BSD ioctls. * Direct QIC-02 commands ERASE and RETENSION added. * There are three possible ioctls: * ioctl (int fd, MTIOCGET, struct mtget *buf) -- get status * ioctl (int fd, MTIOCTOP, struct mtop *buf) -- do BSD-like op * ioctl (int fd, WTQICMD, int qicop) -- do QIC op */ int wtioctl (int dev, int cmd, void *arg, int mode) { int u = minor (dev) & T_UNIT; wtinfo_t *t = wttab + u; int error, count, op; if (u >= NWT || !t->port) return (ENXIO); switch (cmd) { default: return (EINVAL); case WTQICMD: /* direct QIC command */ op = (int) *(void**)arg; switch (op) { default: return (EINVAL); case QIC_ERASE: /* erase the whole tape */ if (! (t->flags & TPWRITE) || (t->flags & TPWP)) return (EACCES); if (error = wtwait (t, PCATCH, "wterase")) return (error); break; case QIC_RETENS: /* retension the tape */ if (error = wtwait (t, PCATCH, "wtretens")) return (error); break; } /* Both ERASE and RETENS operations work like REWIND. */ /* Simulate the rewind operation here. */ t->flags &= ~(TPRO | TPWO | TPVOL); if (! wtcmd (t, op)) return (EIO); t->flags |= TPSTART | TPREW; if (op == QIC_ERASE) t->flags |= TPWANY; wtclock (t); return (0); case MTIOCIEOT: /* ignore EOT errors */ case MTIOCEEOT: /* enable EOT errors */ return (0); case MTIOCGET: ((struct mtget*)arg)->mt_type = t->RDMAPORT ? MT_ISVIPER1 : 0x11; ((struct mtget*)arg)->mt_dsreg = t->flags; /* status */ ((struct mtget*)arg)->mt_erreg = t->error.err; /* errors */ ((struct mtget*)arg)->mt_resid = 0; ((struct mtget*)arg)->mt_fileno = 0; /* file */ ((struct mtget*)arg)->mt_blkno = 0; /* block */ return (0); case MTIOCTOP: break; } switch ((short) ((struct mtop*)arg)->mt_op) { default: case MTFSR: /* forward space record */ case MTBSR: /* backward space record */ case MTBSF: /* backward space file */ break; case MTNOP: /* no operation, sets status only */ case MTCACHE: /* enable controller cache */ case MTNOCACHE: /* disable controller cache */ return (0); case MTREW: /* rewind */ case MTOFFL: /* rewind and put the drive offline */ if (t->flags & TPREW) /* rewind is running */ return (0); if (error = wtwait (t, PCATCH, "wtorew")) return (error); wtrewind (t); return (0); case MTFSF: /* forward space file */ for (count=((struct mtop*)arg)->mt_count; count>0; --count) { if (error = wtwait (t, PCATCH, "wtorfm")) return (error); if (error = wtreadfm (t)) return (error); } return (0); case MTWEOF: /* write an end-of-file record */ if (! (t->flags & TPWRITE) || (t->flags & TPWP)) return (EACCES); if (error = wtwait (t, PCATCH, "wtowfm")) return (error); if (error = wtwritefm (t)) return (error); return (0); } return (EINVAL); } /* * Strategy routine. */ void wtstrategy (struct buf *bp) { int u = minor (bp->b_dev) & T_UNIT; wtinfo_t *t = wttab + u; int s; bp->b_resid = bp->b_bcount; if (u >= NWT || !t->port) goto errxit; /* at file marks and end of tape, we just return '0 bytes available' */ if (t->flags & TPVOL) goto xit; if (bp->b_flags & B_READ) { /* Check read access and no previous write to this tape. */ if (! (t->flags & TPREAD) || (t->flags & TPWANY)) goto errxit; /* For now, we assume that all data will be copied out */ /* If read command outstanding, just skip down */ if (! (t->flags & TPRO)) { if (! wtsense (t, TP_WRP)) /* clear status */ goto errxit; if (! wtcmd (t, QIC_RDDATA)) { /* sed read mode */ wtsense (t, TP_WRP); goto errxit; } t->flags |= TPRO | TPRANY; } } else { /* Check write access and write protection. */ /* No previous read from this tape allowed. */ if (! (t->flags & TPWRITE) || (t->flags & (TPWP | TPRANY))) goto errxit; /* If write command outstanding, just skip down */ if (! (t->flags & TPWO)) { if (! wtsense (t, 0)) /* clear status */ goto errxit; if (! wtcmd (t, QIC_WRTDATA)) { /* set write mode */ wtsense (t, 0); goto errxit; } t->flags |= TPWO | TPWANY; } } if (! bp->b_bcount) goto xit; t->flags &= ~TPEXCEP; s = splbio (); if (wtstart (t, bp->b_flags, bp->b_un.b_addr, bp->b_bcount)) { wtwait (t, 0, (bp->b_flags & B_READ) ? "wtread" : "wtwrite"); bp->b_resid -= t->dmacount; } splx (s); if (t->flags & TPEXCEP) { errxit: bp->b_flags |= B_ERROR; bp->b_error = EIO; } xit: biodone (bp); return; } /* * Interrupt routine. */ void wtintr (int u) { wtinfo_t *t = wttab + u; unsigned char s; if (u >= NWT || !t->port) return; s = inb (t->STATPORT); /* get status */ if ((s & (t->BUSY | t->NOEXCEP)) == (t->BUSY | t->NOEXCEP)) return; /* device is busy */ outb (t->CTLPORT, t->ONLINE); /* stop controller */ /* * Check if rewind finished. */ if (t->flags & TPREW) { t->flags &= ~TPREW; /* Rewind finished. */ wtsense (t, TP_WRP); wakeup (t); return; } /* * Check if writing/reading of file mark finished. */ if (t->flags & (TPRMARK | TPWMARK)) { if (! (s & t->NOEXCEP)) /* Operation failed. */ wtsense (t, (t->flags & TPRMARK) ? TP_WRP : 0); t->flags &= ~(TPRMARK | TPWMARK); /* Operation finished. */ wakeup (t); return; } /* * Do we started any i/o? If no, just return. */ if (! (t->flags & TPACTIVE)) return; t->flags &= ~TPACTIVE; if (inb (DMA_STATUSREG) & DMA_DONE (t->chan)) /* if dma finished */ t->dmacount += BLKSIZE; /* increment counter */ /* * Clean up dma. */ if ((t->dmaflags & B_READ) && (t->dmatotal - t->dmacount) < BLKSIZE) { /* If the address crosses 64-k boundary, or reading short block, * copy the internal buffer to the user memory. */ isa_dmadone (t->dmaflags, t->buf, BLKSIZE, t->chan); bcopy (t->buf, t->dmavaddr, t->dmatotal - t->dmacount); } else isa_dmadone (t->dmaflags, t->dmavaddr, BLKSIZE, t->chan); /* * On exception, check for end of file and end of volume. */ if (! (s & t->NOEXCEP)) { wtsense (t, (t->dmaflags & B_READ) ? TP_WRP : 0); if (t->error.err & (TP_EOM | TP_FIL)) t->flags |= TPVOL; /* end of file */ else t->flags |= TPEXCEP; /* i/o error */ wakeup (t); return; } if (t->dmacount < t->dmatotal) { /* continue i/o */ t->dmavaddr += BLKSIZE; wtdma (t); return; } if (t->dmacount > t->dmatotal) /* short last block */ t->dmacount = t->dmatotal; wakeup (t); /* wake up user level */ } /* start the rewind operation */ static void wtrewind (wtinfo_t *t) { t->flags &= ~(TPRO | TPWO | TPVOL); if (! wtcmd (t, QIC_REWIND)) return; t->flags |= TPSTART | TPREW; wtclock (t); } /* start the `read marker' operation */ static int wtreadfm (wtinfo_t *t) { t->flags &= ~(TPRO | TPWO | TPVOL); if (! wtcmd (t, QIC_READFM)) { wtsense (t, TP_WRP); return (EIO); } t->flags |= TPRMARK | TPRANY; wtclock (t); /* Don't wait for completion here. */ return (0); } /* write marker to the tape */ static int wtwritefm (wtinfo_t *t) { tsleep (wtwritefm, WTPRI, "wtwfm", hz); /* timeout: 1 second */ t->flags &= ~(TPRO | TPWO); if (! wtcmd (t, QIC_WRITEFM)) { wtsense (t, 0); return (EIO); } t->flags |= TPWMARK | TPWANY; wtclock (t); return (wtwait (t, 0, "wtwfm")); } /* wait for controller ready or exception */ static int wtpoll (wtinfo_t *t) { int s, NOTREADY = t->BUSY | t->NOEXCEP; /* Poll status port, waiting for ready or exception. */ do s = inb (t->STATPORT); while ((s & NOTREADY) == NOTREADY); return (s); } /* execute QIC command */ static int wtcmd (wtinfo_t *t, int cmd) { if (! (wtpoll (t) & t->NOEXCEP)) /* wait for ready */ return (0); /* error */ outb (t->CMDPORT, cmd); /* output the command */ outb (t->CTLPORT, t->REQUEST | t->ONLINE); /* set request */ while (inb (t->STATPORT) & t->BUSY) /* wait for ready */ continue; outb (t->CTLPORT, t->IEN | t->ONLINE); /* reset request */ while (! (inb (t->STATPORT) & t->BUSY)) /* wait for not ready */ continue; return (1); } /* wait for the end of i/o, seeking marker or rewind operation */ static int wtwait (wtinfo_t *t, int catch, char *msg) { int error; while (t->flags & (TPACTIVE | TPREW | TPRMARK | TPWMARK)) if (error = tsleep (t, WTPRI | catch, msg, 0)) return (error); return (0); } /* initialize dma for the i/o operation */ static void wtdma (wtinfo_t *t) { t->flags |= TPACTIVE; wtclock (t); if (t->SDMAPORT) outb (t->SDMAPORT, 0); /* set dma */ if ((t->dmaflags & B_READ) && (t->dmatotal - t->dmacount) < BLKSIZE) /* Reading short block. Do it through the internal buffer. */ isa_dmastart (t->dmaflags, t->buf, BLKSIZE, t->chan); else isa_dmastart (t->dmaflags, t->dmavaddr, BLKSIZE, t->chan); outb (t->CTLPORT, t->IEN | t->ONLINE); } /* start i/o operation */ static int wtstart (wtinfo_t *t, unsigned flags, void *vaddr, unsigned len) { if (! (wtpoll (t) & t->NOEXCEP)) { /* wait for ready or error */ t->flags |= TPEXCEP; /* error */ return (0); } t->flags &= ~TPEXCEP; /* clear exception flag */ t->dmavaddr = vaddr; t->dmatotal = len; t->dmacount = 0; t->dmaflags = flags; wtdma (t); return (1); } /* start timer */ static void wtclock (wtinfo_t *t) { if (! (t->flags & TPTIMER)) { t->flags |= TPTIMER; timeout (wtimer, t, hz); } } /* * Simulate an interrupt periodically while i/o is going. * This is necessary in case interrupts get eaten due to * multiple devices on a single IRQ line. */ static void wtimer (wtinfo_t *t) { int s; t->flags &= ~TPTIMER; if (! (t->flags & (TPACTIVE | TPREW | TPRMARK | TPWMARK))) return; /* If i/o going, simulate interrupt. */ s = splbio (); wtintr (t->unit); splx (s); /* Restart timer if i/o pending. */ if (t->flags & (TPACTIVE | TPREW | TPRMARK | TPWMARK)) wtclock (t); } /* reset the controller */ static int wtreset (wtinfo_t *t) { outb (t->CTLPORT, t->RESET); /* send reset */ DELAY (25); outb (t->CTLPORT, 0); /* turn off reset */ if ((inb (t->STATPORT) & t->RESETMASK) != t->RESETVAL) return (0); return (1); } /* get controller status information */ /* return 0 if user i/o request should receive an i/o error code */ static int wtsense (wtinfo_t *t, int ignor) { char *msg = 0; int err; t->flags &= ~(TPRO | TPWO); if (! wtstatus (t)) return (0); if (! (t->error.err & TP_ST0)) t->error.err &= ~TP_ST0MASK; if (! (t->error.err & TP_ST1)) t->error.err &= ~TP_ST1MASK; t->error.err &= ~ignor; /* ignore certain errors */ err = t->error.err & (TP_FIL | TP_BNL | TP_UDA | TP_EOM | TP_WRP | TP_USL | TP_CNI | TP_MBD | TP_NDT | TP_ILL); if (! err) return (1); /* lifted from tdriver.c from Wangtek */ if (err & TP_USL) msg = "Drive not online"; else if (err & TP_CNI) msg = "No cartridge"; else if ((err & TP_WRP) && !(t->flags & TPWP)) { msg = "Tape is write protected"; t->flags |= TPWP; } else if (err & TP_FIL) msg = 0 /*"Filemark detected"*/; else if (err & TP_EOM) msg = 0 /*"End of tape"*/; else if (err & TP_BNL) msg = "Block not located"; else if (err & TP_UDA) msg = "Unrecoverable data error"; else if (err & TP_NDT) msg = "No data detected"; else if (err & TP_ILL) msg = "Illegal command"; if (msg) printf ("wt%d: %s\n", t->unit, msg); return (0); } /* get controller status information */ static int wtstatus (wtinfo_t *t) { char *p; wtpoll (t); /* wait for ready or exception */ outb (t->CMDPORT, QIC_RDSTAT); /* send `read status' command */ outb (t->CTLPORT, t->REQUEST | t->ONLINE); /* set request */ while (inb (t->STATPORT) & t->BUSY) /* wait for ready */ continue; outb (t->CTLPORT, t->ONLINE); /* reset request */ while (! (inb (t->STATPORT) & t->BUSY)) /* wait for not ready */ continue; p = (char*) &t->error; while (p < (char*)&t->error + 6) { if (! (wtpoll (t) & t->NOEXCEP)) /* wait for ready */ return (0); /* error */ *p++ = inb (t->DATAPORT); /* read status byte */ outb (t->CTLPORT, t->REQUEST); /* set request */ while (! (inb (t->STATPORT) & t->BUSY)) /* wait for not ready */ continue; /* DELAY (50); */ /* wait 50 usec */ outb (t->CTLPORT, 0); /* unset request */ } return (1); } #endif /* NWT */ Index: head/sys/i386/isa/wtreg.h =================================================================== --- head/sys/i386/isa/wtreg.h (revision 618) +++ head/sys/i386/isa/wtreg.h (revision 619) @@ -1,110 +1,111 @@ /* * Streamer tape driver for 386bsd and FreeBSD. * Supports Archive QIC-02 and Wangtek QIC-02/QIC-36 boards. * * Copyright (C) 1993 by: * Sergey Ryzhkov * Serge Vakulenko * - * Version 1.1, Fri Sep 24 02:14:42 MSD 1993 - * * Placed in the public domain with NO WARRANTIES, not even the implied * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * Authors grant any other persons or organisations permission to use * or modify this software as long as this message is kept with the software, * all derivative works or modified versions. * * This driver is derived from the old 386bsd Wangtek streamer tape driver, * made by Robert Baron at CMU, based on Intel sources. * Authors thank Robert Baron, CMU and Intel and retain here * the original CMU copyright notice. + * + * from: Version 1.1, Fri Sep 24 02:14:42 MSD 1993 + * $Id$ */ /* * Copyright (c) 1989 Carnegie-Mellon University. * All rights reserved. * * Authors: Robert Baron * * Permission to use, copy, modify and distribute this software and * its documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. */ /* ioctl for direct QIC commands */ #define WTQICMD _IO('W', 0) /* QIC-02 commands allowed for WTQICMD */ #define QIC_ERASE 0x22 #define QIC_RETENS 0x24 /* internal QIC-02 commands */ #define QIC_RDDATA 0x80 /* read data */ #define QIC_READFM 0xa0 /* read file mark */ #define QIC_WRTDATA 0x40 /* write data */ #define QIC_WRITEFM 0x60 /* write file mark */ #define QIC_RDSTAT 0xc0 /* read status command */ #define QIC_REWIND 0x21 /* rewind command (position+bot) */ #define QIC_FMT11 0x26 /* set format QIC-11 */ #define QIC_FMT24 0x27 /* set format QIC-24 */ #define QIC_FMT120 0x28 /* set format QIC-120 */ #define QIC_FMT150 0x29 /* set format QIC-150 */ /* tape driver flags */ #define TPINUSE 0x0001 /* tape is already open */ #define TPREAD 0x0002 /* tape is only open for reading */ #define TPWRITE 0x0004 /* tape is only open for writing */ #define TPSTART 0x0008 /* tape must be rewound and reset */ #define TPRMARK 0x0010 /* read file mark command outstanding */ #define TPWMARK 0x0020 /* write file mark command outstanding */ #define TPREW 0x0040 /* rewind command outstanding */ #define TPEXCEP 0x0080 /* i/o exception flag */ #define TPVOL 0x0100 /* read file mark or hit end of tape */ #define TPWO 0x0200 /* write command outstanding */ #define TPRO 0x0400 /* read command outstanding */ #define TPWANY 0x0800 /* write command requested */ #define TPRANY 0x1000 /* read command requested */ #define TPWP 0x2000 /* write protect error seen */ #define TPTIMER 0x4000 /* timer() is active */ #define TPACTIVE 0x8000 /* dma i/o active */ /* controller error register bits */ #define TP_FIL 0x0001 /* File mark detected */ #define TP_BNL 0x0002 /* Block not located */ #define TP_UDA 0x0004 /* Unrecoverable data error */ #define TP_EOM 0x0008 /* End of media */ #define TP_WRP 0x0010 /* Write protected cartridge */ #define TP_USL 0x0020 /* Unselected drive */ #define TP_CNI 0x0040 /* Cartridge not in place */ #define TP_ST0 0x0080 /* Status byte 0 bits */ #define TP_ST0MASK 0x00ff /* Status byte 0 mask */ #define TP_POR 0x0100 /* Power on/reset occurred */ #define TP_RES1 0x0200 /* Reserved for end of media */ #define TP_RES2 0x0400 /* Reserved for bus parity */ #define TP_BOM 0x0800 /* Beginning of media */ #define TP_MBD 0x1000 /* Marginal block detected */ #define TP_NDT 0x2000 /* No data detected */ #define TP_ILL 0x4000 /* Illegal command - should not happen! */ #define TP_ST1 0x8000 /* Status byte 1 bits */ #define TP_ST1MASK 0xff00 /* Status byte 1 mask */ /* formats for printing flags and error values */ #define WTDS_BITS "\20\1inuse\2read\3write\4start\5rmark\6wmark\7rew\10excep\11vol\12wo\13ro\14wany\15rany\16wp\17timer\20active" #define WTER_BITS "\20\1eof\2bnl\3uda\4eom\5wrp\6usl\7cni\11por\12res1\13res2\14bom\15mbd\16ndt\17ill" Index: head/sys/isa/atrtc.c =================================================================== --- head/sys/isa/atrtc.c (revision 618) +++ head/sys/isa/atrtc.c (revision 619) @@ -1,271 +1,252 @@ /*- * 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. * - * @(#)clock.c 7.2 (Berkeley) 5/12/91 - * - * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE - * -------------------- ----- ---------------------- - * CURRENT PATCH LEVEL: 5 00158 - * -------------------- ----- ---------------------- - * - * 14 Aug 92 Arne Henrik Juul Added code in the kernel to - * allow for DST in the BIOS. - * 17 Jan 93 Bruce Evans Fixed leap year and second - * calculations - * 01 Feb 93 Julian Elischer Added code to for the cpu - * speed independent spinwait() - * function, (used by scsi and others) - * 25 Mar 93 Sean Eric Fagan Add microtimer support using timer 1 - * 08 Apr 93 Poul-Henning Kamp/P-HK Fixes, and support for dcfclock - * 26 Apr 93 Bruce Evans Eliminate findspeed, new spinwait - * 26 Apr 93 Rodney W. Grimes I merged in Bruce changes and hope I - * still kept the other fixes... Had to - * add back in findcpuspeed that Bruce - * had removed. + * from: @(#)clock.c 7.2 (Berkeley) 5/12/91 + * $Id$ */ /* * Primitive clock interrupt routines. */ #include "param.h" #include "systm.h" #include "time.h" #include "kernel.h" #include "machine/segments.h" #include "i386/isa/icu.h" #include "i386/isa/isa.h" #include "i386/isa/rtc.h" #include "i386/isa/timerreg.h" #define DAYST 119 #define DAYEN 303 /* 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 startrtclock() { int s; findcpuspeed(); /* use the clock (while it's free) to find the cpu speed */ /* 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_FREQ+hz/2)/hz); outb (IO_TIMER1, ((TIMER_FREQ+hz/2)/hz)/256); /* initialize brain-dead battery powered clock */ outb (IO_RTC, RTC_STATUSA); outb (IO_RTC+1, 0x26); outb (IO_RTC, RTC_STATUSB); outb (IO_RTC+1, 2); outb (IO_RTC, RTC_DIAG); if (s = inb (IO_RTC+1)) printf("RTC BIOS diagnostic error %b\n", s, RTCDG_BITS); outb (IO_RTC, RTC_DIAG); outb (IO_RTC+1, 0); } unsigned int delaycount; /* calibrated loop variable (1 millisecond) */ #define FIRST_GUESS 0x2000 findcpuspeed() { unsigned char low; unsigned int remainder; /* Put counter in count down mode */ outb(IO_TIMER1+3, 0x34); outb(IO_TIMER1, 0xff); outb(IO_TIMER1, 0xff); delaycount = FIRST_GUESS; spinwait(1); /* Read the value left in the counter */ low = inb(IO_TIMER1); /* least siginifcant */ remainder = inb(IO_TIMER1); /* most significant */ remainder = (remainder<<8) + low ; /* Formula for delaycount is : * (loopcount * timer clock speed)/ (counter ticks * 1000) */ delaycount = (FIRST_GUESS * (TIMER_FREQ/1000)) / (0xffff-remainder); } /* convert 2 digit BCD number */ bcd(i) int i; { return ((i/16)*10 + (i%16)); } /* convert years to seconds (from 1970) */ unsigned long ytos(y) 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(m,leap) int m,leap; { int i; unsigned long ret; ret = 0; for(i=1;i= DAYST) && ( yd <= DAYEN)) { sec -= 60*60; } 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(base) 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 /* * Restart the clock. */ resettodr() { } /* * Wire clock interrupt in. */ #define V(s) __CONCAT(V, s) extern V(clk)(); enablertclock() { setidt(ICU_OFFSET+0, &V(clk), SDT_SYS386IGT, SEL_KPL); INTREN(IRQ0); } /* * Delay for some number of milliseconds. */ void spinwait(millisecs) int millisecs; { DELAY(1000 * millisecs); } Index: head/sys/isa/fdreg.h =================================================================== --- head/sys/isa/fdreg.h (revision 618) +++ head/sys/isa/fdreg.h (revision 619) @@ -1,72 +1,66 @@ /*- * 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. * - * @(#)fdreg.h 7.1 (Berkeley) 5/9/91 - * - * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE - * -------------------- ----- ---------------------- - * CURRENT PATCH LEVEL: 1 00153 - * -------------------- ----- ---------------------- - * - * 20 Apr 93 Julian Elischer Heavily re worked, see notes below + * from: @(#)fdreg.h 7.1 (Berkeley) 5/9/91 + * $Id$ */ /* * 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 */ Index: head/sys/isa/ic/nec765.h =================================================================== --- head/sys/isa/ic/nec765.h (revision 618) +++ head/sys/isa/ic/nec765.h (revision 619) @@ -1,71 +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. * - * @(#)nec765.h 7.1 (Berkeley) 5/9/91 + * 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 */ Index: head/sys/isa/ic/ns16550.h =================================================================== --- head/sys/isa/ic/ns16550.h (revision 618) +++ head/sys/isa/ic/ns16550.h (revision 619) @@ -1,50 +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. * - * @(#)ns16550.h 7.1 (Berkeley) 5/9/91 + * 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) */ Index: head/sys/isa/kbdtables.h =================================================================== --- head/sys/isa/kbdtables.h (revision 618) +++ head/sys/isa/kbdtables.h (revision 619) @@ -1,856 +1,858 @@ /* * Copyright (C) 1992, 1993 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@kmd-ac.dk * Tritonvej 36 UUCP: ...uunet!dkuug!kmd-ac!sos * DK9210 Aalborg SO Phone: +45 9814 8076 + * + * $Id$ */ #define META 0x80 /* eight bit for emacs META-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, NOP, NOP, 0x1B, 0x1B, NOP, NOP, 0x33, 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 */ '*', '*', '*', '*', '*', '*', '*', '*', 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, '.', '.', '.', '.', '.', '.', '.', 0x00, 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 */ '*', '*', '*', '*', '*', '*', '*', '*', 0x00, 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), F(54), 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, 0x1B, 0x1B, 0x00, 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, 0x7F, 0x7F, 0x00, 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 */ '\\', '|', 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 */ '*', '*', '*', '*', '*', '*', '*', '*', 0x00, 0x02, /* 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), F(54), 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, 0x1B, 0x1B, 0x00, 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, 0x7F, 0x7F, 0x00, 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 */ '*', '*', '*', '*', '*', '*', '*', '*', 0x00, 0x02, /* 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), F(54), 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, 0x1B, 0x1B, 0x00, 0x00, /* sc=02 */ '1', '!', NOP, NOP, NOP, NOP, NOP, NOP, 0x3F, 0x00, /* sc=03 */ '2', '"', NOP, NOP, NOP, '@', NOP, NOP, 0x3B, 0x00, /* sc=04 */ '3', 0xA3, NOP, NOP, NOP, '#', NOP, NOP, 0x3B, 0x00, /* sc=05 */ '4', '$', NOP, NOP, NOP, NOP, NOP, NOP, 0x3F, 0x00, /* sc=06 */ '5', '%', NOP, NOP, NOP, NOP, NOP, NOP, 0x3F, 0x00, /* sc=07 */ '6', '&', 0x1E, NOP, NOP, '^', 0x1E, NOP, 0x19, 0x00, /* sc=08 */ '7', '/', NOP, NOP, NOP, '&', NOP, NOP, 0x3B, 0x00, /* sc=09 */ '8', '(', NOP, NOP, NOP, '*', NOP, NOP, 0x3B, 0x00, /* sc=0a */ '9', ')', NOP, NOP, NOP, '(', NOP, NOP, 0x3B, 0x00, /* sc=0b */ '0', '=', NOP, NOP, NOP, ')', NOP, NOP, 0x3B, 0x00, /* sc=0c */ '+', '?', 0x1F, 0x1F, '-', '_', 0x1F, 0x1F, 0x00, 0x00, /* sc=0d */ 0xB4, '`', 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 */ 0xE5, 0xC5, NOP, NOP, '[', '{', 0x1B, NOP, 0x31, 0x01, /* sc=1b */ 0xA8, '^', NOP, NOP, ']', '}', 0x1D, NOP, 0x31, 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 */ 0xF8, 0xD8, NOP, NOP, ';', ':', NOP, NOP, 0x33, 0x01, /* sc=28 */ 0xE6, 0xC6, NOP, NOP, '\'', '"', NOP, NOP, 0x33, 0x01, /* sc=29 */ '<', '>', NOP, NOP, '\\', '|', 0x1C, NOP, 0x31, 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, 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, 0x7F, 0x7F, 0x00, 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 */ '*', '*', '*', '*', '*', '*', '*', '*', 0x00, 0x02, /* 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), F(54), 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, META|0x1B, META|0x1B, NOP, NOP, 0x33, 0x00, /* sc=02 */ '1', '!', NOP, NOP, META|'1', META|'!', NOP, NOP, 0x33, 0x00, /* sc=03 */ '2', '@', 0x00, 0x00, META|'2', META|'@', META|0x00, META|0x00, 0x00, 0x00, /* sc=04 */ '3', '#', NOP, NOP, META|'3', META|'#', NOP, NOP, 0x33, 0x00, /* sc=05 */ '4', '$', NOP, NOP, META|'4', META|'$', NOP, NOP, 0x33, 0x00, /* sc=06 */ '5', '%', NOP, NOP, META|'5', META|'%', NOP, NOP, 0x33, 0x00, /* sc=07 */ '6', '^', 0x1E, 0x1E, META|'6', META|'^', META|0x1E, META|0x1E, 0x00, 0x00, /* sc=08 */ '7', '&', NOP, NOP, META|'7', META|'&', NOP, NOP, 0x33, 0x00, /* sc=09 */ '8', '*', NOP, NOP, META|'8', META|'*', NOP, NOP, 0x33, 0x00, /* sc=0a */ '9', '(', NOP, NOP, META|'9', META|'(', NOP, NOP, 0x33, 0x00, /* sc=0b */ '0', ')', NOP, NOP, META|'0', META|')', NOP, NOP, 0x33, 0x00, /* sc=0c */ '-', '_', 0x1F, 0x1F, META|'-', META|'_', META|0x1F, META|0x1F, 0x00, 0x00, /* sc=0d */ '=', '+', NOP, NOP, META|'=', META|'+', NOP, NOP, 0x33, 0x00, /* sc=0e */ 0x08, 0x08, 0x7F, 0x7F, META|0x08, META|0x08, META|0x7F, META|0x7F, 0x00, 0x00, /* sc=0f */ 0x09, F(16), NOP, NOP, META|0x09, F(16), NOP, NOP, 0x77, 0x00, /* sc=10 */ 'q', 'Q', 0x11, 0x11, META|'q', META|'Q', META|0x11, META|0x11, 0x00, 0x01, /* sc=11 */ 'w', 'W', 0x17, 0x17, META|'w', META|'W', META|0x17, META|0x17, 0x00, 0x01, /* sc=12 */ 'e', 'E', 0x05, 0x05, META|'e', META|'E', META|0x05, META|0x05, 0x00, 0x01, /* sc=13 */ 'r', 'R', 0x12, 0x12, META|'r', META|'R', META|0x12, META|0x12, 0x00, 0x01, /* sc=14 */ 't', 'T', 0x14, 0x14, META|'t', META|'T', META|0x14, META|0x14, 0x00, 0x01, /* sc=15 */ 'y', 'Y', 0x19, 0x19, META|'y', META|'Y', META|0x19, META|0x19, 0x00, 0x01, /* sc=16 */ 'u', 'U', 0x15, 0x15, META|'u', META|'U', META|0x15, META|0x15, 0x00, 0x01, /* sc=17 */ 'i', 'I', 0x09, 0x09, META|'i', META|'I', META|0x09, META|0x09, 0x00, 0x01, /* sc=18 */ 'o', 'O', 0x0F, 0x0F, META|'o', META|'O', META|0x0F, META|0x0F, 0x00, 0x01, /* sc=19 */ 'p', 'P', 0x10, 0x10, META|'p', META|'P', META|0x10, META|0x10, 0x00, 0x01, /* sc=1a */ '[', '{', 0x1B, 0x1B, META|'[', META|'{', META|0x1B, META|0x1B, 0x00, 0x00, /* sc=1b */ ']', '}', 0x1D, 0x1D, META|']', META|'}', META|0x1D, META|0x1D, 0x00, 0x00, /* sc=1c */ 0x0D, 0x0D, 0x0A, 0x0A, META|0x0D, META|0x0D, META|0x0A, META|0x0A, 0x00, 0x00, /* sc=1d */ LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, 0xFF, 0x00, /* sc=1e */ 'a', 'A', 0x01, 0x01, META|'a', META|'A', META|0x01, META|0x01, 0x00, 0x01, /* sc=1f */ 's', 'S', 0x13, 0x13, META|'s', META|'S', META|0x13, META|0x13, 0x00, 0x01, /* sc=20 */ 'd', 'D', 0x04, 0x04, META|'d', META|'D', META|0x04, META|0x04, 0x00, 0x01, /* sc=21 */ 'f', 'F', 0x06, 0x06, META|'f', META|'F', META|0x06, META|0x06, 0x00, 0x01, /* sc=22 */ 'g', 'G', 0x07, 0x07, META|'g', META|'G', META|0x07, META|0x07, 0x00, 0x01, /* sc=23 */ 'h', 'H', 0x08, 0x08, META|'h', META|'H', META|0x08, META|0x08, 0x00, 0x01, /* sc=24 */ 'j', 'J', 0x0A, 0x0A, META|'j', META|'J', META|0x0A, META|0x0A, 0x00, 0x01, /* sc=25 */ 'k', 'K', 0x0B, 0x0B, META|'k', META|'K', META|0x0B, META|0x0B, 0x00, 0x01, /* sc=26 */ 'l', 'L', 0x0C, 0x0C, META|'l', META|'L', META|0x0C, META|0x0C, 0x00, 0x01, /* sc=27 */ ';', ':', NOP, NOP, META|';', META|':', NOP, NOP, 0x33, 0x00, /* sc=28 */ '\'', '"', NOP, NOP, META|'\'', META|'"', NOP, NOP, 0x33, 0x00, /* sc=29 */ '`', '~', NOP, NOP, META|'`', META|'~', NOP, NOP, 0x33, 0x00, /* sc=2a */ LSH, LSH, LSH, LSH, LSH, LSH, LSH, LSH, 0xFF, 0x00, /* sc=2b */ '\\', '|', 0x1C, 0x1C, META|'\\', META|'|', META|0x1C, META|0x1C, 0x00, 0x00, /* sc=2c */ 'z', 'Z', 0x1A, 0x1A, META|'z', META|'Z', META|0x1A, META|0x1A, 0x00, 0x01, /* sc=2d */ 'x', 'X', 0x18, 0x18, META|'x', META|'X', META|0x18, META|0x18, 0x00, 0x01, /* sc=2e */ 'c', 'C', 0x03, 0x03, META|'c', META|'C', META|0x03, META|0x03, 0x00, 0x01, /* sc=2f */ 'v', 'V', 0x16, 0x16, META|'v', META|'V', META|0x16, META|0x16, 0x00, 0x01, /* sc=30 */ 'b', 'B', 0x02, 0x02, META|'b', META|'B', META|0x02, META|0x02, 0x00, 0x01, /* sc=31 */ 'n', 'N', 0x0E, 0x0E, META|'n', META|'N', META|0x0E, META|0x0E, 0x00, 0x01, /* sc=32 */ 'm', 'M', 0x0D, 0x0D, META|'m', META|'M', META|0x0D, META|0x0D, 0x00, 0x01, /* sc=33 */ ',', '<', NOP, NOP, META|',', META|'<', NOP, NOP, 0x33, 0x00, /* sc=34 */ '.', '>', NOP, NOP, META|'.', META|'>', NOP, NOP, 0x33, 0x00, /* sc=35 */ '/', '?', NOP, NOP, META|'/', META|'?', NOP, NOP, 0x33, 0x00, /* sc=36 */ ASH, RSH, RSH, RSH, RSH, RSH, RSH, RSH, 0xFF, 0x00, /* sc=37 */ '*', '*', 0x0A, 0x0A, META|'*', META|'*', META|0x0A, META|0x0A, 0x00, 0x00, /* sc=38 */ LALT, LALT, LALT, LALT, LALT, LALT, LALT, LALT, 0xFF, 0x00, /* sc=39 */ ' ', ' ', ' ', ' ', META|' ', META|' ', META|' ', META|' ', 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', META|'7', META|'7', META|'7', META|'7', 0x80, 0x02, /* sc=48 */ F(50), '8', '8', '8', META|'8', META|'8', META|'8', META|'8', 0x80, 0x02, /* sc=49 */ F(51), '9', '9', '9', META|'9', META|'9', META|'9', META|'9', 0x80, 0x02, /* sc=4a */ F(52), '-', '-', '-', META|'-', META|'-', META|'-', META|'-', 0x80, 0x02, /* sc=4b */ F(53), '4', '4', '4', META|'4', META|'4', META|'4', META|'4', 0x80, 0x02, /* sc=4c */ F(48), '5', '5', '5', META|'5', META|'5', META|'5', META|'5', 0x80, 0x02, /* sc=4d */ F(55), '6', '6', '6', META|'6', META|'6', META|'6', META|'6', 0x80, 0x02, /* sc=4e */ F(56), '+', '+', '+', META|'+', META|'+', META|'+', META|'+', 0x80, 0x02, /* sc=4f */ F(57), '1', '1', '1', META|'1', META|'1', META|'1', META|'1', 0x80, 0x02, /* sc=50 */ F(58), '2', '2', '2', META|'2', META|'2', META|'2', META|'2', 0x80, 0x02, /* sc=51 */ F(59), '3', '3', '3', META|'3', META|'3', META|'3', META|'3', 0x80, 0x02, /* sc=52 */ F(60), '0', '0', '0', META|'0', META|'0', META|'0', META|'0', 0x80, 0x02, /* sc=53 */ F(54), '.', 0x7F, 0x7F, META|0x7F, META|0x7F, META|0x7F, META|0x7F, 0x80, 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, META|0x0D, META|0x0D, META|0x0A, META|0x0A, 0x00, 0x00, /* sc=5a */ RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, 0xFF, 0x00, /* sc=5b */ '/', '/', NOP, NOP, META|'/', META|'/', NOP, NOP, 0x33, 0x00, /* sc=5c */ CLK, ALK, ALK, ALK, ALK, ALK, ALK, ALK, 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, META|0x7F, META|0x7F, META|0x7F, META|0x7F, 0xC0, 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, META|0x1B, META|0x1B, NOP, NOP, 0x33, 0x00, /* sc=02 */ '!', '1', NOP, NOP, META|'1', META|'!', NOP, NOP, 0x33, 0x00, /* sc=03 */ '"', '2', 0x00, 0x00, META|'2', META|'@', META|0x00, META|0x00, 0x00, 0x00, /* sc=04 */ '\'', '3', NOP, NOP, META|'3', META|'#', NOP, NOP, 0x33, 0x00, /* sc=05 */ ';', '4', NOP, NOP, META|'4', META|'$', NOP, NOP, 0x33, 0x00, /* sc=06 */ ':', '5', NOP, NOP, META|'5', META|'%', NOP, NOP, 0x33, 0x00, /* sc=07 */ ',', '6', 0x1E, 0x1E, META|'6', META|'^', META|0x1E, META|0x1E, 0x00, 0x00, /* sc=08 */ '.', '7', NOP, NOP, META|'7', META|'&', NOP, NOP, 0x33, 0x00, /* sc=09 */ '*', '8', NOP, NOP, META|'8', META|'*', NOP, NOP, 0x33, 0x00, /* sc=0a */ '(', '9', NOP, NOP, META|'9', META|'(', NOP, NOP, 0x33, 0x00, /* sc=0b */ ')', '0', NOP, NOP, META|'0', META|')', NOP, NOP, 0x33, 0x00, /* sc=0c */ '_', '-', 0x1F, 0x1F, META|'-', META|'_', META|0x1F, META|0x1F, 0x00, 0x00, /* sc=0d */ '+', '=', NOP, NOP, META|'=', META|'+', NOP, NOP, 0x33, 0x00, /* sc=0e */ 0x08, 0x08, 0x7F, 0x7F, META|0x08, META|0x08, META|0x7F, META|0x7F, 0x00, 0x00, /* sc=0f */ 0x09, F(16), NOP, NOP, META|0x09, F(16), NOP, NOP, 0x77, 0x00, /* sc=10 */ 0xca, 0xea, 0x11, 0x11, META|'q', META|'Q', META|0x11, META|0x11, 0x00, 0x01, /* sc=11 */ 0xc3, 0xe3, 0x17, 0x17, META|'w', META|'W', META|0x17, META|0x17, 0x00, 0x01, /* sc=12 */ 0xd5, 0xf5, 0x05, 0x05, META|'e', META|'E', META|0x05, META|0x05, 0x00, 0x01, /* sc=13 */ 0xcb, 0xeb, 0x12, 0x12, META|'r', META|'R', META|0x12, META|0x12, 0x00, 0x01, /* sc=14 */ 0xc5, 0xe5, 0x14, 0x14, META|'t', META|'T', META|0x14, META|0x14, 0x00, 0x01, /* sc=15 */ 0xce, 0xee, 0x19, 0x19, META|'y', META|'Y', META|0x19, META|0x19, 0x00, 0x01, /* sc=16 */ 0xc7, 0xe7, 0x15, 0x15, META|'u', META|'U', META|0x15, META|0x15, 0x00, 0x01, /* sc=17 */ 0xdb, 0xfb, 0x09, 0x09, META|'i', META|'I', META|0x09, META|0x09, 0x00, 0x01, /* sc=18 */ 0xdd, 0xfd, 0x0F, 0x0F, META|'o', META|'O', META|0x0F, META|0x0F, 0x00, 0x01, /* sc=19 */ 0xda, 0xfa, 0x10, 0x10, META|'p', META|'P', META|0x10, META|0x10, 0x00, 0x01, /* sc=1a */ 0xc8, 0xe8, 0x1B, 0x1B, META|'[', META|'{', META|0x1B, META|0x1B, 0x00, 0x01, /* sc=1b */ 0xdf, 0xff, 0x1D, 0x1D, META|']', META|'}', META|0x1D, META|0x1D, 0x00, 0x01, /* sc=1c */ 0x0D, 0x0D, 0x0A, 0x0A, META|0x0D, META|0x0D, META|0x0A, META|0x0A, 0x00, 0x00, /* sc=1d */ LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, 0xFF, 0x00, /* sc=1e */ 0xc6, 0xe6, 0x01, 0x01, META|'a', META|'A', META|0x01, META|0x01, 0x00, 0x01, /* sc=1f */ 0xd9, 0xf9, 0x13, 0x13, META|'s', META|'S', META|0x13, META|0x13, 0x00, 0x01, /* sc=20 */ 0xd7, 0xf7, 0x04, 0x04, META|'d', META|'D', META|0x04, META|0x04, 0x00, 0x01, /* sc=21 */ 0xc1, 0xe1, 0x06, 0x06, META|'f', META|'F', META|0x06, META|0x06, 0x00, 0x01, /* sc=22 */ 0xd0, 0xf0, 0x07, 0x07, META|'g', META|'G', META|0x07, META|0x07, 0x00, 0x01, /* sc=23 */ 0xd2, 0xf2, 0x08, 0x08, META|'h', META|'H', META|0x08, META|0x08, 0x00, 0x01, /* sc=24 */ 0xcf, 0xef, 0x0A, 0x0A, META|'j', META|'J', META|0x0A, META|0x0A, 0x00, 0x01, /* sc=25 */ 0xcc, 0xec, 0x0B, 0x0B, META|'k', META|'K', META|0x0B, META|0x0B, 0x00, 0x01, /* sc=26 */ 0xc4, 0xe4, 0x0C, 0x0C, META|'l', META|'L', META|0x0C, META|0x0C, 0x00, 0x01, /* sc=27 */ 0xd6, 0xf6, NOP, NOP, META|';', META|':', NOP, NOP, 0x33, 0x01, /* sc=28 */ 0xdc, 0xfc, NOP, NOP, META|'\'', META|'"', NOP, NOP, 0x33, 0x01, /* sc=29 */ 0xa3, 0xb3, NOP, NOP, META|'`', META|'~', NOP, NOP, 0x33, 0x01, /* sc=2a */ LSH, LSH, LSH, LSH, LSH, LSH, LSH, LSH, 0xFF, 0x00, /* sc=2b */ '\\', '|', 0x1C, 0x1C, META|'\\', META|'|', META|0x1C, META|0x1C, 0x00, 0x00, /* sc=2c */ 0xd1, 0xf1, 0x1A, 0x1A, META|'z', META|'Z', META|0x1A, META|0x1A, 0x00, 0x01, /* sc=2d */ 0xde, 0xfe, 0x18, 0x18, META|'x', META|'X', META|0x18, META|0x18, 0x00, 0x01, /* sc=2e */ 0xd3, 0xf3, 0x03, 0x03, META|'c', META|'C', META|0x03, META|0x03, 0x00, 0x01, /* sc=2f */ 0xcd, 0xed, 0x16, 0x16, META|'v', META|'V', META|0x16, META|0x16, 0x00, 0x01, /* sc=30 */ 0xc9, 0xe9, 0x02, 0x02, META|'b', META|'B', META|0x02, META|0x02, 0x00, 0x01, /* sc=31 */ 0xd4, 0xf4, 0x0E, 0x0E, META|'n', META|'N', META|0x0E, META|0x0E, 0x00, 0x01, /* sc=32 */ 0xd8, 0xf8, 0x0D, 0x0D, META|'m', META|'M', META|0x0D, META|0x0D, 0x00, 0x01, /* sc=33 */ 0xc2, 0xe2, NOP, NOP, META|',', META|'<', NOP, NOP, 0x33, 0x01, /* sc=34 */ 0xc0, 0xe0, NOP, NOP, META|'.', META|'>', NOP, NOP, 0x33, 0x01, /* sc=35 */ '/', '?', NOP, NOP, META|'/', META|'?', NOP, NOP, 0x33, 0x00, /* sc=36 */ ASH, RSH, RSH, RSH, RSH, RSH, RSH, RSH, 0xFF, 0x00, /* sc=37 */ '*', '*', 0x0A, 0x0A, META|'*', META|'*', META|0x0A, META|0x0A, 0x00, 0x00, /* sc=38 */ LALT, LALT, LALT, LALT, LALT, LALT, LALT, LALT, 0xFF, 0x00, /* sc=39 */ ' ', ' ', ' ', ' ', META|' ', META|' ', META|' ', META|' ', 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', META|'7', META|'7', META|'7', META|'7', 0x80, 0x02, /* sc=48 */ F(50), '8', '8', '8', META|'8', META|'8', META|'8', META|'8', 0x80, 0x02, /* sc=49 */ F(51), '9', '9', '9', META|'9', META|'9', META|'9', META|'9', 0x80, 0x02, /* sc=4a */ F(52), '-', '-', '-', META|'-', META|'-', META|'-', META|'-', 0x80, 0x02, /* sc=4b */ F(53), '4', '4', '4', META|'4', META|'4', META|'4', META|'4', 0x80, 0x02, /* sc=4c */ F(48), '5', '5', '5', META|'5', META|'5', META|'5', META|'5', 0x80, 0x02, /* sc=4d */ F(55), '6', '6', '6', META|'6', META|'6', META|'6', META|'6', 0x80, 0x02, /* sc=4e */ F(56), '+', '+', '+', META|'+', META|'+', META|'+', META|'+', 0x80, 0x02, /* sc=4f */ F(57), '1', '1', '1', META|'1', META|'1', META|'1', META|'1', 0x80, 0x02, /* sc=50 */ F(58), '2', '2', '2', META|'2', META|'2', META|'2', META|'2', 0x80, 0x02, /* sc=51 */ F(59), '3', '3', '3', META|'3', META|'3', META|'3', META|'3', 0x80, 0x02, /* sc=52 */ F(60), '0', '0', '0', META|'0', META|'0', META|'0', META|'0', 0x80, 0x02, /* sc=53 */ F(54), '.', 0x7F, 0x7F, META|0x7F, META|0x7F, META|0x7F, META|0x7F, 0x80, 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, META|0x0D, META|0x0D, META|0x0A, META|0x0A, 0x00, 0x00, /* sc=5a */ RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, 0xFF, 0x00, /* sc=5b */ '/', '/', NOP, NOP, META|'/', META|'/', NOP, NOP, 0x33, 0x00, /* sc=5c */ CLK, ALK, ALK, ALK, ALK, ALK, ALK, ALK, 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, META|0x7F, META|0x7F, META|0x7F, META|0x7F, 0xC0, 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, NOP, NOP, 0x1B, 0x1B, NOP, NOP, 0x33, 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, 0x7F, 0x7F, 0x00, 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 */ '*', '*', '*', '*', '*', '*', '*', '*', 0x00, 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), F(54), 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} }; Index: head/sys/isa/rtc.h =================================================================== --- head/sys/isa/rtc.h (revision 618) +++ head/sys/isa/rtc.h (revision 619) @@ -1,85 +1,86 @@ /*- * 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. * - * @(#)rtc.h 7.1 (Berkeley) 5/12/91 + * from: @(#)rtc.h 7.1 (Berkeley) 5/12/91 + * $Id$ */ /* * 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 RTC_STATUSB 0x0b /* status register B */ #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_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*/ Index: head/sys/isa/sio.c =================================================================== --- head/sys/isa/sio.c (revision 618) +++ head/sys/isa/sio.c (revision 619) @@ -1,1749 +1,1740 @@ /*- * 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 - * - * 27 May 93 Bruce Evans From com-0.2 package, fast interrupt - * com port driver. - * 27 May 93 Guido van Rooij Ported in Chris Demetriou's BIDIR - * code, add multiport support. - * 27 May 93 Rodney W. Grimes I then renamed it to sio.c for putting - * into the patch kit. Added in sioselect - * from com.c. Added port 4 support. + * from: @(#)com.c 7.5 (Berkeley) 5/16/91 + * $Id$ */ -static char rcsid[] = "$Header: /a/cvs/386BSD/src/sys/i386/isa/sio.c,v 1.10 1993/10/12 06:32:28 davidg Exp $"; #include "sio.h" #if NSIO > 0 /* * COM driver, based on HP dca driver. * Mostly rewritten to use pseudo-DMA. * Works for National Semiconductor NS8250-NS16550AF UARTs. */ #include "param.h" #include "systm.h" #include "ioctl.h" #include "tty.h" #include "proc.h" #include "user.h" #include "conf.h" #include "file.h" #include "uio.h" #include "kernel.h" #include "syslog.h" #include "i386/isa/isa.h" #include "i386/isa/isa_device.h" #include "i386/isa/comreg.h" #include "i386/isa/ic/ns16550.h" #undef CRTS_IFLOW #define CRTS_IFLOW CRTSCTS /* XXX, CCTS_OFLOW = CRTSCTS already */ #define LOTS_OF_EVENTS 64 /* helps separate urgent events from input */ #define RB_I_HIGH_WATER (RBSZ - 2 * RS_IBUFSIZE) #define RB_I_LOW_WATER ((RBSZ - 2 * RS_IBUFSIZE) * 7 / 8) #define RS_IBUFSIZE 256 #define TS_RTSBLOCK TS_TBLOCK /* XXX */ #define TTY_BI TTY_FE /* XXX */ #define TTY_OE TTY_PE /* XXX */ #ifndef COM_BIDIR #define UNIT(x) (minor(x)) /* XXX */ #else /* COM_BIDIR */ #define COM_UNITMASK 0x7f #define COM_CALLOUTMASK 0x80 #define UNIT(x) (minor(x) & COM_UNITMASK) #define CALLOUT(x) (minor(x) & COM_CALLOUTMASK) #endif /* COM_BIDIR */ #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) #endif /* COM_MULTIPORT */ #define com_scr 7 /* scratch register for 16450-16550 (R/W) */ #define schedsoftcom() (ipending |= 1 << 4) /* XXX */ /* * 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. * Bug: I think TIOCSETA doesn't clear TS_TTSTOP when it clears IXON. */ #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_ODONE 4 /* output completed */ #define CS_RTS_IFLOW 8 /* use RTS input flow control */ static char *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 int Bool_t; /* promoted boolean */ typedef u_char bool_t; /* boolean */ /* com device structure */ struct com_s { u_char state; /* miscellaneous flag bits */ u_char cfcr_image; /* copy of value written to CFCR */ bool_t hasfifo; /* nonzero for 16550 UARTs */ u_char mcr_image; /* copy of value written to MCR */ bool_t softDCD; /* nonzero for faked carrier detect */ #ifdef COM_BIDIR bool_t bidir; /* is this unit bidirectional? */ bool_t active; /* is the port active _at all_? */ bool_t active_in; /* is the incoming port in use? */ bool_t active_out; /* is the outgoing port in use? */ #endif /* COM_BIDIR */ #ifdef COM_MULTIPORT bool_t multiport; /* is this unit part of a multiport device? */ #endif /* COM_MULTIPORT */ /* * 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 *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 */ int ocount; /* original count for current output */ 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 */ 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]; }; /* * These functions in the com module ought to be declared (with a prototype) * in a com-driver system header. The void ones may need to be int to match * ancient devswitch declarations, but they don't actually return anything. */ #define Dev_t int /* promoted dev_t */ struct consdev; int sioclose __P((Dev_t dev, int fflag, int devtype, struct proc *p)); void siointr __P((int unit)); #ifdef COM_MULTIPORT bool_t comintr1 __P((struct com_s *com)); #endif /* COM_MULTIPORT */ int sioioctl __P((Dev_t dev, int cmd, caddr_t data, int fflag, struct proc *p)); int siocngetc __P((Dev_t dev)); void siocninit __P((struct consdev *cp)); void siocnprobe __P((struct consdev *cp)); void siocnputc __P((Dev_t dev, int c)); int sioopen __P((Dev_t dev, int oflags, int devtype, struct proc *p)); /* * sioopen gets compared to the d_open entry in struct cdevsw. d_open and * other functions are declared in with short types like dev_t * in the prototype. Such declarations are broken because they vary with * __P (significantly in theory - the compiler is allowed to push a short * arg if it has seen the prototype; insignificantly in practice - gcc * doesn't push short args and it would be slower on 386's to do so). * * Also, most of the device switch functions are still declared old-style * so they take a Dev_t arg and shorten it to a dev_t. It would be simpler * and faster if dev_t's were always promoted (to ints or whatever) as * early as possible. * * Until is fixed, we cast sioopen to the following `wrong' type * when comparing it to the d_open entry just to avoid compiler warnings. */ typedef int (*bogus_open_t) __P((dev_t dev, int oflags, int devtype, struct proc *p)); int sioread __P((Dev_t dev, struct uio *uio, int ioflag)); void siostop __P((struct tty *tp, int rw)); int siowrite __P((Dev_t dev, struct uio *uio, int ioflag)); void softsio0 __P((void)); void softsio1 __P((void)); void softsio2 __P((void)); void softsio3 __P((void)); void softsio4 __P((void)); void softsio5 __P((void)); void softsio6 __P((void)); void softsio7 __P((void)); void softsio8 __P((void)); static int sioattach __P((struct isa_device *dev)); static void comflush __P((struct com_s *com)); static void comhardclose __P((struct com_s *com)); static void cominit __P((int unit, int rate)); static int 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 compoll __P((void)); static int comstart __P((struct tty *tp)); static void comwakeup __P((void)); static int tiocm2mcr __P((int)); /* 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]) static struct com_s com_structs[NSIO]; struct isa_driver siodriver = { sioprobe, sioattach, "sio" }; #ifdef COMCONSOLE static int comconsole = COMCONSOLE; #else static int comconsole = -1; #endif static bool_t comconsinit; static speed_t comdefaultrate = TTYDEF_SPEED; static u_int com_events; /* input chars + weighted output completions */ static int commajor; struct tty sio_tty[NSIO]; extern struct tty *constty; extern u_int ipending; /* XXX */ extern int tk_nin; /* XXX */ extern int tk_rawcc; /* 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; Port_t iobase; 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. */ 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; } iobase = dev->id_iobase; result = IO_COMSIZE; /* * 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(); /* * Enable output interrupts (only) and check the following: * 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. */ outb(iobase + com_cfcr, CFCR_8BITS); /* ensure IER is addressed */ outb(iobase + com_mcr, MCR_IENABLE); /* open gate early */ outb(iobase + com_ier, 0); /* ensure edge on next intr */ outb(iobase + com_ier, IER_ETXRDY); /* generate interrupt */ if ( inb(iobase + com_cfcr) != CFCR_8BITS || inb(iobase + com_ier) != IER_ETXRDY || inb(iobase + com_mcr) != MCR_IENABLE || (inb(iobase + com_iir) & IIR_IMASK) != IIR_TXRDY || isa_irq_pending(dev) || (inb(iobase + com_iir) & IIR_IMASK) != IIR_NOPEND) result = 0; /* * Turn off all device interrupts and check that they go off properly. * Leave MCR_IENABLE set. 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_mcr, MCR_IENABLE); /* dummy to avoid bus echo */ if ( inb(iobase + com_ier) != 0 || isa_irq_pending(dev) || (inb(iobase + com_iir) & IIR_IMASK) != IIR_NOPEND) result = 0; enable_intr(); return (result); } static int /* XXX - should be void */ sioattach(isdp) struct isa_device *isdp; { struct com_s *com; static bool_t comwakeup_started = FALSE; Port_t iobase; int s; u_char scr; u_char scr1; u_char scr2; int unit; iobase = isdp->id_iobase; unit = isdp->id_unit; if (unit == comconsole) DELAY(1000); /* XXX */ s = spltty(); /* * 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. * Keeping MCR_DTR and MCR_RTS off might stop the external * device from sending before we are ready. */ com = &com_structs[unit]; com->cfcr_image = CFCR_8BITS; com->mcr_image = MCR_IENABLE; #if 0 com->softDCD = TRUE; #endif 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->line_status_port = iobase + com_lsr; com->modem_status_port = iobase + com_msr; com->tp = &sio_tty[unit]; #ifdef COM_BIDIR /* * if bidirectional ports possible, clear the bidir port info; */ com->bidir = FALSE; com->active = FALSE; com->active_in = com->active_out = FALSE; #endif /* COM_BIDIR */ /* attempt to determine UART type */ 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); printf("sio%d: type", unit); #ifdef COM_MULTIPORT if (0); #else if (scr1 != 0xa5 || scr2 != 0x5a) printf(" <8250>"); #endif else { outb(iobase + com_fifo, FIFO_ENABLE | FIFO_TRIGGER_14); DELAY(100); switch (inb(iobase + com_iir) & 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: com->hasfifo = TRUE; printf(" <16550A>"); break; } outb(iobase + com_fifo, 0); } #ifdef COM_MULTIPORT if (COM_ISMULTIPORT(isdp)) { struct isa_device *masterdev; com->multiport = TRUE; printf(" (multiport)"); /* set the master's common-interrupt-enable reg., * as appropriate. YYY See your manual */ /* enable only common interrupt for port */ outb(iobase + com_mcr, 0); masterdev = find_isadev(isa_devtab_tty, &siodriver, COM_MPMASTER(isdp)); outb(masterdev->id_iobase+com_scr, 0x80); } else com->multiport = FALSE; #endif /* COM_MULTIPORT */ printf("\n"); #ifdef KGDB if (kgdb_dev == makedev(commajor, unit)) { if (comconsole == unit) kgdb_dev = -1; /* can't debug over console port */ else { cominit(unit, kgdb_rate); if (kgdb_debug_init) { /* * Print prefix of device name, * let kgdb_connect print the rest. */ printf("com%d: ", unit); kgdb_connect(1); } else printf("com%d: kgdb enabled\n", unit); } } #endif /* * Need to reset baud rate, etc. of next print so reset comconsinit. * Also make sure console is always "hardwired" */ if (unit == comconsole) { comconsinit = FALSE; com->softDCD = TRUE; } com_addr(unit) = com; splx(s); if (!comwakeup_started) { comwakeup(); 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 = 0; Port_t iobase; int s; struct tty *tp; int unit = UNIT(dev); #ifdef COM_BIDIR bool_t callout = CALLOUT(dev); #endif /* COM_BIDIR */ if ((u_int) unit >= NSIO || (com = com_addr(unit)) == NULL) return (ENXIO); #ifdef COM_BIDIR /* if it's a callout device, and bidir not possible on that dev, die */ if (callout && !(com->bidir)) return (ENXIO); #endif /* COM_BIDIR */ tp = com->tp; s = spltty(); #ifdef COM_BIDIR bidir_open_top: /* if it's bidirectional, we've gotta deal with it... */ if (com->bidir) { if (callout) { if (com->active_in) { /* it's busy. die */ splx(s); return (EBUSY); } else { /* it's ours. lock it down, and set it up */ com->active_out = TRUE; com->softDCD = TRUE; } } else { if (com->active_out) { /* it's busy, outgoing. wait, if possible */ if (flag & O_NONBLOCK) { /* can't wait; bail */ splx(s); return (EBUSY); } else { /* wait for it... */ error = tsleep(&com->active_out, TTIPRI|PCATCH, "comoth", 0); /* if there was an error, take off. */ if (error != 0) { splx(s); return (error); } /* else take it from the top */ goto bidir_open_top; } } else if (com->last_modem_status & MSR_DCD) { /* there's a carrier on the line; we win */ com->active_in = TRUE; com->softDCD = FALSE; } else { /* there is no carrier on the line */ if (flag & O_NONBLOCK) { /* can't wait; let it open */ com->active_in = TRUE; com->softDCD = FALSE; } else { /* put DTR & RTS up */ /* NOTE: cgd'sdriver used the ier register * to enable/disable interrupts. This one * uses both ier and IENABLE in the mcr. */ (void) commctl(com, MCR_DTR | MCR_RTS, DMSET); outb(com->iobase + com_ier, IER_EMSC); /* wait for it... */ error = tsleep(&com->active_in, TTIPRI|PCATCH, "comdcd", 0); /* if not active, turn DTR & RTS off */ if (!com->active) (void) commctl(com, MCR_DTR, DMBIC); /* if there was an error, take off. */ if (error != 0) { splx(s); return (error); } /* else take it from the top */ goto bidir_open_top; } } } } com->active = TRUE; #endif /* COM_BIDIR */ tp->t_oproc = comstart; tp->t_param = comparam; tp->t_dev = dev; if (!(tp->t_state & TS_ISOPEN)) { tp->t_state |= TS_WOPEN; ttychars(tp); if (tp->t_ispeed == 0) { /* * We no longer use the flags from * since those 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. */ tp->t_iflag = 0; tp->t_oflag = 0; tp->t_cflag = CREAD | CS8 | HUPCL; tp->t_lflag = 0; tp->t_ispeed = tp->t_ospeed = comdefaultrate; } (void) commctl(com, MCR_DTR | MCR_RTS, DMSET); error = comparam(tp, &tp->t_termios); if (error != 0) goto out; ttsetwater(tp); iobase = com->iobase; disable_intr(); if (com->hasfifo) /* (re)enable and drain FIFO */ outb(iobase + com_fifo, FIFO_ENABLE | FIFO_TRIGGER_14 | FIFO_RCV_RST | FIFO_XMT_RST); (void) inb(com->line_status_port); (void) inb(com->data_port); com->last_modem_status = com->prev_modem_status = inb(com->modem_status_port); outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC); enable_intr(); if (com->softDCD || com->prev_modem_status & MSR_DCD) tp->t_state |= TS_CARR_ON; } else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) { splx(s); return (EBUSY); } while (!(flag & O_NONBLOCK) && !(tp->t_cflag & CLOCAL) #ifdef COM_BIDIR /* We went through a lot of trouble to open it, * but it's certain we have a carrier now, so * don't spend any time on it now. */ && !(com->bidir) #endif /* COM_BIDIR */ && !(tp->t_state & TS_CARR_ON)) { tp->t_state |= TS_WOPEN; error = ttysleep(tp, (caddr_t)&tp->t_raw, TTIPRI | PCATCH, ttopen, 0); if (error != 0) break; } out: splx(s); if (error == 0) error = (*linesw[tp->t_line].l_open)(dev, tp); #ifdef COM_BIDIR /* wakeup sleepers */ wakeup((caddr_t) &com->active_in); #endif /* COM_BIDIR */ /* * XXX - the next step was once not done, so interrupts, DTR and RTS * remainded hot if the process was killed while it was sleeping * waiting for carrier. Now there is the opposite problem. If several * processes are sleeping waiting for carrier on the same line and one * is killed, interrupts are turned off so the other processes will * never see the carrier rise. */ if (error != 0 && !(tp->t_state & TS_ISOPEN)) { comhardclose(com); } tp->t_state &= ~TS_WOPEN; return (error); } /*ARGSUSED*/ int sioclose(dev, flag, mode, p) dev_t dev; int flag; int mode; struct proc *p; { struct com_s *com; struct tty *tp; com = com_addr(UNIT(dev)); tp = com->tp; (*linesw[tp->t_line].l_close)(tp, flag); comhardclose(com); ttyclose(tp); return (0); } void comhardclose(com) struct com_s *com; { Port_t iobase; int s; struct tty *tp; s = spltty(); iobase = com->iobase; outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK); #ifdef KGDB /* do not disable interrupts if debugging */ if (kgdb_dev != makedev(commajor, com - &com_structs[0])) #endif outb(iobase + com_ier, 0); tp = com->tp; if (tp->t_cflag & HUPCL || tp->t_state & TS_WOPEN || !(tp->t_state & TS_ISOPEN)) (void) commctl(com, MCR_RTS, DMSET); #ifdef COM_BIDIR com->active = com->active_in = com->active_out = FALSE; com->softDCD = FALSE; /* wakeup sleepers who are waiting for out to finish */ wakeup((caddr_t) &com->active_out); #endif /* COM_BIDIR */ splx(s); } int sioread(dev, uio, flag) dev_t dev; struct uio *uio; int flag; { struct tty *tp = com_addr(UNIT(dev))->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 unit = UNIT(dev); struct tty *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)); } void siointr(unit) int unit; { struct com_s *com; #ifndef COM_MULTIPORT u_char line_status; u_char modem_status; u_char *ioptr; u_char recv_data; com = com_addr(unit); #else /* COM_MULTIPORT */ int i; bool_t donesomething; do { donesomething = FALSE; for(i=0;iline_status_port); /* input event? (check first to help avoid overruns) */ while (line_status & LSR_RCV_MASK) { /* break/unnattached error bits or real input? */ #ifdef COM_MULTIPORT donesomething = TRUE; #endif /* COM_MULTIPORT */ if (!(line_status & LSR_RXRDY)) recv_data = 0; else recv_data = inb(com->data_port); ++com->bytes_in; #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; 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); } /* * "& 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. */ #ifdef COM_MULTIPORT donesomething = TRUE; #endif /* COM_MULTIPORT */ com->last_modem_status = modem_status; if (!(com->state & CS_CHECKMSR)) { com_events += LOTS_OF_EVENTS; com->state |= CS_CHECKMSR; schedsoftcom(); } /* 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)) { #ifdef COM_MULTIPORT donesomething = TRUE; #endif /* COM_MULTIPORT */ ioptr = com->optr; 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); schedsoftcom(); /* handle at high level ASAP */ } } /* finished? */ if ((inb(com->int_id_port) & IIR_IMASK) == IIR_NOPEND) #ifdef COM_MULTIPORT return (donesomething); #else return; #endif /* COM_MULTIPORT */ } } static int tiocm2mcr(data) int data; { register m = 0; if (data & TIOCM_DTR) m |= MCR_DTR; if (data & TIOCM_RTS) m |= MCR_RTS; return m; } 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 s; struct tty *tp; com = com_addr(UNIT(dev)); tp = com->tp; error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 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: (void) commctl(com, MCR_DTR, DMBIS); break; case TIOCCDTR: (void) commctl(com, MCR_DTR, DMBIC); break; case TIOCMSET: (void) commctl(com, tiocm2mcr(*(int *)data), DMSET); break; case TIOCMBIS: (void) commctl(com, tiocm2mcr(*(int *)data), DMBIS); break; case TIOCMBIC: (void) commctl(com, tiocm2mcr(*(int *)data), DMBIC); break; case TIOCMGET: { register int bits = 0, mode; mode = commctl(com, 0, DMGET); if (inb(com->iobase+com_ier)) bits |= TIOCM_LE; /* XXX */ if (mode & MSR_DCD) bits |= TIOCM_CD; if (mode & MSR_CTS) bits |= TIOCM_CTS; if (mode & MSR_DSR) bits |= TIOCM_DSR; if (mode & (MCR_DTR<<8)) bits |= TIOCM_DTR; if (mode & (MCR_RTS<<8)) bits |= TIOCM_RTS; if (mode & (MSR_RI|MSR_TERI)) bits |= TIOCM_RI; *(int *)data = bits; } break; #ifdef COM_BIDIR case TIOCMSBIDIR: /* must be root to set bidir. capability */ if (p->p_ucred->cr_uid != 0) return(EPERM); /* if it's the console, can't do it */ if (UNIT(dev) == comconsole) return(ENOTTY); /* can't do the next, for obvious reasons... * but there are problems to be looked at... */ /* if the port is active, don't do it */ /* if (com->active) return(EBUSY); */ com->bidir = *(int *)data; break; case TIOCMGBIDIR: *(int *)data = com->bidir; break; #endif /* COM_BIDIR */ default: splx(s); return (ENOTTY); } splx(s); return (0); } /* cancel pending output */ static void comflush(com) struct com_s *com; { struct ringb *rbp; disable_intr(); if (com->state & CS_ODONE) com_events -= LOTS_OF_EVENTS; com->state &= ~(CS_ODONE | CS_BUSY); enable_intr(); rbp = &com->tp->t_out; rbp->rb_hd += com->ocount; rbp->rb_hd = RB_ROLLOVER(rbp, rbp->rb_hd); com->ocount = 0; com->tp->t_state &= ~TS_BUSY; } static void compoll() { static bool_t awake = FALSE; struct com_s *com; int s; int unit; if (com_events == 0) return; disable_intr(); if (awake) { enable_intr(); return; } awake = TRUE; enable_intr(); s = spltty(); repeat: for (unit = 0; unit < NSIO; ++unit) { u_char *buf; u_char *ibuf; int incc; struct tty *tp; com = com_addr(unit); if (com == NULL) continue; tp = com->tp; /* switch the role of the low-level input buffers */ if (com->iptr == (ibuf = com->ibuf)) incc = 0; else { 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. */ if (!(com->mcr_image & MCR_RTS) && !(tp->t_state & TS_RTSBLOCK)) 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 && unit != comconsole) { #ifdef COM_BIDIR if (com->prev_modem_status & MSR_DCD) { (*linesw[tp->t_line].l_modem)(tp, 1); com->softDCD = FALSE; wakeup((caddr_t) &com->active_in); } #else if (com->prev_modem_status & MSR_DCD) (*linesw[tp->t_line].l_modem)(tp, 1); #endif /* COM_BIDIR */ else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) { disable_intr(); outb(com->modem_ctl_port, com->mcr_image &= ~MCR_DTR); enable_intr(); } } } /* XXX */ if (TRUE) { u_int delta; u_int delta_error_counts[CE_NTYPES]; int errnum; u_long total; disable_intr(); bcopy(com->delta_error_counts, delta_error_counts, sizeof delta_error_counts); bzero(com->delta_error_counts, sizeof delta_error_counts); enable_intr(); for (errnum = 0; errnum < CE_NTYPES; ++errnum) { delta = delta_error_counts[errnum]; if (delta != 0) { total = com->error_counts[errnum] += delta; log(LOG_WARNING, "com%d: %u more %s%s (total %lu)\n", unit, delta, error_desc[errnum], delta == 1 ? "" : "s", total); } } } 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 && RB_LEN(&tp->t_raw) + incc >= RB_I_HIGH_WATER && !(tp->t_state & TS_RTSBLOCK) /* * 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_RTSBLOCK; 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] += incc - rb_write(&tp->t_raw, (char *) buf, incc); 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; splx(s); awake = FALSE; } 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 (divisor < 0 || t->c_ispeed != 0 && t->c_ispeed != t->c_ospeed) return (EINVAL); /* parameters are OK, convert them to the com struct and the device */ unit = UNIT(tp->t_dev); com = com_addr(unit); iobase = com->iobase; s = spltty(); if (divisor == 0) { (void) commctl(com, MCR_RTS, DMSET); /* hang up line */ splx(s); return (0); } 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; /* * 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 siointr() might lose some receiver * error bits, but that is acceptable here. */ disable_intr(); com->state &= ~CS_TTGO; enable_intr(); while ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY)) != (LSR_TSRE | LSR_TXRDY)) { error = ttysleep(tp, (caddr_t)&tp->t_raw, TTIPRI | PCATCH, "comparam", 1); 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 */ 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 16+ msec latency, while CTS flow has 50- usec latency. * Note that DCD flow control stupidly uses the same state flag * (TS_TTSTOP) as XON/XOFF flow control. */ com->state &= ~CS_CTS_OFLOW; com->state |= CS_ODEVREADY; if (cflag & CCTS_OFLOW) { com->state |= CS_CTS_OFLOW; if (!(com->prev_modem_status & MSR_CTS)) com->state &= ~CS_ODEVREADY; } enable_intr(); siointr(unit); /* recover from fiddling with CS_TTGO */ splx(s); return (0); } static int /* XXX - should be void */ comstart(tp) struct tty *tp; { struct com_s *com; int s; int unit; unit = 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_RTSBLOCK) { if (com->mcr_image & MCR_RTS && com->state & CS_RTS_IFLOW) outb(com->modem_ctl_port, com->mcr_image &= ~MCR_RTS); } else { if (!(com->mcr_image & MCR_RTS) && com->iptr < com->ihighwater) { tp->t_state &= ~TS_RTSBLOCK; outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS); } } enable_intr(); if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) goto out; if (RB_LEN(&tp->t_out) <= tp->t_lowat) { if (tp->t_state & TS_ASLEEP) { tp->t_state &= ~TS_ASLEEP; wakeup((caddr_t)&tp->t_out); } if (tp->t_wsel) { selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); tp->t_wsel = 0; tp->t_state &= ~TS_WCOLL; } } if (com->ocount != 0) { disable_intr(); siointr(unit); enable_intr(); } else if (RB_LEN(&tp->t_out) != 0) { tp->t_state |= TS_BUSY; com->ocount = RB_CONTIGGET(&tp->t_out); disable_intr(); com->obufend = (com->optr = (u_char *) tp->t_out.rb_hd) + com->ocount; com->state |= CS_BUSY; siointr(unit); /* fake interrupt to start output */ enable_intr(); } out: splx(s); return (1); } void siostop(tp, rw) struct tty *tp; int rw; { struct com_s *com; com = com_addr(UNIT(tp->t_dev)); if (rw & FWRITE) comflush(com); disable_intr(); if (tp->t_state & TS_TTSTOP) com->state &= ~CS_TTGO; else com->state |= CS_TTGO; enable_intr(); } static int commctl(com, bits, how) struct com_s *com; int bits; int how; { disable_intr(); switch (how) { case DMSET: #ifdef COM_MULTIPORT /* YYY maybe your card doesn't want IENABLE to be reset? */ if(com->multiport) outb(com->modem_ctl_port, com->mcr_image = bits); else #endif /* COM_MULTIPORT */ outb(com->modem_ctl_port, com->mcr_image = bits | MCR_IENABLE); break; case DMBIS: outb(com->modem_ctl_port, com->mcr_image |= bits); break; case DMBIC: #ifdef COM_MULTIPORT /* YYY maybe your card doesn't want IENABLE to be reset? */ if(com->multiport) outb(com->modem_ctl_port, com->mcr_image &= ~(bits)); else #endif /* COM_MULTIPORT */ outb(com->modem_ctl_port, com->mcr_image &= ~(bits & ~MCR_IENABLE)); break; case DMGET: bits = com->prev_modem_status | (com->mcr_image << 8); break; } enable_intr(); return (bits); } static void comwakeup() { struct com_s *com; int unit; timeout((timeout_func_t) comwakeup, (caddr_t) NULL, 1); if (com_events != 0) /* schedule compoll() to run when the cpl allows */ schedsoftcom(); /* recover from lost output interrupts */ for (unit = 0; unit < NSIO; ++unit) { com = com_addr(unit); if (com != NULL && com->state >= (CS_BUSY | CS_TTGO)) { disable_intr(); siointr(unit); enable_intr(); } } } void softsio0() { compoll(); } void softsio1() { compoll(); } void softsio2() { compoll(); } void softsio3() { compoll(); } void softsio4() { compoll(); } void softsio5() { compoll(); } void softsio6() { compoll(); } void softsio7() { compoll(); } void softsio8() { compoll(); } /* * Following are all routines needed for COM to act as console * XXX - not tested in this version * XXX - check that the corresponding serial interrupts are never enabled */ #include "i386/i386/cons.h" void siocnprobe(cp) struct consdev *cp; { int unit; /* locate the major number */ for (commajor = 0; commajor < nchrdev; commajor++) if (cdevsw[commajor].d_open == (bogus_open_t) sioopen) break; /* XXX: ick */ unit = CONUNIT; com_addr(unit) = &com_structs[unit]; com_addr(unit)->iobase = CONADDR; /* make sure hardware exists? XXX */ /* initialize required fields */ cp->cn_dev = makedev(commajor, unit); cp->cn_tp = &sio_tty[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; { int unit; unit = UNIT(cp->cn_dev); cominit(unit, comdefaultrate); comconsole = unit; comconsinit = TRUE; } static void cominit(unit, rate) int unit; int rate; { Port_t iobase; int s; iobase = com_addr(unit)->iobase; s = splhigh(); outb(iobase + com_cfcr, CFCR_DLAB); rate = ttspeedtab(comdefaultrate, comspeedtab); outb(iobase + com_data, rate & 0xFF); outb(iobase + com_ier, rate >> 8); outb(iobase + com_cfcr, CFCR_8BITS); /* * XXX - fishy to enable interrupts and then poll. * It shouldn't be necessary to ready the iir. */ outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC); outb(iobase + com_fifo, FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER_14); (void) inb(iobase + com_iir); splx(s); } int siocngetc(dev) dev_t dev; { int c; Port_t iobase; int s; iobase = com_addr(UNIT(dev))->iobase; s = splhigh(); while (!(inb(iobase + com_lsr) & LSR_RXRDY)) ; c = inb(iobase + com_data); (void) inb(iobase + com_iir); splx(s); return (c); } void siocnputc(dev, c) dev_t dev; int c; { Port_t iobase; int s; int timo; iobase = com_addr(UNIT(dev))->iobase; s = splhigh(); #ifdef KGDB if (dev != kgdb_dev) #endif if (!comconsinit) { (void) cominit(UNIT(dev), comdefaultrate); comconsinit = TRUE; } /* wait for any pending transmission to finish */ timo = 50000; while (!(inb(iobase + com_lsr) & LSR_TXRDY) && --timo) ; outb(iobase + com_data, c); /* wait for this transmission to complete */ timo = 1500000; while (!(inb(iobase + com_lsr) & LSR_TXRDY) && --timo) ; /* clear any interrupts generated by this transmission */ (void) inb(iobase + com_iir); splx(s); } /* * 10 Feb 93 Jordan K. Hubbard Added select code * 27 May 93 Rodney W. Grimes Stole the select code from com.c.pl5 */ int sioselect(dev, rw, p) dev_t dev; int rw; struct proc *p; { register struct tty *tp = &sio_tty[UNIT(dev)]; int nread; int s = spltty(); struct proc *selp; switch (rw) { case FREAD: nread = ttnread(tp); if (nread > 0 || ((tp->t_cflag&CLOCAL) == 0 && (tp->t_state&TS_CARR_ON) == 0)) goto win; if (tp->t_rsel && (selp = pfind(tp->t_rsel)) && selp->p_wchan == (caddr_t)&selwait) tp->t_state |= TS_RCOLL; else tp->t_rsel = p->p_pid; break; case FWRITE: if (RB_LEN(&tp->t_out) <= tp->t_lowat) goto win; if (tp->t_wsel && (selp = pfind(tp->t_wsel)) && selp->p_wchan == (caddr_t)&selwait) tp->t_state |= TS_WCOLL; else tp->t_wsel = p->p_pid; break; } splx(s); return (0); win: splx(s); return (1); } #endif /* NSIO > 0 */ Index: head/sys/isa/syscons.c =================================================================== --- head/sys/isa/syscons.c (revision 618) +++ head/sys/isa/syscons.c (revision 619) @@ -1,2416 +1,2414 @@ /*- * 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: @(#)pccons.c 5.11 (Berkeley) 5/21/91 + * from: @(#)syscons.c 1.0 930928 + * $Id$ + * * Heavily modified by Søren Schmidt (sos@login.dkuug.dk) to provide: * * virtual consoles, SYSV ioctl's, ANSI emulation - * - * @(#)syscons.c 1.0 930928 - * Derived from: - * @(#)pccons.c 5.11 (Berkeley) 5/21/91 */ #define STAR_SAVER /* #define FAT_CURSOR /* This breaks on some CGA displays */ #include "param.h" #include "conf.h" #include "ioctl.h" #include "proc.h" #include "user.h" #include "tty.h" #include "uio.h" #include "callout.h" #include "systm.h" #include "kernel.h" #include "syslog.h" #include "errno.h" #include "machine/console.h" #include "malloc.h" #include "i386/isa/icu.h" #include "i386/isa/isa.h" #include "i386/isa/isa_device.h" #include "machine/pc/display.h" #include "i386/i386/cons.h" #include "machine/psl.h" #include "machine/frame.h" #include "sc.h" #include "ddb.h" #include "iso8859.font" #include "kbdtables.h" #if NSC > 0 #ifndef NCONS #define NCONS 12 #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 /* virtual video memory addresses */ #define MONO_BUF (KERNBASE + 0xB0000) #define CGA_BUF (KERNBASE + 0xB8000) #define VGA_BUF (KERNBASE + 0xA0000) #define VIDEOMEM 0x000A0000 #define MEMSIZE 0x00020000 /* misc defines */ #define MAX_ESC_PAR 3 #define TEXT80x25 1 #define TEXT80x50 2 #define COL 80 #define ROW 25 #ifndef XTALSPEED #define XTALSPEED 1193182 /* should be in isa.h */ #endif /* 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 */ typedef struct term_stat { int esc; /* processing escape sequence */ int n_par; /* # of parameters to ESC */ int last_par; /* last parameter # */ int par[MAX_ESC_PAR]; /* contains ESC parameters */ int 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; /* buffer when off screen */ u_short *crtat; /* cursor address */ int posx; /* current X position */ int posy; /* current Y position */ int max_posx; /* X size */ int max_posy; /* X size */ term_stat term; /* terminal emulation stuff */ char cursor_start; /* cursor start line # */ char cursor_end; /* cursor start end # */ 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 default_attr *current_default; static scr_stat cons_scr_stat[NCONS]; static scr_stat *cur_scr_stat = &cons_scr_stat[0]; static scr_stat *new_scp, *old_scp; static term_stat kernel_console; static int switch_in_progress = 0; u_short *Crtat = (u_short *)MONO_BUF; 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; static u_char nlkcnt = 0, clkcnt = 0, slkcnt = 0, alkcnt = 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, nx_scr; static char saved_console = -1; /* saved console number */ static long scrn_blank_time = 0; /* screen saver timout value */ static int scrn_blanked = 0; /* screen saver active flag */ static long scrn_time_stamp; static u_char scr_map[256]; struct tty pccons[NCONS]; struct tty *cur_pccons = &pccons[0]; struct tty *new_pccons; extern int hz; extern struct timeval time; #define CSF_ACTIVE 0x1 /* timeout active */ #define CSF_POLLING 0x2 /* polling for input */ struct pcconsoftc { char cs_flags; char cs_lastc; /* last char sent */ int cs_timo; /* timeouts since interrupt */ u_long cs_wedgecnt; /* times restarted */ } pcconsoftc = {0, 0, 0, 0}; /* special characters */ #define bs 8 #define lf 10 #define cr 13 #define cntlc 3 #define del 0177 #define cntld 4 /* 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); int pcxint(dev_t dev); int pcstart(struct tty *tp); int pccnprobe(struct consdev *cp); int pccninit(struct consdev *cp); int pccnputc(dev_t dev, char c); int pccngetc(dev_t dev); int scintr(dev_t dev, int irq, int cpl); void scrn_saver(int test); static struct tty *get_pccons(dev_t dev); static scr_stat *get_scr_stat(dev_t dev); static int get_scr_num(scr_stat *scp); static void cursor_shape(int start, int end); static void get_cursor_shape(int *start, int *end); static void cursor_pos(void); static void clear_screen(scr_stat *scp); static 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); void consinit(void); static void sput(u_char c); static u_char *get_fstr(u_int c, u_int *len); static update_leds(int which); void reset_cpu(void); u_int sgetc(int noblock); int pcmmap(dev_t dev, int offset, int nprot); int getchar(void); 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 load_font(int segment, int size, char* font); static void save_palette(void); static void load_palette(void); static change_winsize(struct tty *tp, int x, int y); struct isa_driver scdriver = { pcprobe, pcattach, "sc", }; int pcprobe(struct isa_device *dev) { u_char c; int again = 0; /* Enable interrupts and keyboard controller */ kbd_wait(); outb(KB_STAT, KB_WRITE); kbd_cmd(0x4D); /* Start keyboard stuff RESET */ kbd_cmd(KB_RESET); while ((c=inb(KB_DATA)) != KB_ACK) { if ((c == 0xFE) || (c == 0xFF)) { if (!again) printf("KEYBOARD disconnected: RECONNECT \n"); kbd_cmd(KB_RESET); again = 1; } } kbd_wait(); return (IO_KBDSIZE); } int pcattach(struct isa_device *dev) { scr_stat *scp; int start = -1, end = -1, i; 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 (crtc_vga) { #ifdef FAT_CURSOR start = 0; end = 18; #else get_cursor_shape(&start, &end); #endif save_palette(); load_font(0, 16, font_8x16); load_font(1, 8, font_8x8); load_font(2, 14, font_8x14); } current_default = &user_default; for (i = 0; i < NCONS; i++) { scp = &cons_scr_stat[i]; scp->scr = (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.attr = scp->term.std_attr; scp->border = BG_BLACK; scp->cursor_start = start; scp->cursor_end = end; scp->max_posx = COL; scp->max_posy = ROW; scp->bell_pitch = 800; scp->bell_duration = 10; scp->status = 0; scp->pid = 0; scp->proc = NULL; scp->smode.mode = VT_AUTO; if (i > 0) { scp->crt_base = scp->crtat = scp->scr; fillw(scp->term.attr|scr_map[0x20], scp->scr, COL*ROW); } } /* get cursor going */ #ifdef FAT_CURSOR cursor_shape(cons_scr_stat[0].cursor_start, cons_scr_stat[0].cursor_end); #endif cursor_pos(); } static struct tty *get_pccons(dev_t dev) { int i = minor(dev); if (i >= NCONS) return(NULL); return(&pccons[i]); } static scr_stat *get_scr_stat(dev_t dev) { int i = minor(dev); if (i >= NCONS) return(NULL); return(&cons_scr_stat[i]); } static int get_scr_num(scr_stat *scp) /* allways call with legal scp !! */ { int i = 0; while ((i < NCONS) && (cur_scr_stat != &cons_scr_stat[i])) i++; return i; } pcopen(dev_t dev, int flag, int mode, struct proc *p) { struct tty *tp = get_pccons(dev); if (!tp) return(ENXIO); tp->t_oproc = pcstart; tp->t_param = pcparam; tp->t_dev = dev; if ((tp->t_state & TS_ISOPEN) == 0) { tp->t_state |= TS_WOPEN; ttychars(tp); tp->t_iflag = TTYDEF_IFLAG; tp->t_oflag = TTYDEF_OFLAG; tp->t_cflag = TTYDEF_CFLAG; tp->t_lflag = TTYDEF_LFLAG; tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; pcparam(tp, &tp->t_termios); ttsetwater(tp); } else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0) return(EBUSY); tp->t_state |= TS_CARR_ON; return((*linesw[tp->t_line].l_open)(dev, tp)); } pcclose(dev_t dev, int flag, int mode, struct proc *p) { struct tty *tp = get_pccons(dev); struct scr_stat *scp; if (!tp) return(ENXIO); scp = get_scr_stat(tp->t_dev); scp->pid = 0; scp->proc = NULL; scp->smode.mode = VT_AUTO; (*linesw[tp->t_line].l_close)(tp, flag); ttyclose(tp); return(0); } pcread(dev_t dev, struct uio *uio, int flag) { struct tty *tp = get_pccons(dev); if (!tp) return(ENXIO); return((*linesw[tp->t_line].l_read)(tp, uio, flag)); } pcwrite(dev_t dev, struct uio *uio, int flag) { struct tty *tp = get_pccons(dev); if (!tp) return(ENXIO); return((*linesw[tp->t_line].l_write)(tp, uio, flag)); } /* * Got a console interrupt, keyboard action ! * Catch the character, and see who it goes to. */ scintr(dev_t dev, int irq, int cpl) { int c, len; u_char *cp; /* make screensaver happy */ scrn_time_stamp = time.tv_sec; if (scrn_blanked) scrn_saver(0); c = sgetc(1); if (c & 0x100) return; if ((cur_pccons->t_state & TS_ISOPEN) == 0) return; if (pcconsoftc.cs_flags & CSF_POLLING) return; if (c < 0x100) (*linesw[cur_pccons->t_line].l_rint)(c & 0xFF, cur_pccons); else if (cp = get_fstr((u_int)c, (u_int *)&len)) { while (len-- > 0) (*linesw[cur_pccons->t_line].l_rint) (*cp++ & 0xFF, cur_pccons); } } /* * Set line parameters */ 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); } pcioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) { int i, error; struct tty *tp; struct syscframe *fp; scr_stat *scp; tp = get_pccons(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_80x25TEXT: /* set 80x25 text mode */ if (!crtc_vga) return ENXIO; scp->mode = TEXT80x25; scp->max_posy = 25; free(scp->scr, M_DEVBUF); scp->scr = (u_short *)malloc(scp->max_posx*scp->max_posy*2, M_DEVBUF, M_NOWAIT); if (scp != cur_scr_stat) scp->crt_base = scp->scr; set_mode(scp); clear_screen(scp); change_winsize(tp, scp->max_posx, scp->max_posy); return 0; case CONS_80x50TEXT: /* set 80x50 text mode */ if (!crtc_vga) return ENXIO; scp->mode = TEXT80x50; scp->max_posy = 50; free(scp->scr, M_DEVBUF); scp->scr = (u_short *)malloc(scp->max_posx*scp->max_posy*2, M_DEVBUF, M_NOWAIT); if (scp != cur_scr_stat) scp->crt_base = scp->scr; set_mode(scp); clear_screen(scp); change_winsize(tp, scp->max_posx, scp->max_posy); return 0; case CONS_GETVERS: /* get version number */ *(int*)data = 0x100; /* version 1.0 */ return 0; case CONS_GETINFO: /* get current (virtual) console info */ if (*data == sizeof(struct vid_info)) { vid_info_t *ptr = (vid_info_t*)data; ptr->m_num = get_scr_num(scp); ptr->mv_col = scp->posx; ptr->mv_row = scp->posy; ptr->mv_csz = scp->max_posx; ptr->mv_rsz = scp->max_posy; 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++) if (!(pccons[i].t_state & TS_ISOPEN)) { *data = i + 1; return 0; } return EINVAL; /* NOT REACHED */ case VT_GETACTIVE: /* return number of active virtual console */ *data = get_scr_num(scp) + 1; return 0; 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_scr_stat) return 0; while ((error=tsleep(&scp->smode, PZERO|PCATCH, "waitvt", 0)) == ERESTART) ; } else while ((error=tsleep(&cons_scr_stat[*data].smode, PZERO|PCATCH, "waitvt", 0)) == ERESTART) ; return error; case KDENABIO: /* allow io operations */ fp = (struct syscframe *)p->p_regs; fp->sf_eflags |= PSL_IOPL; return 0; case KDDISABIO: /* disallow io operations (default) */ fp = (struct syscframe *)p->p_regs; fp->sf_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) { load_font(0, 16, font_8x16); load_font(1, 8, font_8x8); load_font(2, 14, font_8x14); 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_scr_stat) 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_scr_stat) update_leds(scp->status & LED_MASK); 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 (*(u_char*)data < 0x80) { kbd_cmd(KB_SETRAD); kbd_cmd(*data & 0x7f); return 0; } return EINVAL; 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 */ 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_scr_stat) sysbeep(scp->bell_pitch, scp->bell_duration); return 0; case KIOCSOUND: /* make tone (*data) hz */ if (scp == cur_scr_stat) { if (*(int*)data) { int pitch = XTALSPEED/(*(int*)data); /* enable counter 2 */ outb(0x61, inb(0x61) | 3); /* set command for counter 2, 2 byte write */ outb(0x43, 0xb6); /* set pitch */ outb(0x42, pitch); outb(0x42, (pitch>>8)); } else { /* disable counter 2 */ outb(0x61, inb(0x61) & 0xFC); } } 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_scr_stat) update_leds(scp->status & LED_MASK); 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_8x8, sizeof(font_8x8)); load_font(1, 8, font_8x8); return 0; case GIO_FONT8x8: /* get 8x8 dot font */ if (!crtc_vga) return ENXIO; bcopy(&font_8x8, data, sizeof(font_8x8)); return 0; case PIO_FONT8x14: /* set 8x14 dot font */ if (!crtc_vga) return ENXIO; bcopy(data, &font_8x14, sizeof(font_8x14)); load_font(2, 14, font_8x14); return 0; case GIO_FONT8x14: /* get 8x14 dot font */ if (!crtc_vga) return ENXIO; bcopy(&font_8x14, data, sizeof(font_8x14)); return 0; case PIO_FONT8x16: /* set 8x16 dot font */ if (!crtc_vga) return ENXIO; bcopy(data, &font_8x16, sizeof(font_8x16)); load_font(0, 16, font_8x16); return 0; case GIO_FONT8x16: /* get 8x16 dot font */ if (!crtc_vga) return ENXIO; bcopy(&font_8x16, data, sizeof(font_8x16)); return 0; case CONSOLE_X_MODE_ON: /* just to be compatible */ if (saved_console < 0) { saved_console = get_scr_num(cur_scr_stat); switch_scr(minor(dev)); fp = (struct syscframe *)p->p_regs; fp->sf_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 syscframe *)p->p_regs; fp->sf_eflags &= ~PSL_IOPL; if (crtc_vga) { load_font(0, 16, font_8x16); load_font(1, 8, font_8x8); load_font(2, 14, font_8x14); 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(XTALSPEED/((int*)data)[0], ((int*)data)[1]*hz/3000); else sysbeep(0x31b, hz/4); return 0; default: break; } error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); if (error >= 0) return(error); error = ttioctl(tp, cmd, data, flag); if (error >= 0) return(error); return(ENOTTY); } pcxint(dev_t dev) { pccons[minor(dev)].t_state &= ~TS_BUSY; pcconsoftc.cs_timo = 0; if (pccons[minor(dev)].t_line) (*linesw[pccons[minor(dev)].t_line].l_start) (&pccons[minor(dev)]); else pcstart(&pccons[minor(dev)]); } pcstart(struct tty *tp) { int c, s; scr_stat *scp = get_scr_stat(tp->t_dev); s = spltty(); if (!(tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))) for (;;) { if (RB_LEN(&tp->t_out) <= tp->t_lowat) { if (tp->t_state & TS_ASLEEP) { tp->t_state &= ~TS_ASLEEP; wakeup((caddr_t)&tp->t_out); } if (tp->t_wsel) { selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); tp->t_wsel = 0; tp->t_state &= ~TS_WCOLL; } } if (RB_LEN(&tp->t_out) == 0) break; if (scp->status & SLKED) break; c = getc(&tp->t_out); tp->t_state |= TS_BUSY; splx(s); ansi_put(scp, c); s = spltty(); tp->t_state &= ~TS_BUSY; } splx(s); } pccnprobe(struct consdev *cp) { int maj; /* locate the major number */ for (maj = 0; maj < nchrdev; maj++) if (cdevsw[maj].d_open == pcopen) break; /* initialize required fields */ cp->cn_dev = makedev(maj, 0); cp->cn_tp = &pccons[0]; cp->cn_pri = CN_INTERNAL; } pccninit(struct consdev *cp) { } pccnputc(dev_t dev, char c) { int pos; if (cur_scr_stat->status & UNKNOWN_MODE) return; if (c == '\n') sput('\r'); sput(c); pos = cur_scr_stat->crtat - cur_scr_stat->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); } } pccngetc(dev_t dev) { int c, s; s = spltty(); /* block scintr while we poll */ c = sgetc(0); splx(s); if (c == '\r') c = '\n'; return(c); } #if !defined(STAR_SAVER) && !defined(SNAKE_SAVER) void scrn_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); } } #endif #if defined(STAR_SAVER) || defined(SNAKE_SAVER) static u_long rand_next = 1; static rand() { return ((rand_next = rand_next * 1103515245 + 12345) & 0x7FFFFFFF); } #endif #ifdef STAR_SAVER /* * Alternate saver that got its inspiration from a well known utility * package for an unfamous OS. */ #define NUM_STARS 50 void scrn_saver(int test) { scr_stat *scp = cur_scr_stat; 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, scp->max_posx * scp->max_posy * 2); fillw((FG_LIGHTGREY|BG_BLACK)<<8 | scr_map[0x20], Crtat, scp->max_posx * scp->max_posy); set_border(0); i = scp->max_posy * scp->max_posx + 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; imax_posx*scp->max_posy); stars[i][1] = 0; } } cell = rand() % NUM_STARS; *((u_short*)(Crtat + stars[cell][0])) = scr_map[pattern[stars[cell][1]]] | colors[rand()%sizeof(colors)] << 8; if ((stars[cell][1]+=(rand()%4)) >= sizeof(pattern)-1) { stars[cell][0] = rand() % (scp->max_posx*scp->max_posy); stars[cell][1] = 0; } } else { if (scrn_blanked) { bcopy(scp->scr, Crtat, scp->max_posx*scp->max_posy*2); cur_cursor_pos = -1; set_border(scp->border); scrn_blanked = 0; } } } #endif #ifdef SNAKE_SAVER /* * alternative screen saver for cards that do not like blanking */ void scrn_saver(int test) { const char saves[] = {"FreeBSD"}; static u_char *savs[sizeof(saves)-1]; static int dirx, diry; int f; scr_stat *scp = cur_scr_stat; if (test) { if (!scrn_blanked) { bcopy(Crtat, scp->scr, scp->max_posx * scp->max_posy * 2); fillw((FG_LIGHTGREY|BG_BLACK)<<8 | scr_map[0x20], Crtat, scp->max_posx * scp->max_posy); set_border(0); dirx = (scp->posx ? 1 : -1); diry = (scp->posy ? scp->max_posx : -scp->max_posx); for (f=0; f< sizeof(saves)-1; f++) savs[f] = (u_char *)Crtat + 2 * (scp->posx+scp->posy*scp->max_posx); *(savs[0]) = scr_map[*saves]; f = scp->max_posy * scp->max_posx + 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->max_posx) == 0 || (f % scp->max_posx) == scp->max_posx - 1 || (rand() % 50) == 0) dirx = -dirx; if ((f / scp->max_posx) == 0 || (f / scp->max_posx) == scp->max_posy - 1 || (rand() % 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, Crtat, scp->max_posx * scp->max_posy * 2); cur_cursor_pos = -1; set_border(scp->border); scrn_blanked = 0; } } } #endif 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); } 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; } static void cursor_pos(void) { int pos; if (cur_scr_stat->status & UNKNOWN_MODE) return; if (scrn_blank_time && (time.tv_sec > scrn_time_stamp+scrn_blank_time)) scrn_saver(1); pos = cur_scr_stat->crtat - cur_scr_stat->crt_base; if (!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(cursor_pos, 0, hz/20); } static void clear_screen(scr_stat *scp) { move_crsr(scp, 0, 0); fillw(scp->term.attr | scr_map[0x20], scp->crt_base, scp->max_posx * scp->max_posy); } static switch_scr(u_int next_scr) { if (in_putc) { /* don't switch if in putc */ nx_scr = next_scr+1; return 0; } if (switch_in_progress && (cur_scr_stat->proc != pfind(cur_scr_stat->pid))) switch_in_progress = 0; if (next_scr >= NCONS || switch_in_progress) { sysbeep(800, hz/4); return -1; } switch_in_progress = 1; old_scp = cur_scr_stat; new_scp = &cons_scr_stat[next_scr]; wakeup(&new_scp->smode); if (new_scp == old_scp) { switch_in_progress = 0; return 0; } new_pccons = &pccons[next_scr]; /* 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) { bcopy(Crtat, old_scp->scr, old_scp->max_posx * old_scp->max_posy * 2); old_scp->crt_base = old_scp->scr; move_crsr(old_scp, old_scp->posx, old_scp->posy); cur_scr_stat = new_scp; cur_pccons = new_pccons; if (old_scp->status & KBD_RAW_MODE || new_scp->status & KBD_RAW_MODE) shfts = ctls = alts = 0; update_leds(new_scp->status & LED_MASK); set_mode(new_scp); new_scp->crt_base = Crtat; move_crsr(new_scp, new_scp->posx, new_scp->posy); bcopy(new_scp->scr, Crtat, new_scp->max_posx * new_scp->max_posy * 2); nx_scr = 0; } static void move_crsr(scr_stat *scp, int x, int y) { if (x < 0 || y < 0 || x >= scp->max_posx || y >= scp->max_posy) return; scp->posx = x; scp->posy = y; scp->crtat = scp->crt_base + scp->posy * scp->max_posx + scp->posx; } 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_par = -1; for (i = scp->term.n_par; i < MAX_ESC_PAR; i++) scp->term.par[i] = 1; scp->term.n_par = 0; return; case 'M': /* Move cursor up 1 line, scroll if at top */ if (scp->posy > 0) move_crsr(scp, scp->posx, scp->posy - 1); else { move_up(scp->crt_base, scp->crt_base + scp->max_posx, (scp->max_posy - 1) * scp->max_posx); fillw(scp->term.attr | scr_map[0x20], scp->crt_base, scp->max_posx); } 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.n_par < MAX_ESC_PAR) { if (scp->term.last_par != scp->term.n_par) { scp->term.last_par = scp->term.n_par; scp->term.par[scp->term.n_par] = 0; } else scp->term.par[scp->term.n_par] *= 10; scp->term.par[scp->term.n_par] += c - '0'; return; } } scp->term.n_par = scp->term.last_par + 1; switch (c) { case ';': if (scp->term.n_par < MAX_ESC_PAR) return; break; case '=': scp->term.esc = 3; scp->term.last_par = -1; for (i = scp->term.n_par; i < MAX_ESC_PAR; i++) scp->term.par[i] = 1; scp->term.n_par = 0; return; case 'A': /* up n rows */ n = scp->term.par[0]; if (n < 1) n = 1; move_crsr(scp, scp->posx, scp->posy - n); break; case 'B': /* down n rows */ n = scp->term.par[0]; if (n < 1) n = 1; move_crsr(scp, scp->posx, scp->posy + n); break; case 'C': /* right n columns */ n = scp->term.par[0]; if (n < 1) n = 1; move_crsr(scp, scp->posx + n, scp->posy); break; case 'D': /* left n columns */ n = scp->term.par[0]; if (n < 1) n = 1; move_crsr(scp, scp->posx - n, scp->posy); break; case 'E': /* cursor to start of line n lines down */ n = scp->term.par[0]; if (n < 1) n = 1; move_crsr(scp, 0, scp->posy + n); break; case 'F': /* cursor to start of line n lines up */ n = scp->term.par[0]; if (n < 1) n = 1; move_crsr(scp, 0, scp->posy - n); break; case 'f': /* System V consoles .. */ case 'H': /* Cursor move */ if (scp->term.n_par == 0) move_crsr(scp, 0, 0); else if (scp->term.n_par == 2) move_crsr(scp, scp->term.par[1] - 1, scp->term.par[0] - 1); break; case 'J': /* Clear all or part of display */ if (scp->term.n_par == 0) n = 0; else n = scp->term.par[0]; switch (n) { case 0: /* clear form cursor to end of display */ fillw(scp->term.attr | scr_map[0x20], scp->crtat, scp->crt_base + scp->max_posx * scp->max_posy - scp->crtat); break; case 1: /* clear from beginning of display to cursor */ fillw(scp->term.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.n_par == 0) n = 0; else n = scp->term.par[0]; switch (n) { case 0: /* clear form cursor to end of line */ fillw(scp->term.attr | scr_map[0x20], scp->crtat, scp->max_posx - scp->posx); break; case 1: /* clear from beginning of line to cursor */ fillw(scp->term.attr|scr_map[0x20], scp->crtat - (scp->max_posx - scp->posx), (scp->max_posx - scp->posx) + 1); break; case 2: /* clear entire line */ fillw(scp->term.attr|scr_map[0x20], scp->crtat - (scp->max_posx - scp->posx), scp->max_posx); break; } break; case 'L': /* Insert n lines */ n = scp->term.par[0]; if (n < 1) n = 1; if (n > scp->max_posy - scp->posy) n = scp->max_posy - scp->posy; src = scp->crt_base + scp->posy * scp->max_posx; dst = src + n * scp->max_posx; count = scp->max_posy - (scp->posy + n); move_up(src, dst, count * scp->max_posx); fillw(scp->term.attr | scr_map[0x20], src, n * scp->max_posx); break; case 'M': /* Delete n lines */ n = scp->term.par[0]; if (n < 1) n = 1; if (n > scp->max_posy - scp->posy) n = scp->max_posy - scp->posy; dst = scp->crt_base + scp->posy * scp->max_posx; src = dst + n * scp->max_posx; count = scp->max_posy - (scp->posy + n); move_down(src, dst, count * scp->max_posx); src = dst + count * scp->max_posx; fillw(scp->term.attr | scr_map[0x20], src, n * scp->max_posx); break; case 'P': /* Delete n chars */ n = scp->term.par[0]; if (n < 1) n = 1; if (n > scp->max_posx - scp->posx) n = scp->max_posx - scp->posx; dst = scp->crtat; src = dst + n; count = scp->max_posx - (scp->posx + n); move_down(src, dst, count); src = dst + count; fillw(scp->term.attr | scr_map[0x20], src, n); break; case '@': /* Insert n chars */ n = scp->term.par[0]; if (n < 1) n = 1; if (n > scp->max_posx - scp->posx) n = scp->max_posx - scp->posx; src = scp->crtat; dst = src + n; count = scp->max_posx - (scp->posx + n); move_up(src, dst, count); fillw(scp->term.attr | scr_map[0x20], src, n); break; case 'S': /* scroll up n lines */ n = scp->term.par[0]; if (n < 1) n = 1; bcopy(scp->crt_base + (scp->max_posx * n), scp->crt_base, scp->max_posx * (scp->max_posy - n) * sizeof(u_short)); fillw(scp->term.attr | scr_map[0x20], scp->crt_base + scp->max_posx * (scp->max_posy - 1), scp->max_posx); break; case 'T': /* scroll down n lines */ n = scp->term.par[0]; if (n < 1) n = 1; bcopy(scp->crt_base, scp->crt_base + (scp->max_posx * n), scp->max_posx * (scp->max_posy - n) * sizeof(u_short)); fillw(scp->term.attr | scr_map[0x20], scp->crt_base, scp->max_posx); break; case 'X': /* delete n characters in line */ n = scp->term.par[0]; if (n < 1) n = 1; fillw(scp->term.attr | scr_map[0x20], scp->crt_base + scp->posx + ((scp->max_posx*scp->posy) * sizeof(u_short)), n); break; case 'Z': /* move n tabs backwards */ n = scp->term.par[0]; if (n < 1) n = 1; if ((i = scp->posx & 0xf8) == scp->posx) i -= 8*n; else i -= 8*(n-1); if (i < 0) i = 0; move_crsr(scp, i, scp->posy); break; case '`': /* move cursor to column n */ n = scp->term.par[0]; if (n < 1) n = 1; move_crsr(scp, n, scp->posy); break; case 'a': /* move cursor n columns to the right */ n = scp->term.par[0]; if (n < 1) n = 1; move_crsr(scp, scp->posx + n, scp->posy); break; case 'd': /* move cursor to row n */ n = scp->term.par[0]; if (n < 1) n = 1; move_crsr(scp, scp->posx, n); break; case 'e': /* move cursor n rows down */ n = scp->term.par[0]; if (n < 1) n = 1; move_crsr(scp, scp->posx, scp->posy + n); break; case 'm': /* change attribute */ if (scp->term.n_par == 0) n = 0; else n = scp->term.par[0]; switch (n) { case 0: /* back to normal */ scp->term.attr = scp->term.std_attr; break; case 1: /* highlight (bold) */ scp->term.attr &= 0xFF00; scp->term.attr |= 0x0800; break; case 4: /* highlight (underline) */ scp->term.attr &= 0x0F00; scp->term.attr |= 0x0800; break; case 5: /* blink */ scp->term.attr &= 0xFF00; scp->term.attr |= 0x8000; break; case 7: /* reverse video */ scp->term.attr = scp->term.rev_attr; break; case 30: case 31: case 32: case 33: /* set fg color */ case 34: case 35: case 36: case 37: scp->term.attr = (scp->term.attr & 0xF0FF) | (ansi_col[(n - 30) & 7] << 8); break; case 40: case 41: case 42: case 43: /* set bg color */ case 44: case 45: case 46: case 47: scp->term.attr = (scp->term.attr & 0x0FFF) | (ansi_col[(n - 40) & 7] << 12); break; } break; case 'x': if (scp->term.n_par == 0) n = 0; else n = scp->term.par[0]; switch (n) { case 0: /* reset attributes */ scp->term.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.attr = scp->term.std_attr = (scp->term.std_attr & 0x0F00) | (ansi_col[(scp->term.par[1])&0x0F]<<12); break; case 2: /* set ansi foreground */ scp->term.attr = scp->term.std_attr = (scp->term.std_attr & 0xF000) | (ansi_col[(scp->term.par[1])&0x0F]<<8); break; case 3: /* set ansi attribute directly */ scp->term.attr = scp->term.std_attr = (scp->term.par[1]&0xFF)<<8; break; case 5: /* set ansi reverse video background */ scp->term.rev_attr = (scp->term.rev_attr & 0x0F00) | (ansi_col[(scp->term.par[1])&0x0F]<<12); break; case 6: /* set ansi reverse video foreground */ scp->term.rev_attr = (scp->term.rev_attr & 0xF000) | (ansi_col[(scp->term.par[1])&0x0F]<<8); break; case 7: /* set ansi reverse video directly */ scp->term.rev_attr = (scp->term.par[1]&0xFF)<<8; break; } break; case 'z': /* switch to (virtual) console n */ if (scp->term.n_par == 1) switch_scr(scp->term.par[0]); break; } } else if (scp->term.esc == 3) { if (c >= '0' && c <= '9') { if (scp->term.n_par < MAX_ESC_PAR) { if (scp->term.last_par != scp->term.n_par) { scp->term.last_par = scp->term.n_par; scp->term.par[scp->term.n_par] = 0; } else scp->term.par[scp->term.n_par] *= 10; scp->term.par[scp->term.n_par] += c - '0'; return; } } scp->term.n_par = scp->term.last_par + 1; switch (c) { case ';': if (scp->term.n_par < MAX_ESC_PAR) return; break; case 'A': /* set display border color */ if (scp->term.n_par == 1) scp->border=scp->term.par[0] & 0xff; if (scp == cur_scr_stat) set_border(scp->border); break; case 'B': /* set bell pitch and duration */ if (scp->term.n_par == 2) { scp->bell_pitch = scp->term.par[0]; scp->bell_duration = scp->term.par[1]*10; } break; case 'C': /* set cursor shape (start & end line) */ if (scp->term.n_par == 2) { scp->cursor_start = scp->term.par[0] & 0x1F; scp->cursor_end = scp->term.par[1] & 0x1F; if (scp == cur_scr_stat) cursor_shape(scp->cursor_start, scp->cursor_end); } break; case 'F': /* set ansi foreground */ if (scp->term.n_par == 1) scp->term.attr = scp->term.std_attr = (scp->term.std_attr & 0xF000) | ((scp->term.par[0] & 0x0F) << 8); break; case 'G': /* set ansi background */ if (scp->term.n_par == 1) scp->term.attr = scp->term.std_attr = (scp->term.std_attr & 0x0F00) | ((scp->term.par[0] & 0x0F) << 12); break; case 'H': /* set ansi reverse video foreground */ if (scp->term.n_par == 1) scp->term.rev_attr = (scp->term.rev_attr & 0xF000) | ((scp->term.par[0] & 0x0F) << 8); break; case 'I': /* set ansi reverse video background */ if (scp->term.n_par == 1) scp->term.rev_attr = (scp->term.rev_attr & 0x0F00) | ((scp->term.par[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_scr_stat) { 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.n_par = 0; break; case 0x07: if (scp == cur_scr_stat) sysbeep(scp->bell_pitch, scp->bell_duration); break; case '\t': /* non-destructive tab */ scp->crtat += (8 - scp->posx % 8); scp->posx += (8 - scp->posx % 8); break; case '\b': /* non-destructive backspace */ if (scp->crtat > scp->crt_base) { scp->crtat--; if (scp->posx > 0) scp->posx--; else { scp->posx += scp->max_posx - 1; scp->posy--; } } break; case '\r': /* return to pos 0 */ move_crsr(scp, 0, scp->posy); break; case '\n': /* newline, same pos */ scp->crtat += scp->max_posx; scp->posy++; break; case '\f': /* form feed, clears screen */ clear_screen(scp); break; default: /* Print only printables */ *scp->crtat = (scp->term.attr | scr_map[c]); scp->crtat++; if (++scp->posx >= scp->max_posx) { scp->posx = 0; scp->posy++; } break; } if (scp->crtat >= scp->crt_base + scp->max_posy * scp->max_posx) { bcopy(scp->crt_base + scp->max_posx, scp->crt_base, scp->max_posx * (scp->max_posy - 1) * sizeof(u_short)); fillw(scp->term.attr | scr_map[0x20], scp->crt_base + scp->max_posx * (scp->max_posy - 1), scp->max_posx); scp->crtat -= scp->max_posx; scp->posy--; } in_putc--; if (nx_scr) switch_scr(nx_scr - 1); } void consinit(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 consinit 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; cons_scr_stat[0].crtat = crtat; cons_scr_stat[0].crt_base = Crtat; cons_scr_stat[0].term.esc = 0; cons_scr_stat[0].term.std_attr = current_default->std_attr; cons_scr_stat[0].term.rev_attr = current_default->rev_attr; cons_scr_stat[0].term.attr = current_default->std_attr; cons_scr_stat[0].posx = cursorat % COL; cons_scr_stat[0].posy = cursorat / COL; cons_scr_stat[0].border = BG_BLACK;; cons_scr_stat[0].max_posx = COL; cons_scr_stat[0].max_posy = ROW; cons_scr_stat[0].status = 0; cons_scr_stat[0].pid = 0; cons_scr_stat[0].proc = NULL; cons_scr_stat[0].smode.mode = VT_AUTO; cons_scr_stat[0].bell_pitch = 800; cons_scr_stat[0].bell_duration = 10; kernel_console.esc = 0; kernel_console.std_attr = kernel_default.std_attr; kernel_console.rev_attr = kernel_default.rev_attr; kernel_console.attr = kernel_default.std_attr; /* initialize mapscrn array to */ for (i=0; iterm; scp->term = kernel_console; current_default = &kernel_default; ansi_put(scp, c); kernel_console = scp->term; current_default = &user_default; scp->term = save; } 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 update_leds(int which) { u_char xlate_leds[8] = { 0, 4, 2, 6, 1, 5, 3, 7 }; kbd_cmd(KB_SETLEDS); /* LED Command */ kbd_cmd(xlate_leds[which & LED_MASK]); kbd_wait(); } volatile void reset_cpu(void) { while (1) { kbd_cmd(KB_RESET_CPU); /* Reset Command */ DELAY(4000000); kbd_cmd(KB_RESET); /* Keyboard Reset Command */ } } /* * sgetc(noblock) : get a character from the keyboard. * If noblock = 0 wait until a key is gotten. Otherwise return a 0x100. */ u_int sgetc(int noblock) { u_char val, code, release; 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) val = inb(KB_DATA); else if (noblock) return(0x100); else goto next_code; if (cur_scr_stat->status & KBD_RAW_MODE) return val; code = val & 0x7F; release = val & 0x80; /* Check for cntl-alt-del */ if ((code == 83) && ctls && alts) cpu_reset(); #if NDDB > 0 /* Check for cntl-alt-esc */ if ((val == 1) && ctls && alts) { /* if debugger called, try to switch to console 0 */ if (cur_scr_stat->smode.mode == VT_AUTO && cons_scr_stat[0].smode.mode == VT_AUTO) switch_scr(0); Debugger(); return(0x100); } #endif switch (esc_flag) { case 0x00: /* normal scancode */ switch(code) { case 0x38: /* left alt (compose key) */ if (release && compose) { compose = 0; if (chr > 255) { sysbeep(500, hz/4); chr = 0; } } else { if (!compose) { compose = 1; chr = 0; } } break; case 0x60: case 0x61: esc_flag = code; goto next_code; } break; case 0x60: /* 0xE0 prefix */ esc_flag = 0; switch (code) { case 0x1c: /* right enter key */ code = 0x59; break; case 0x1d: /* right ctrl key */ code = 0x5a; break; case 0x35: /* keypad divide key */ code = 0x5b; break; case 0x37: /* print scrn key */ code = 0x5c; break; case 0x38: /* right alt key (alt gr) */ code = 0x5d; break; case 0x47: /* grey home key */ code = 0x5e; break; case 0x48: /* grey up arrow key */ code = 0x5f; break; case 0x49: /* grey page up key */ code = 0x60; break; case 0x4b: /* grey left arrow key */ code = 0x61; break; case 0x4d: /* grey right arrow key */ code = 0x62; break; case 0x4f: /* grey end key */ code = 0x63; break; case 0x50: /* grey down arrow key */ code = 0x64; break; case 0x51: /* grey page down key */ code = 0x65; break; case 0x52: /* grey insert key */ code = 0x66; break; case 0x53: /* grey delete key */ code = 0x67; break; default: /* ignore everything else */ goto next_code; } break; case 0x61: /* 0xE1 prefix */ esc_flag = 0; if (code == 0x1D) esc_flag = 0x1D; goto next_code; /* NOT REACHED */ case 0x1D: /* pause / break */ esc_flag = 0; if (code != 0x45) goto next_code; code = 0x68; break; } if (compose) { switch (code) { case 0x47: case 0x48: /* keypad 7,8,9 */ case 0x49: if (!release) chr = (code - 0x40) + chr*10; goto next_code; case 0x4b: case 0x4c: /* keypad 4,5,6 */ case 0x4d: if (!release) chr = (code - 0x47) + chr*10; goto next_code; case 0x4f: case 0x50: /* keypad 1,2,3 */ case 0x51: if (!release) chr = (code - 0x4e) + chr*10; goto next_code; case 0x52: /* keypad 0 */ if (!release) chr *= 10; goto next_code; case 0x38: /* left alt key */ break; default: if (chr) { compose = chr = 0; sysbeep(500, hz/4); goto next_code; } break; } } state = (shfts ? 1 : 0 ) | (2 * (ctls ? 1 : 0)) | (4 * (alts ? 1 : 0)); if ((!agrs && (cur_scr_stat->status & ALKED)) || (agrs && !(cur_scr_stat->status & ALKED))) code += ALTGR_OFFSET; key = &key_map.key[code]; if ( ((key->flgs & FLAG_LOCK_C) && (cur_scr_stat->status & CLKED)) || ((key->flgs & FLAG_LOCK_N) && (cur_scr_stat->status & NLKED)) ) state ^= 1; /* Check for make/break */ action = key->map[state]; if (release) { /* 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; } } 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_scr_stat->status & NLKED) cur_scr_stat->status &= ~NLKED; else cur_scr_stat->status |= NLKED; update_leds(cur_scr_stat->status & LED_MASK); } break; case CLK: if (!clkcnt) { clkcnt++; if (cur_scr_stat->status & CLKED) cur_scr_stat->status &= ~CLKED; else cur_scr_stat->status |= CLKED; update_leds(cur_scr_stat->status & LED_MASK); } break; case SLK: if (!slkcnt) { slkcnt++; if (cur_scr_stat->status & SLKED) { cur_scr_stat->status &= ~SLKED; pcstart(&pccons[get_scr_num(cur_scr_stat)]); } else cur_scr_stat->status |= SLKED; update_leds(cur_scr_stat->status & LED_MASK); } break; case ALK: if (!alkcnt) { alkcnt++; if (cur_scr_stat->status & ALKED) cur_scr_stat->status &= ~ALKED; else cur_scr_stat->status |= ALKED; } break; /* NON-LOCKING KEYS */ 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 NOP: break; default: if (action >= F_SCR && action <= L_SCR) { switch_scr(action - F_SCR); break; } if (action >= F_FN && action <= L_FN) { return(action | FKEY); } return(action); } } else return(action); } goto next_code; } /* July '93, jkh. Added in for init_main.c */ void cons_highlight() { cons_scr_stat[0].term.attr &= 0xFF00; cons_scr_stat[0].term.attr |= 0x0800; } void cons_normal() { cons_scr_stat[0].term.attr = cons_scr_stat[0].term.std_attr; } int getchar(void) { char thechar; int s; pcconsoftc.cs_flags |= CSF_POLLING; s = splhigh(); sput('>'); thechar = (char) sgetc(0); pcconsoftc.cs_flags &= ~CSF_POLLING; splx(s); switch (thechar) { default: if (thechar >= scr_map[0x20]) sput(thechar); return(thechar); case cr: case lf: sput(cr); sput(lf); return(lf); case bs: case del: sput(bs); sput(scr_map[0x20]); sput(bs); return(thechar); case cntld: sput('^'); sput('D'); sput('\r'); sput('\n'); return(0); } } 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; for (i=0; i<10000; i++) if ((inb(KB_STAT) & KB_READY) == 0) break; } static void kbd_cmd(u_char command) { kbd_wait(); outb(KB_DATA, command); } static void set_mode(scr_stat *scp) { u_char byte; int s; if (scp != cur_scr_stat) return; /* (re)activate cursor */ untimeout(cursor_pos, 0); cursor_pos(); /* 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: return; } 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 load_font(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++) *((char *)atdevbase+(segment*0x4000)+(ch*32)+line) = font[(ch*size)+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 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 */ Index: head/sys/isa/timerreg.h =================================================================== --- head/sys/isa/timerreg.h (revision 618) +++ head/sys/isa/timerreg.h (revision 619) @@ -1,89 +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. * - * $Header: timerreg.h,v 1.2 93/02/28 15:08:58 mccanne Exp $ + * 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 */