summaryrefslogtreecommitdiffstats
path: root/sys/dev
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/ed/if_ed.c2487
-rw-r--r--sys/dev/ed/if_edreg.h962
-rw-r--r--sys/dev/ep/if_ep.c993
-rw-r--r--sys/dev/ep/if_epreg.h295
-rw-r--r--sys/dev/fdc/fdc.c1255
-rw-r--r--sys/dev/fdc/fdcreg.h65
-rw-r--r--sys/dev/ic/i8237.h11
-rw-r--r--sys/dev/ic/i82586.h325
-rw-r--r--sys/dev/ic/nec765.h72
-rw-r--r--sys/dev/ic/ns16550.h51
-rw-r--r--sys/dev/ie/if_ie.c1801
-rw-r--r--sys/dev/ie/if_iereg.h24
-rw-r--r--sys/dev/kbd/kbdtables.h859
-rw-r--r--sys/dev/mcd/mcd.c1335
-rw-r--r--sys/dev/mcd/mcdreg.h159
-rw-r--r--sys/dev/mse/mse.c499
-rw-r--r--sys/dev/ppbus/lptio.h24
-rw-r--r--sys/dev/sio/sio.c1920
-rw-r--r--sys/dev/sio/sioreg.h114
-rw-r--r--sys/dev/speaker/speaker.h30
-rw-r--r--sys/dev/speaker/spkr.c541
-rw-r--r--sys/dev/syscons/syscons.c2660
22 files changed, 16482 insertions, 0 deletions
diff --git a/sys/dev/ed/if_ed.c b/sys/dev/ed/if_ed.c
new file mode 100644
index 0000000..26e3ebd
--- /dev/null
+++ b/sys/dev/ed/if_ed.c
@@ -0,0 +1,2487 @@
+/*
+ * Device driver for National Semiconductor DS8390/WD83C690 based ethernet
+ * adapters. By David Greenman, 29-April-1993
+ *
+ * Copyright (C) 1993, David Greenman. 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.
+ *
+ * Currently supports the Western Digital/SMC 8003 and 8013 series,
+ * the SMC Elite Ultra (8216), the 3Com 3c503, the NE1000 and NE2000,
+ * and a variety of similar clones.
+ *
+ */
+
+/*
+ * $Id: if_ed.c,v 1.36 1994/04/10 20:06:26 davidg Exp $
+ */
+
+#include "ed.h"
+#if NED > 0
+/* bpfilter included here in case it is needed in future net includes */
+#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"
+
+#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.h"
+#include "i386/isa/isa_device.h"
+#include "i386/isa/icu.h"
+#include "i386/isa/if_edreg.h"
+
+#include "i386/include/pio.h"
+
+/* For backwards compatibility */
+#ifndef IFF_ALTPHYS
+#define IFF_ALTPHYS IFF_LINK0
+#endif
+
+/*
+ * ed_softc: per line info and status
+ */
+struct ed_softc {
+ struct arpcom arpcom; /* ethernet common */
+
+ char *type_str; /* pointer to type string */
+ u_char vendor; /* interface vendor */
+ u_char type; /* interface type code */
+
+ u_short asic_addr; /* ASIC I/O bus address */
+ u_short nic_addr; /* NIC (DS8390) I/O bus address */
+
+/*
+ * The following 'proto' variable is part of a work-around for 8013EBT asics
+ * being write-only. It's sort of a prototype/shadow of the real thing.
+ */
+ u_char wd_laar_proto;
+ u_char isa16bit; /* width of access to card 0=8 or 1=16 */
+ int is790; /* set by the probe code if the card is 790 based */
+
+ caddr_t bpf; /* BPF "magic cookie" */
+ caddr_t mem_start; /* NIC memory start address */
+ caddr_t mem_end; /* NIC memory end address */
+ u_long mem_size; /* total NIC memory size */
+ caddr_t mem_ring; /* start of RX ring-buffer (in NIC mem) */
+
+ u_char mem_shared; /* NIC memory is shared with host */
+ u_char xmit_busy; /* transmitter is busy */
+ u_char txb_cnt; /* number of transmit buffers */
+ u_char txb_inuse; /* number of TX buffers currently in-use*/
+
+ u_char txb_new; /* pointer to where new buffer will be added */
+ u_char txb_next_tx; /* pointer to next buffer ready to xmit */
+ u_short txb_len[8]; /* buffered xmit buffer lengths */
+ u_char tx_page_start; /* first page of TX buffer area */
+ u_char rec_page_start; /* first page of RX ring-buffer */
+ u_char rec_page_stop; /* last page of RX ring-buffer */
+ u_char next_packet; /* pointer to next unread RX packet */
+} ed_softc[NED];
+
+int ed_attach(struct isa_device *);
+void ed_init(int);
+void edintr(int);
+int ed_ioctl(struct ifnet *, int, caddr_t);
+int ed_probe(struct isa_device *);
+void ed_start(struct ifnet *);
+void ed_reset(int);
+void ed_watchdog(int);
+
+static void ed_get_packet(struct ed_softc *, char *, int /*u_short*/);
+static void ed_stop(int);
+
+static inline void ed_rint();
+static inline void ed_xmit();
+static inline char *ed_ring_copy();
+
+void ed_pio_readmem(), ed_pio_writemem();
+u_short ed_pio_write_mbufs();
+
+extern int ether_output();
+
+struct trailer_header {
+ u_short ether_type;
+ u_short ether_residual;
+};
+
+struct isa_driver eddriver = {
+ ed_probe,
+ ed_attach,
+ "ed"
+};
+/*
+ * Interrupt conversion table for WD/SMC ASIC
+ * (IRQ* are defined in icu.h)
+ */
+static unsigned short ed_intr_mask[] = {
+ IRQ9,
+ IRQ3,
+ IRQ5,
+ IRQ7,
+ IRQ10,
+ IRQ11,
+ IRQ15,
+ IRQ4
+};
+
+/*
+ * Interrupt conversion table for 585/790 Combo
+ */
+static unsigned short ed_790_intr_mask[] = {
+ 0,
+ IRQ9,
+ IRQ3,
+ IRQ5,
+ IRQ7,
+ IRQ10,
+ IRQ11,
+ IRQ15
+};
+#define ETHER_MIN_LEN 64
+#define ETHER_MAX_LEN 1518
+#define ETHER_ADDR_LEN 6
+#define ETHER_HDR_SIZE 14
+
+/*
+ * Determine if the device is present
+ *
+ * on entry:
+ * a pointer to an isa_device struct
+ * on exit:
+ * NULL if device not found
+ * or # of i/o addresses used (if found)
+ */
+int
+ed_probe(isa_dev)
+ struct isa_device *isa_dev;
+{
+ struct ed_softc *sc = &ed_softc[isa_dev->id_unit];
+ int nports;
+
+ if (nports = ed_probe_WD80x3(isa_dev))
+ return (nports);
+
+ if (nports = ed_probe_3Com(isa_dev))
+ return (nports);
+
+ if (nports = ed_probe_Novell(isa_dev))
+ return (nports);
+
+ return(0);
+}
+
+/*
+ * Generic probe routine for testing for the existance of a DS8390.
+ * Must be called after the NIC has just been reset. This routine
+ * works by looking at certain register values that are gauranteed
+ * to be initialized a certain way after power-up or reset. Seems
+ * not to currently work on the 83C690.
+ *
+ * Specifically:
+ *
+ * Register reset bits set bits
+ * Command Register (CR) TXP, STA RD2, STP
+ * Interrupt Status (ISR) RST
+ * Interrupt Mask (IMR) All bits
+ * Data Control (DCR) LAS
+ * Transmit Config. (TCR) LB1, LB0
+ *
+ * We only look at the CR and ISR registers, however, because looking at
+ * the others would require changing register pages (which would be
+ * intrusive if this isn't an 8390).
+ *
+ * Return 1 if 8390 was found, 0 if not.
+ */
+
+int
+ed_probe_generic8390(sc)
+ struct ed_softc *sc;
+{
+ if ((inb(sc->nic_addr + ED_P0_CR) &
+ (ED_CR_RD2|ED_CR_TXP|ED_CR_STA|ED_CR_STP)) !=
+ (ED_CR_RD2|ED_CR_STP))
+ return (0);
+ if ((inb(sc->nic_addr + ED_P0_ISR) & ED_ISR_RST) != ED_ISR_RST)
+ return (0);
+
+ return(1);
+}
+
+/*
+ * Probe and vendor-specific initialization routine for SMC/WD80x3 boards
+ */
+int
+ed_probe_WD80x3(isa_dev)
+ struct isa_device *isa_dev;
+{
+ struct ed_softc *sc = &ed_softc[isa_dev->id_unit];
+ int i;
+ u_int memsize;
+ u_char iptr, isa16bit, sum;
+
+ sc->asic_addr = isa_dev->id_iobase;
+ sc->nic_addr = sc->asic_addr + ED_WD_NIC_OFFSET;
+ sc->is790 = 0;
+
+#ifdef TOSH_ETHER
+ outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_POW);
+ DELAY(10000);
+#endif
+ /*
+ * Attempt to do a checksum over the station address PROM.
+ * If it fails, it's probably not a SMC/WD board. There
+ * is a problem with this, though: some clone WD boards
+ * don't pass the checksum test. Danpex boards for one.
+ */
+ for (sum = 0, i = 0; i < 8; ++i)
+ sum += inb(sc->asic_addr + ED_WD_PROM + i);
+
+ if (sum != ED_WD_ROM_CHECKSUM_TOTAL) {
+ /*
+ * Checksum is invalid. This often happens with cheap
+ * WD8003E clones. In this case, the checksum byte
+ * (the eighth byte) seems to always be zero.
+ */
+ if (inb(sc->asic_addr + ED_WD_CARD_ID) != ED_TYPE_WD8003E ||
+ inb(sc->asic_addr + ED_WD_PROM + 7) != 0)
+ return(0);
+ }
+
+ /* reset card to force it into a known state. */
+#ifdef TOSH_ETHER
+ outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_RST | ED_WD_MSR_POW);
+#else
+ outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_RST);
+#endif
+ DELAY(100);
+ outb(sc->asic_addr + ED_WD_MSR, inb(sc->asic_addr + ED_WD_MSR) & ~ED_WD_MSR_RST);
+ /* wait in the case this card is reading it's EEROM */
+ DELAY(5000);
+
+ sc->vendor = ED_VENDOR_WD_SMC;
+ sc->type = inb(sc->asic_addr + ED_WD_CARD_ID);
+
+ /*
+ * Set initial values for width/size.
+ */
+ memsize = 8192;
+ isa16bit = 0;
+ switch (sc->type) {
+ case ED_TYPE_WD8003S:
+ sc->type_str = "WD8003S";
+ break;
+ case ED_TYPE_WD8003E:
+ sc->type_str = "WD8003E";
+ break;
+ case ED_TYPE_WD8003EB:
+ sc->type_str = "WD8003EB";
+ break;
+ case ED_TYPE_WD8003W:
+ sc->type_str = "WD8003W";
+ break;
+ case ED_TYPE_WD8013EBT:
+ sc->type_str = "WD8013EBT";
+ memsize = 16384;
+ isa16bit = 1;
+ break;
+ case ED_TYPE_WD8013W:
+ sc->type_str = "WD8013W";
+ memsize = 16384;
+ isa16bit = 1;
+ break;
+ case ED_TYPE_WD8013EP: /* also WD8003EP */
+ if (inb(sc->asic_addr + ED_WD_ICR)
+ & ED_WD_ICR_16BIT) {
+ isa16bit = 1;
+ memsize = 16384;
+ sc->type_str = "WD8013EP";
+ } else {
+ sc->type_str = "WD8003EP";
+ }
+ break;
+ case ED_TYPE_WD8013WC:
+ sc->type_str = "WD8013WC";
+ memsize = 16384;
+ isa16bit = 1;
+ break;
+ case ED_TYPE_WD8013EBP:
+ sc->type_str = "WD8013EBP";
+ memsize = 16384;
+ isa16bit = 1;
+ break;
+ case ED_TYPE_WD8013EPC:
+ sc->type_str = "WD8013EPC";
+ memsize = 16384;
+ isa16bit = 1;
+ break;
+ case ED_TYPE_SMC8216C:
+ sc->type_str = "SMC8216/SMC8216C";
+ memsize = 16384;
+ isa16bit = 1;
+ sc->is790 = 1;
+ break;
+ case ED_TYPE_SMC8216T:
+ sc->type_str = "SMC8216T";
+ memsize = 16384;
+ isa16bit = 1;
+ sc->is790 = 1;
+ break;
+#ifdef TOSH_ETHER
+ case ED_TYPE_TOSHIBA1:
+ sc->type_str = "Toshiba1";
+ memsize = 32768;
+ isa16bit = 1;
+ break;
+ case ED_TYPE_TOSHIBA4:
+ sc->type_str = "Toshiba4";
+ memsize = 32768;
+ isa16bit = 1;
+ break;
+#endif
+ default:
+ sc->type_str = "";
+ break;
+ }
+ /*
+ * Make some adjustments to initial values depending on what is
+ * found in the ICR.
+ */
+ if (isa16bit && (sc->type != ED_TYPE_WD8013EBT)
+#ifdef TOSH_ETHER
+ && (sc->type != ED_TYPE_TOSHIBA1) && (sc->type != ED_TYPE_TOSHIBA4)
+#endif
+ && ((inb(sc->asic_addr + ED_WD_ICR) & ED_WD_ICR_16BIT) == 0)) {
+ isa16bit = 0;
+ memsize = 8192;
+ }
+
+#if ED_DEBUG
+ printf("type = %x type_str=%s isa16bit=%d memsize=%d id_msize=%d\n",
+ sc->type,sc->type_str,isa16bit,memsize,isa_dev->id_msize);
+ for (i=0; i<8; i++)
+ printf("%x -> %x\n", i, inb(sc->asic_addr + i));
+#endif
+ /*
+ * Allow the user to override the autoconfiguration
+ */
+ if (isa_dev->id_msize)
+ memsize = isa_dev->id_msize;
+ /*
+ * (note that if the user specifies both of the following flags
+ * that '8bit' mode intentionally has precedence)
+ */
+ if (isa_dev->id_flags & ED_FLAGS_FORCE_16BIT_MODE)
+ isa16bit = 1;
+ if (isa_dev->id_flags & ED_FLAGS_FORCE_8BIT_MODE)
+ isa16bit = 0;
+
+ /*
+ * Check 83C584 interrupt configuration register if this board has one
+ * XXX - we could also check the IO address register. But why
+ * bother...if we get past this, it *has* to be correct.
+ */
+ if ((sc->type & ED_WD_SOFTCONFIG) && (!sc->is790)) {
+ /*
+ * Assemble together the encoded interrupt number.
+ */
+ iptr = (inb(isa_dev->id_iobase + ED_WD_ICR) & ED_WD_ICR_IR2) |
+ ((inb(isa_dev->id_iobase + ED_WD_IRR) &
+ (ED_WD_IRR_IR0 | ED_WD_IRR_IR1)) >> 5);
+ /*
+ * Translate it using translation table, and check for correctness.
+ */
+ if (ed_intr_mask[iptr] != isa_dev->id_irq) {
+ printf("ed%d: kernel configured irq %d doesn't match board configured irq %d\n",
+ isa_dev->id_unit, ffs(isa_dev->id_irq) - 1,
+ ffs(ed_intr_mask[iptr]) - 1);
+ return(0);
+ }
+ /*
+ * Enable the interrupt.
+ */
+ outb(isa_dev->id_iobase + ED_WD_IRR,
+ inb(isa_dev->id_iobase + ED_WD_IRR) | ED_WD_IRR_IEN);
+ }
+ if (sc->is790) {
+ outb(isa_dev->id_iobase + ED_WD790_HWR,
+ inb(isa_dev->id_iobase + ED_WD790_HWR) | ED_WD790_HWR_SWH);
+ iptr = (((inb(isa_dev->id_iobase + ED_WD790_GCR) & ED_WD790_GCR_IR2) >> 4) |
+ (inb(isa_dev->id_iobase + ED_WD790_GCR) &
+ (ED_WD790_GCR_IR1|ED_WD790_GCR_IR0)) >> 2);
+ outb(isa_dev->id_iobase + ED_WD790_HWR,
+ inb(isa_dev->id_iobase + ED_WD790_HWR) & ~ED_WD790_HWR_SWH);
+
+ if (ed_790_intr_mask[iptr] != isa_dev->id_irq) {
+ printf("ed%d: kernel configured irq %d doesn't match board configured irq %d %d\n",
+ isa_dev->id_unit, ffs(isa_dev->id_irq) - 1,
+ ffs(ed_790_intr_mask[iptr]) - 1, iptr);
+ return 0;
+ }
+ /*
+ * Enable interrupts.
+ */
+ outb(isa_dev->id_iobase + ED_WD790_ICR,
+ inb(isa_dev->id_iobase + ED_WD790_ICR) | ED_WD790_ICR_EIL);
+ }
+
+ sc->isa16bit = isa16bit;
+
+#ifdef notyet /* XXX - I'm not sure if PIO mode is even possible on WD/SMC boards */
+ /*
+ * The following allows the WD/SMC boards to be used in Programmed I/O
+ * mode - without mapping the NIC memory shared. ...Not the prefered
+ * way, but it might be the only way.
+ */
+ if (isa_dev->id_flags & ED_FLAGS_FORCE_PIO) {
+ sc->mem_shared = 0;
+ isa_dev->id_maddr = 0;
+ } else {
+ sc->mem_shared = 1;
+ }
+#else
+ sc->mem_shared = 1;
+#endif
+ isa_dev->id_msize = memsize;
+
+ sc->mem_start = (caddr_t)isa_dev->id_maddr;
+
+ /*
+ * allocate one xmit buffer if < 16k, two buffers otherwise
+ */
+ if ((memsize < 16384) || (isa_dev->id_flags & ED_FLAGS_NO_MULTI_BUFFERING)) {
+ sc->mem_ring = sc->mem_start + (ED_PAGE_SIZE * ED_TXBUF_SIZE);
+ sc->txb_cnt = 1;
+ sc->rec_page_start = ED_TXBUF_SIZE;
+ } else {
+ sc->mem_ring = sc->mem_start + (ED_PAGE_SIZE * ED_TXBUF_SIZE * 2);
+ sc->txb_cnt = 2;
+ sc->rec_page_start = ED_TXBUF_SIZE * 2;
+ }
+ sc->mem_size = memsize;
+ sc->mem_end = sc->mem_start + memsize;
+ sc->rec_page_stop = memsize / ED_PAGE_SIZE;
+ sc->tx_page_start = ED_WD_PAGE_OFFSET;
+
+ /*
+ * Get station address from on-board ROM
+ */
+ for (i = 0; i < ETHER_ADDR_LEN; ++i)
+ sc->arpcom.ac_enaddr[i] = inb(sc->asic_addr + ED_WD_PROM + i);
+
+ if (sc->mem_shared) {
+ /*
+ * Set address and enable interface shared memory.
+ */
+ if(!sc->is790) {
+#ifdef TOSH_ETHER
+ outb(sc->asic_addr + ED_WD_MSR + 1, ((kvtop(sc->mem_start) >> 8) & 0xe0) | 4);
+ outb(sc->asic_addr + ED_WD_MSR + 2, ((kvtop(sc->mem_start) >> 16) & 0x0f));
+ outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_MENB | ED_WD_MSR_POW);
+
+#else
+ outb(sc->asic_addr + ED_WD_MSR, ((kvtop(sc->mem_start) >> 13) &
+ ED_WD_MSR_ADDR) | ED_WD_MSR_MENB);
+#endif
+ } else {
+ outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_MENB);
+ outb(sc->asic_addr + 0x04, (inb(sc->asic_addr + 0x04) | 0x80));
+ outb(sc->asic_addr + 0x0b, ((kvtop(sc->mem_start) >> 13) & 0x0f) |
+ ((kvtop(sc->mem_start) >> 11) & 0x40) |
+ (inb(sc->asic_addr + 0x0b) & 0xb0));
+ outb(sc->asic_addr + 0x04, (inb(sc->asic_addr + 0x04) & ~0x80));
+ }
+
+ /*
+ * Set upper address bits and 8/16 bit access to shared memory
+ */
+ if (isa16bit) {
+ if (sc->is790) {
+ sc->wd_laar_proto = inb(sc->asic_addr + ED_WD_LAAR);
+ outb(sc->asic_addr + ED_WD_LAAR, ED_WD_LAAR_M16EN);
+ (void) inb(0x84);
+ } else {
+ outb(sc->asic_addr + ED_WD_LAAR, (sc->wd_laar_proto =
+ ED_WD_LAAR_L16EN | ED_WD_LAAR_M16EN |
+ ((kvtop(sc->mem_start) >> 19) & ED_WD_LAAR_ADDRHI)));
+ }
+ } else {
+ if ((sc->type & ED_WD_SOFTCONFIG) ||
+#ifdef TOSH_ETHER
+ (sc->type == ED_TYPE_TOSHIBA1) || (sc->type == ED_TYPE_TOSHIBA4) ||
+#endif
+ (sc->type == ED_TYPE_WD8013EBT) && (!sc->is790)) {
+ outb(sc->asic_addr + ED_WD_LAAR, (sc->wd_laar_proto =
+ ((kvtop(sc->mem_start) >> 19) & ED_WD_LAAR_ADDRHI)));
+ }
+ }
+
+ /*
+ * Now zero memory and verify that it is clear
+ */
+ bzero(sc->mem_start, memsize);
+
+ for (i = 0; i < memsize; ++i)
+ if (sc->mem_start[i]) {
+ printf("ed%d: failed to clear shared memory at %x - check configuration\n",
+ isa_dev->id_unit, kvtop(sc->mem_start + i));
+
+ /*
+ * Disable 16 bit access to shared memory
+ */
+ if (isa16bit) {
+ outb(sc->asic_addr + ED_WD_LAAR, (sc->wd_laar_proto &=
+ ~ED_WD_LAAR_M16EN));
+ (void) inb(0x84);
+ }
+
+ return(0);
+ }
+
+ /*
+ * Disable 16bit access to shared memory - we leave it disabled so
+ * that 1) machines reboot properly when the board is set
+ * 16 bit mode and there are conflicting 8bit devices/ROMS
+ * in the same 128k address space as this boards shared
+ * memory. and 2) so that other 8 bit devices with shared
+ * memory can be used in this 128k region, too.
+ */
+ if (isa16bit) {
+ outb(sc->asic_addr + ED_WD_LAAR, (sc->wd_laar_proto &=
+ ~ED_WD_LAAR_M16EN));
+ (void) inb(0x84);
+ }
+ }
+
+ return (ED_WD_IO_PORTS);
+}
+
+/*
+ * Probe and vendor-specific initialization routine for 3Com 3c503 boards
+ */
+int
+ed_probe_3Com(isa_dev)
+ struct isa_device *isa_dev;
+{
+ struct ed_softc *sc = &ed_softc[isa_dev->id_unit];
+ int i;
+ u_int memsize;
+ u_char isa16bit, sum;
+
+ sc->asic_addr = isa_dev->id_iobase + ED_3COM_ASIC_OFFSET;
+ sc->nic_addr = isa_dev->id_iobase + ED_3COM_NIC_OFFSET;
+
+ /*
+ * Verify that the kernel configured I/O address matches the board
+ * configured address
+ */
+ switch (inb(sc->asic_addr + ED_3COM_BCFR)) {
+ case ED_3COM_BCFR_300:
+ if (isa_dev->id_iobase != 0x300)
+ return(0);
+ break;
+ case ED_3COM_BCFR_310:
+ if (isa_dev->id_iobase != 0x310)
+ return(0);
+ break;
+ case ED_3COM_BCFR_330:
+ if (isa_dev->id_iobase != 0x330)
+ return(0);
+ break;
+ case ED_3COM_BCFR_350:
+ if (isa_dev->id_iobase != 0x350)
+ return(0);
+ break;
+ case ED_3COM_BCFR_250:
+ if (isa_dev->id_iobase != 0x250)
+ return(0);
+ break;
+ case ED_3COM_BCFR_280:
+ if (isa_dev->id_iobase != 0x280)
+ return(0);
+ break;
+ case ED_3COM_BCFR_2A0:
+ if (isa_dev->id_iobase != 0x2a0)
+ return(0);
+ break;
+ case ED_3COM_BCFR_2E0:
+ if (isa_dev->id_iobase != 0x2e0)
+ return(0);
+ break;
+ default:
+ return(0);
+ }
+
+ /*
+ * Verify that the kernel shared memory address matches the
+ * board configured address.
+ */
+ switch (inb(sc->asic_addr + ED_3COM_PCFR)) {
+ case ED_3COM_PCFR_DC000:
+ if (kvtop(isa_dev->id_maddr) != 0xdc000)
+ return(0);
+ break;
+ case ED_3COM_PCFR_D8000:
+ if (kvtop(isa_dev->id_maddr) != 0xd8000)
+ return(0);
+ break;
+ case ED_3COM_PCFR_CC000:
+ if (kvtop(isa_dev->id_maddr) != 0xcc000)
+ return(0);
+ break;
+ case ED_3COM_PCFR_C8000:
+ if (kvtop(isa_dev->id_maddr) != 0xc8000)
+ return(0);
+ break;
+ default:
+ return(0);
+ }
+
+
+ /*
+ * Reset NIC and ASIC. Enable on-board transceiver throughout reset
+ * sequence because it'll lock up if the cable isn't connected
+ * if we don't.
+ */
+ outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_RST | ED_3COM_CR_XSEL);
+
+ /*
+ * Wait for a while, then un-reset it
+ */
+ DELAY(50);
+ /*
+ * The 3Com ASIC defaults to rather strange settings for the CR after
+ * a reset - it's important to set it again after the following
+ * outb (this is done when we map the PROM below).
+ */
+ outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_XSEL);
+
+ /*
+ * Wait a bit for the NIC to recover from the reset
+ */
+ DELAY(5000);
+
+ sc->vendor = ED_VENDOR_3COM;
+ sc->type_str = "3c503";
+
+ sc->mem_shared = 1;
+
+ /*
+ * Hmmm...a 16bit 3Com board has 16k of memory, but only an 8k
+ * window to it.
+ */
+ memsize = 8192;
+
+ /*
+ * Get station address from on-board ROM
+ */
+ /*
+ * First, map ethernet address PROM over the top of where the NIC
+ * registers normally appear.
+ */
+ outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_EALO | ED_3COM_CR_XSEL);
+
+ for (i = 0; i < ETHER_ADDR_LEN; ++i)
+ sc->arpcom.ac_enaddr[i] = inb(sc->nic_addr + i);
+
+ /*
+ * Unmap PROM - select NIC registers. The proper setting of the
+ * tranceiver is set in ed_init so that the attach code
+ * is given a chance to set the default based on a compile-time
+ * config option
+ */
+ outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_XSEL);
+
+ /*
+ * Determine if this is an 8bit or 16bit board
+ */
+
+ /*
+ * select page 0 registers
+ */
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STP);
+
+ /*
+ * Attempt to clear WTS bit. If it doesn't clear, then this is a
+ * 16bit board.
+ */
+ outb(sc->nic_addr + ED_P0_DCR, 0);
+
+ /*
+ * select page 2 registers
+ */
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_2|ED_CR_RD2|ED_CR_STP);
+
+ /*
+ * The 3c503 forces the WTS bit to a one if this is a 16bit board
+ */
+ if (inb(sc->nic_addr + ED_P2_DCR) & ED_DCR_WTS)
+ isa16bit = 1;
+ else
+ isa16bit = 0;
+
+ /*
+ * select page 0 registers
+ */
+ outb(sc->nic_addr + ED_P2_CR, ED_CR_RD2|ED_CR_STP);
+
+ sc->mem_start = (caddr_t)isa_dev->id_maddr;
+ sc->mem_size = memsize;
+ sc->mem_end = sc->mem_start + memsize;
+
+ /*
+ * We have an entire 8k window to put the transmit buffers on the
+ * 16bit boards. But since the 16bit 3c503's shared memory
+ * is only fast enough to overlap the loading of one full-size
+ * packet, trying to load more than 2 buffers can actually
+ * leave the transmitter idle during the load. So 2 seems
+ * the best value. (Although a mix of variable-sized packets
+ * might change this assumption. Nonetheless, we optimize for
+ * linear transfers of same-size packets.)
+ */
+ if (isa16bit) {
+ if (isa_dev->id_flags & ED_FLAGS_NO_MULTI_BUFFERING)
+ sc->txb_cnt = 1;
+ else
+ sc->txb_cnt = 2;
+
+ sc->tx_page_start = ED_3COM_TX_PAGE_OFFSET_16BIT;
+ sc->rec_page_start = ED_3COM_RX_PAGE_OFFSET_16BIT;
+ sc->rec_page_stop = memsize / ED_PAGE_SIZE +
+ ED_3COM_RX_PAGE_OFFSET_16BIT;
+ sc->mem_ring = sc->mem_start;
+ } else {
+ sc->txb_cnt = 1;
+ sc->tx_page_start = ED_3COM_TX_PAGE_OFFSET_8BIT;
+ sc->rec_page_start = ED_TXBUF_SIZE + ED_3COM_TX_PAGE_OFFSET_8BIT;
+ sc->rec_page_stop = memsize / ED_PAGE_SIZE +
+ ED_3COM_TX_PAGE_OFFSET_8BIT;
+ sc->mem_ring = sc->mem_start + (ED_PAGE_SIZE * ED_TXBUF_SIZE);
+ }
+
+ sc->isa16bit = isa16bit;
+
+ /*
+ * Initialize GA page start/stop registers. Probably only needed
+ * if doing DMA, but what the hell.
+ */
+ outb(sc->asic_addr + ED_3COM_PSTR, sc->rec_page_start);
+ outb(sc->asic_addr + ED_3COM_PSPR, sc->rec_page_stop);
+
+ /*
+ * Set IRQ. 3c503 only allows a choice of irq 2-5.
+ */
+ switch (isa_dev->id_irq) {
+ case IRQ2:
+ outb(sc->asic_addr + ED_3COM_IDCFR, ED_3COM_IDCFR_IRQ2);
+ break;
+ case IRQ3:
+ outb(sc->asic_addr + ED_3COM_IDCFR, ED_3COM_IDCFR_IRQ3);
+ break;
+ case IRQ4:
+ outb(sc->asic_addr + ED_3COM_IDCFR, ED_3COM_IDCFR_IRQ4);
+ break;
+ case IRQ5:
+ outb(sc->asic_addr + ED_3COM_IDCFR, ED_3COM_IDCFR_IRQ5);
+ break;
+ default:
+ printf("ed%d: Invalid irq configuration (%d) must be 2-5 for 3c503\n",
+ isa_dev->id_unit, ffs(isa_dev->id_irq) - 1);
+ return(0);
+ }
+
+ /*
+ * Initialize GA configuration register. Set bank and enable shared mem.
+ */
+ outb(sc->asic_addr + ED_3COM_GACFR, ED_3COM_GACFR_RSEL |
+ ED_3COM_GACFR_MBS0);
+
+ /*
+ * Initialize "Vector Pointer" registers. These gawd-awful things
+ * are compared to 20 bits of the address on ISA, and if they
+ * match, the shared memory is disabled. We set them to
+ * 0xffff0...allegedly the reset vector.
+ */
+ outb(sc->asic_addr + ED_3COM_VPTR2, 0xff);
+ outb(sc->asic_addr + ED_3COM_VPTR1, 0xff);
+ outb(sc->asic_addr + ED_3COM_VPTR0, 0x00);
+
+ /*
+ * Zero memory and verify that it is clear
+ */
+ bzero(sc->mem_start, memsize);
+
+ for (i = 0; i < memsize; ++i)
+ if (sc->mem_start[i]) {
+ printf("ed%d: failed to clear shared memory at %x - check configuration\n",
+ isa_dev->id_unit, kvtop(sc->mem_start + i));
+ return(0);
+ }
+
+ isa_dev->id_msize = memsize;
+ return(ED_3COM_IO_PORTS);
+}
+
+/*
+ * Probe and vendor-specific initialization routine for NE1000/2000 boards
+ */
+int
+ed_probe_Novell(isa_dev)
+ struct isa_device *isa_dev;
+{
+ struct ed_softc *sc = &ed_softc[isa_dev->id_unit];
+ u_int memsize, n;
+ u_char romdata[16], isa16bit = 0, tmp;
+ static char test_pattern[32] = "THIS is A memory TEST pattern";
+ char test_buffer[32];
+
+ sc->asic_addr = isa_dev->id_iobase + ED_NOVELL_ASIC_OFFSET;
+ sc->nic_addr = isa_dev->id_iobase + ED_NOVELL_NIC_OFFSET;
+
+ /* XXX - do Novell-specific probe here */
+
+ /* Reset the board */
+ tmp = inb(sc->asic_addr + ED_NOVELL_RESET);
+
+ /*
+ * I don't know if this is necessary; probably cruft leftover from
+ * Clarkson packet driver code. Doesn't do a thing on the boards
+ * I've tested. -DG [note that a outb(0x84, 0) seems to work
+ * here, and is non-invasive...but some boards don't seem to reset
+ * and I don't have complete documentation on what the 'right'
+ * thing to do is...so we do the invasive thing for now. Yuck.]
+ */
+ outb(sc->asic_addr + ED_NOVELL_RESET, tmp);
+ DELAY(5000);
+
+ /*
+ * This is needed because some NE clones apparently don't reset the
+ * NIC properly (or the NIC chip doesn't reset fully on power-up)
+ * XXX - this makes the probe invasive! ...Done against my better
+ * judgement. -DLG
+ */
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STP);
+
+ DELAY(5000);
+
+ /* Make sure that we really have an 8390 based board */
+ if (!ed_probe_generic8390(sc))
+ return(0);
+
+ sc->vendor = ED_VENDOR_NOVELL;
+ sc->mem_shared = 0;
+ isa_dev->id_maddr = 0;
+
+ /*
+ * Test the ability to read and write to the NIC memory. This has
+ * the side affect of determining if this is an NE1000 or an NE2000.
+ */
+
+ /*
+ * This prevents packets from being stored in the NIC memory when
+ * the readmem routine turns on the start bit in the CR.
+ */
+ outb(sc->nic_addr + ED_P0_RCR, ED_RCR_MON);
+
+ /* Temporarily initialize DCR for byte operations */
+ outb(sc->nic_addr + ED_P0_DCR, ED_DCR_FT1|ED_DCR_LS);
+
+ outb(sc->nic_addr + ED_P0_PSTART, 8192 / ED_PAGE_SIZE);
+ outb(sc->nic_addr + ED_P0_PSTOP, 16384 / ED_PAGE_SIZE);
+
+ sc->isa16bit = 0;
+
+ /*
+ * Write a test pattern in byte mode. If this fails, then there
+ * probably isn't any memory at 8k - which likely means
+ * that the board is an NE2000.
+ */
+ ed_pio_writemem(sc, test_pattern, 8192, sizeof(test_pattern));
+ ed_pio_readmem(sc, 8192, test_buffer, sizeof(test_pattern));
+
+ if (bcmp(test_pattern, test_buffer, sizeof(test_pattern))) {
+ /* not an NE1000 - try NE2000 */
+
+ outb(sc->nic_addr + ED_P0_DCR, ED_DCR_WTS|ED_DCR_FT1|ED_DCR_LS);
+ outb(sc->nic_addr + ED_P0_PSTART, 16384 / ED_PAGE_SIZE);
+ outb(sc->nic_addr + ED_P0_PSTOP, 32768 / ED_PAGE_SIZE);
+
+ sc->isa16bit = 1;
+ /*
+ * Write a test pattern in word mode. If this also fails, then
+ * we don't know what this board is.
+ */
+ ed_pio_writemem(sc, test_pattern, 16384, sizeof(test_pattern));
+ ed_pio_readmem(sc, 16384, test_buffer, sizeof(test_pattern));
+
+ if (bcmp(test_pattern, test_buffer, sizeof(test_pattern)))
+ return(0); /* not an NE2000 either */
+
+ sc->type = ED_TYPE_NE2000;
+ sc->type_str = "NE2000";
+ } else {
+ sc->type = ED_TYPE_NE1000;
+ sc->type_str = "NE1000";
+ }
+
+ /* 8k of memory plus an additional 8k if 16bit */
+ memsize = 8192 + sc->isa16bit * 8192;
+
+#if 0 /* probably not useful - NE boards only come two ways */
+ /* allow kernel config file overrides */
+ if (isa_dev->id_msize)
+ memsize = isa_dev->id_msize;
+#endif
+
+ sc->mem_size = memsize;
+
+ /* NIC memory doesn't start at zero on an NE board */
+ /* The start address is tied to the bus width */
+ sc->mem_start = (char *) 8192 + sc->isa16bit * 8192;
+ sc->mem_end = sc->mem_start + memsize;
+ sc->tx_page_start = memsize / ED_PAGE_SIZE;
+
+ /*
+ * Use one xmit buffer if < 16k, two buffers otherwise (if not told
+ * otherwise).
+ */
+ if ((memsize < 16384) || (isa_dev->id_flags & ED_FLAGS_NO_MULTI_BUFFERING))
+ sc->txb_cnt = 1;
+ else
+ sc->txb_cnt = 2;
+
+ sc->rec_page_start = sc->tx_page_start + sc->txb_cnt * ED_TXBUF_SIZE;
+ sc->rec_page_stop = sc->tx_page_start + memsize / ED_PAGE_SIZE;
+
+ sc->mem_ring = sc->mem_start + sc->txb_cnt * ED_PAGE_SIZE * ED_TXBUF_SIZE;
+
+ ed_pio_readmem(sc, 0, romdata, 16);
+ for (n = 0; n < ETHER_ADDR_LEN; n++)
+ sc->arpcom.ac_enaddr[n] = romdata[n*(sc->isa16bit+1)];
+
+ /* clear any pending interrupts that might have occurred above */
+ outb(sc->nic_addr + ED_P0_ISR, 0xff);
+
+ return(ED_NOVELL_IO_PORTS);
+}
+
+/*
+ * Install interface into kernel networking data structures
+ */
+int
+ed_attach(isa_dev)
+ struct isa_device *isa_dev;
+{
+ struct ed_softc *sc = &ed_softc[isa_dev->id_unit];
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ struct ifaddr *ifa;
+ struct sockaddr_dl *sdl;
+
+ /*
+ * Set interface to stopped condition (reset)
+ */
+ ed_stop(isa_dev->id_unit);
+
+ /*
+ * Initialize ifnet structure
+ */
+ ifp->if_unit = isa_dev->id_unit;
+ ifp->if_name = "ed" ;
+ ifp->if_mtu = ETHERMTU;
+ ifp->if_init = ed_init;
+ ifp->if_output = ether_output;
+ ifp->if_start = ed_start;
+ ifp->if_ioctl = ed_ioctl;
+ ifp->if_reset = ed_reset;
+ ifp->if_watchdog = ed_watchdog;
+
+ /*
+ * Set default state for ALTPHYS flag (used to disable the tranceiver
+ * for AUI operation), based on compile-time config option.
+ */
+ if (isa_dev->id_flags & ED_FLAGS_DISABLE_TRANCEIVER)
+ ifp->if_flags =
+ (IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_ALTPHYS);
+ else
+ ifp->if_flags = (IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS);
+
+ /*
+ * Attach the interface
+ */
+ 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 fill in the hardware address.
+ * This is useful for netstat(1) to keep track of which interface
+ * is which.
+ */
+ 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(sc->arpcom.ac_enaddr, LLADDR(sdl), ETHER_ADDR_LEN);
+ }
+
+ /*
+ * Print additional info when attached
+ */
+ printf("ed%d: address %s, ", isa_dev->id_unit,
+ ether_sprintf(sc->arpcom.ac_enaddr));
+
+ if (sc->type_str && (*sc->type_str != 0))
+ printf("type %s ", sc->type_str);
+ else
+ printf("type unknown (0x%x) ", sc->type);
+
+ printf("%s ",sc->isa16bit ? "(16 bit)" : "(8 bit)");
+
+ printf("%s\n", ((sc->vendor == ED_VENDOR_3COM) &&
+ (ifp->if_flags & IFF_ALTPHYS)) ? " tranceiver disabled" : "");
+
+ /*
+ * If BPF is in the kernel, call the attach for it
+ */
+#if NBPFILTER > 0
+ bpfattach(&sc->bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
+#endif
+ return 1;
+}
+
+/*
+ * Reset interface.
+ */
+void
+ed_reset(unit)
+ int unit;
+{
+ int s;
+
+ s = splimp();
+
+ /*
+ * Stop interface and re-initialize.
+ */
+ ed_stop(unit);
+ ed_init(unit);
+
+ (void) splx(s);
+}
+
+/*
+ * Take interface offline.
+ */
+void
+ed_stop(unit)
+ int unit;
+{
+ struct ed_softc *sc = &ed_softc[unit];
+ int n = 5000;
+
+ /*
+ * Stop everything on the interface, and select page 0 registers.
+ */
+ if (sc->is790) {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_STP);
+ } else {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STP);
+ }
+ /*
+ * Wait for interface to enter stopped state, but limit # of checks
+ * to 'n' (about 5ms). It shouldn't even take 5us on modern
+ * DS8390's, but just in case it's an old one.
+ */
+ while (((inb(sc->nic_addr + ED_P0_ISR) & ED_ISR_RST) == 0) && --n);
+
+}
+
+/*
+ * Device timeout/watchdog routine. Entered if the device neglects to
+ * generate an interrupt after a transmit has been started on it.
+ */
+void
+ed_watchdog(unit)
+ int unit;
+{
+ struct ed_softc *sc = &ed_softc[unit];
+
+ log(LOG_ERR, "ed%d: device timeout\n", unit);
+ ++sc->arpcom.ac_if.if_oerrors;
+
+ ed_reset(unit);
+}
+
+/*
+ * Initialize device.
+ */
+void
+ed_init(unit)
+ int unit;
+{
+ struct ed_softc *sc = &ed_softc[unit];
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ int i, s;
+ u_char command;
+
+
+ /* address not known */
+ if (ifp->if_addrlist == (struct ifaddr *)0) return;
+
+ /*
+ * Initialize the NIC in the exact order outlined in the NS manual.
+ * This init procedure is "mandatory"...don't change what or when
+ * things happen.
+ */
+ s = splimp();
+
+ /* reset transmitter flags */
+ sc->xmit_busy = 0;
+ sc->arpcom.ac_if.if_timer = 0;
+
+ sc->txb_inuse = 0;
+ sc->txb_new = 0;
+ sc->txb_next_tx = 0;
+
+ /* This variable is used below - don't move this assignment */
+ sc->next_packet = sc->rec_page_start + 1;
+
+ /*
+ * Set interface for page 0, Remote DMA complete, Stopped
+ */
+ if (sc->is790) {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_STP);
+ } else {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STP);
+ }
+ if (sc->isa16bit) {
+ /*
+ * Set FIFO threshold to 8, No auto-init Remote DMA,
+ * byte order=80x86, word-wide DMA xfers,
+ */
+ outb(sc->nic_addr + ED_P0_DCR, ED_DCR_FT1|ED_DCR_WTS|ED_DCR_LS);
+ } else {
+ /*
+ * Same as above, but byte-wide DMA xfers
+ */
+ outb(sc->nic_addr + ED_P0_DCR, ED_DCR_FT1|ED_DCR_LS);
+ }
+
+ /*
+ * Clear Remote Byte Count Registers
+ */
+ outb(sc->nic_addr + ED_P0_RBCR0, 0);
+ outb(sc->nic_addr + ED_P0_RBCR1, 0);
+
+ /*
+ * Enable reception of broadcast packets
+ */
+ outb(sc->nic_addr + ED_P0_RCR, ED_RCR_AB);
+
+ /*
+ * Place NIC in internal loopback mode
+ */
+ outb(sc->nic_addr + ED_P0_TCR, ED_TCR_LB0);
+
+ /*
+ * Initialize transmit/receive (ring-buffer) Page Start
+ */
+ outb(sc->nic_addr + ED_P0_TPSR, sc->tx_page_start);
+ outb(sc->nic_addr + ED_P0_PSTART, sc->rec_page_start);
+ /* Set lower bits of byte addressable framing to 0 */
+ if (sc->is790)
+ outb(sc->nic_addr + 0x09, 0);
+
+ /*
+ * Initialize Receiver (ring-buffer) Page Stop and Boundry
+ */
+ outb(sc->nic_addr + ED_P0_PSTOP, sc->rec_page_stop);
+ outb(sc->nic_addr + ED_P0_BNRY, sc->rec_page_start);
+
+ /*
+ * Clear all interrupts. A '1' in each bit position clears the
+ * corresponding flag.
+ */
+ outb(sc->nic_addr + ED_P0_ISR, 0xff);
+
+ /*
+ * Enable the following interrupts: receive/transmit complete,
+ * receive/transmit error, and Receiver OverWrite.
+ *
+ * Counter overflow and Remote DMA complete are *not* enabled.
+ */
+ outb(sc->nic_addr + ED_P0_IMR,
+ ED_IMR_PRXE|ED_IMR_PTXE|ED_IMR_RXEE|ED_IMR_TXEE|ED_IMR_OVWE);
+
+ /*
+ * Program Command Register for page 1
+ */
+ if (sc->is790) {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1|ED_CR_STP);
+ } else {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1|ED_CR_RD2|ED_CR_STP);
+ }
+ /*
+ * Copy out our station address
+ */
+ for (i = 0; i < ETHER_ADDR_LEN; ++i)
+ outb(sc->nic_addr + ED_P1_PAR0 + i, sc->arpcom.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)
+ outb(sc->nic_addr + ED_P1_MAR0 + i, 0xff);
+#endif
+
+ /*
+ * Set Current Page pointer to next_packet (initialized above)
+ */
+ outb(sc->nic_addr + ED_P1_CURR, sc->next_packet);
+
+ /*
+ * Set Command Register for page 0, Remote DMA complete,
+ * and interface Start.
+ */
+ if (sc->is790) {
+ outb(sc->nic_addr + ED_P1_CR, ED_CR_STA);
+ } else {
+ outb(sc->nic_addr + ED_P1_CR, ED_CR_RD2|ED_CR_STA);
+ }
+ /*
+ * Take interface out of loopback
+ */
+ outb(sc->nic_addr + ED_P0_TCR, 0);
+
+ /*
+ * If this is a 3Com board, the tranceiver must be software enabled
+ * (there is no settable hardware default).
+ */
+ if (sc->vendor == ED_VENDOR_3COM) {
+ if (ifp->if_flags & IFF_ALTPHYS) {
+ outb(sc->asic_addr + ED_3COM_CR, 0);
+ } else {
+ outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_XSEL);
+ }
+ }
+
+ /*
+ * Set 'running' flag, and clear output active flag.
+ */
+ ifp->if_flags |= IFF_RUNNING;
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ /*
+ * ...and attempt to start output
+ */
+ ed_start(ifp);
+
+ (void) splx(s);
+}
+
+/*
+ * This routine actually starts the transmission on the interface
+ */
+static inline void ed_xmit(ifp)
+ struct ifnet *ifp;
+{
+ struct ed_softc *sc = &ed_softc[ifp->if_unit];
+ unsigned short len;
+
+ len = sc->txb_len[sc->txb_next_tx];
+
+ /*
+ * Set NIC for page 0 register access
+ */
+ if (sc->is790) {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_STA);
+ } else {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STA);
+ }
+ /*
+ * Set TX buffer start page
+ */
+ outb(sc->nic_addr + ED_P0_TPSR, sc->tx_page_start +
+ sc->txb_next_tx * ED_TXBUF_SIZE);
+
+ /*
+ * Set TX length
+ */
+ outb(sc->nic_addr + ED_P0_TBCR0, len);
+ outb(sc->nic_addr + ED_P0_TBCR1, len >> 8);
+
+ /*
+ * Set page 0, Remote DMA complete, Transmit Packet, and *Start*
+ */
+ if (sc->is790) {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_TXP | ED_CR_STA);
+ } else {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_TXP|ED_CR_STA);
+ }
+ sc->xmit_busy = 1;
+
+ /*
+ * Point to next transmit buffer slot and wrap if necessary.
+ */
+ sc->txb_next_tx++;
+ if (sc->txb_next_tx == sc->txb_cnt)
+ sc->txb_next_tx = 0;
+
+ /*
+ * Set a timer just in case we never hear from the board again
+ */
+ ifp->if_timer = 2;
+}
+
+/*
+ * Start output on interface.
+ * We make two assumptions here:
+ * 1) that the current priority is set to splimp _before_ this code
+ * is called *and* is returned to the appropriate priority after
+ * return
+ * 2) that the IFF_OACTIVE flag is checked before this code is called
+ * (i.e. that the output part of the interface is idle)
+ */
+void
+ed_start(ifp)
+ struct ifnet *ifp;
+{
+ struct ed_softc *sc = &ed_softc[ifp->if_unit];
+ struct mbuf *m0, *m;
+ caddr_t buffer;
+ int len;
+
+outloop:
+ /*
+ * First, see if there are buffered packets and an idle
+ * transmitter - should never happen at this point.
+ */
+ if (sc->txb_inuse && (sc->xmit_busy == 0)) {
+ printf("ed: packets buffers, but transmitter idle\n");
+ ed_xmit(ifp);
+ }
+
+ /*
+ * See if there is room to put another packet in the buffer.
+ */
+ if (sc->txb_inuse == sc->txb_cnt) {
+ /*
+ * No room. Indicate this to the outside world
+ * and exit.
+ */
+ ifp->if_flags |= IFF_OACTIVE;
+ return;
+ }
+
+ IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, m);
+ if (m == 0) {
+ /*
+ * We are using the !OACTIVE flag to indicate to the outside
+ * world that we can accept an additional packet rather than
+ * that the transmitter is _actually_ active. Indeed, the
+ * transmitter may be active, but if we haven't filled all
+ * the buffers with data then we still want to accept more.
+ */
+ ifp->if_flags &= ~IFF_OACTIVE;
+ return;
+ }
+
+ /*
+ * Copy the mbuf chain into the transmit buffer
+ */
+
+ m0 = m;
+
+ /* txb_new points to next open buffer slot */
+ buffer = sc->mem_start + (sc->txb_new * ED_TXBUF_SIZE * ED_PAGE_SIZE);
+
+ if (sc->mem_shared) {
+ /*
+ * Special case setup for 16 bit boards...
+ */
+ if (sc->isa16bit) {
+ switch (sc->vendor) {
+ /*
+ * For 16bit 3Com boards (which have 16k of memory),
+ * we have the xmit buffers in a different page
+ * of memory ('page 0') - so change pages.
+ */
+ case ED_VENDOR_3COM:
+ outb(sc->asic_addr + ED_3COM_GACFR,
+ ED_3COM_GACFR_RSEL);
+ break;
+ /*
+ * Enable 16bit access to shared memory on WD/SMC boards
+ * Don't update wd_laar_proto because we want to restore the
+ * previous state (because an arp reply in the input code
+ * may cause a call-back to ed_start)
+ * XXX - the call-back to 'start' is a bug, IMHO.
+ */
+ case ED_VENDOR_WD_SMC: {
+ outb(sc->asic_addr + ED_WD_LAAR,
+ (sc->wd_laar_proto | ED_WD_LAAR_M16EN));
+ (void) inb(0x84);
+ if (sc->is790) {
+ outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_MENB);
+ (void) inb(0x84);
+ }
+ (void) inb(0x84);
+ break;
+ }
+ }
+ }
+
+ for (len = 0; m != 0; m = m->m_next) {
+ bcopy(mtod(m, caddr_t), buffer, m->m_len);
+ buffer += m->m_len;
+ len += m->m_len;
+ }
+
+ /*
+ * Restore previous shared memory access
+ */
+ if (sc->isa16bit) {
+ switch (sc->vendor) {
+ case ED_VENDOR_3COM:
+ outb(sc->asic_addr + ED_3COM_GACFR,
+ ED_3COM_GACFR_RSEL | ED_3COM_GACFR_MBS0);
+ break;
+ case ED_VENDOR_WD_SMC: {
+ outb(sc->asic_addr + ED_WD_LAAR, sc->wd_laar_proto);
+ (void) inb(0x84);
+ if (sc->is790) {
+ outb(sc->asic_addr + ED_WD_MSR, 0x00);
+ (void) inb(0x84);
+ }
+ break;
+ }
+ }
+ }
+ } else {
+ len = ed_pio_write_mbufs(sc, m, buffer);
+ }
+
+ sc->txb_len[sc->txb_new] = max(len, ETHER_MIN_LEN);
+
+ sc->txb_inuse++;
+
+ /*
+ * Point to next buffer slot and wrap if necessary.
+ */
+ sc->txb_new++;
+ if (sc->txb_new == sc->txb_cnt)
+ sc->txb_new = 0;
+
+ if (sc->xmit_busy == 0)
+ ed_xmit(ifp);
+ /*
+ * If there is BPF support in the configuration, tap off here.
+ * The following has support for converting trailer packets
+ * back to normal.
+ * XXX - support for trailer packets in BPF should be moved into
+ * the bpf code proper to avoid code duplication in all of
+ * the drivers.
+ */
+#if NBPFILTER > 0
+ if (sc->bpf) {
+ u_short etype;
+ int off, datasize, resid;
+ struct ether_header *eh;
+ struct trailer_header 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),
+ (caddr_t)&trailer_header.ether_type);
+
+ /* copy residual data */
+ m_copydata(m0, off+sizeof(struct trailer_header),
+ resid = ntohs(trailer_header.ether_residual) -
+ sizeof(struct trailer_header), 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(sc->bpf, ether_packet, ep - ether_packet);
+ } else
+ bpf_mtap(sc->bpf, m0);
+ }
+#endif
+
+ m_freem(m0);
+
+ /*
+ * Loop back to the top to possibly buffer more packets
+ */
+ goto outloop;
+}
+
+/*
+ * Ethernet interface receiver interrupt.
+ */
+static inline void
+ed_rint(unit)
+ int unit;
+{
+ register struct ed_softc *sc = &ed_softc[unit];
+ u_char boundry, current;
+ u_short len;
+ struct ed_ring packet_hdr;
+ char *packet_ptr;
+
+ /*
+ * Set NIC to page 1 registers to get 'current' pointer
+ */
+ if (sc->is790) {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1|ED_CR_STA);
+ } else {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1|ED_CR_RD2|ED_CR_STA);
+ }
+ /*
+ * 'sc->next_packet' is the logical beginning of the ring-buffer - i.e.
+ * it points to where new data has been buffered. The 'CURR'
+ * (current) register points to the logical end of the ring-buffer
+ * - i.e. it points to where additional new data will be added.
+ * We loop here until the logical beginning equals the logical
+ * end (or in other words, until the ring-buffer is empty).
+ */
+ while (sc->next_packet != inb(sc->nic_addr + ED_P1_CURR)) {
+
+ /* get pointer to this buffer's header structure */
+ packet_ptr = sc->mem_ring +
+ (sc->next_packet - sc->rec_page_start) * ED_PAGE_SIZE;
+
+ /*
+ * The byte count includes the FCS - Frame Check Sequence (a
+ * 32 bit CRC).
+ */
+ if (sc->mem_shared)
+ packet_hdr = *(struct ed_ring *)packet_ptr;
+ else
+ ed_pio_readmem(sc, packet_ptr, (char *) &packet_hdr,
+ sizeof(packet_hdr));
+ len = packet_hdr.count;
+ if ((len >= ETHER_MIN_LEN) && (len <= ETHER_MAX_LEN)) {
+ /*
+ * Go get packet. len - 4 removes CRC from length.
+ */
+ ed_get_packet(sc, packet_ptr + 4, len - 4);
+ ++sc->arpcom.ac_if.if_ipackets;
+ } else {
+ /*
+ * Really BAD...probably indicates that the ring pointers
+ * are corrupted. Also seen on early rev chips under
+ * high load - the byte order of the length gets switched.
+ */
+ log(LOG_ERR,
+ "ed%d: NIC memory corrupt - invalid packet length %d\n",
+ unit, len);
+ ++sc->arpcom.ac_if.if_ierrors;
+ ed_reset(unit);
+ return;
+ }
+
+ /*
+ * Update next packet pointer
+ */
+ sc->next_packet = packet_hdr.next_packet;
+
+ /*
+ * Update NIC boundry pointer - being careful to keep it
+ * one buffer behind. (as recommended by NS databook)
+ */
+ boundry = sc->next_packet - 1;
+ if (boundry < sc->rec_page_start)
+ boundry = sc->rec_page_stop - 1;
+
+ /*
+ * Set NIC to page 0 registers to update boundry register
+ */
+ if (sc->is790) {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_STA);
+ } else {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STA);
+ }
+ outb(sc->nic_addr + ED_P0_BNRY, boundry);
+
+ /*
+ * Set NIC to page 1 registers before looping to top (prepare to
+ * get 'CURR' current pointer)
+ */
+ if (sc->is790) {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1|ED_CR_STA);
+ } else {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1|ED_CR_RD2|ED_CR_STA);
+ }
+ }
+}
+
+/*
+ * Ethernet interface interrupt processor
+ */
+void
+edintr(unit)
+ int unit;
+{
+ struct ed_softc *sc = &ed_softc[unit];
+ u_char isr;
+
+ /*
+ * Set NIC to page 0 registers
+ */
+ if (sc->is790) {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_STA);
+ } else {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STA);
+ }
+ /*
+ * loop until there are no more new interrupts
+ */
+ while (isr = inb(sc->nic_addr + ED_P0_ISR)) {
+
+ /*
+ * reset all the bits that we are 'acknowledging'
+ * by writing a '1' to each bit position that was set
+ * (writing a '1' *clears* the bit)
+ */
+ outb(sc->nic_addr + ED_P0_ISR, isr);
+
+ /*
+ * Handle transmitter interrupts. Handle these first
+ * because the receiver will reset the board under
+ * some conditions.
+ */
+ if (isr & (ED_ISR_PTX|ED_ISR_TXE)) {
+ u_char collisions = inb(sc->nic_addr + ED_P0_NCR) & 0x0f;
+
+ /*
+ * Check for transmit error. If a TX completed with an
+ * error, we end up throwing the packet away. Really
+ * the only error that is possible is excessive
+ * collisions, and in this case it is best to allow the
+ * automatic mechanisms of TCP to backoff the flow. Of
+ * course, with UDP we're screwed, but this is expected
+ * when a network is heavily loaded.
+ */
+ (void) inb(sc->nic_addr + ED_P0_TSR);
+ if (isr & ED_ISR_TXE) {
+
+ /*
+ * Excessive collisions (16)
+ */
+ if ((inb(sc->nic_addr + ED_P0_TSR) & ED_TSR_ABT)
+ && (collisions == 0)) {
+ /*
+ * When collisions total 16, the
+ * P0_NCR will indicate 0, and the
+ * TSR_ABT is set.
+ */
+ collisions = 16;
+ }
+
+ /*
+ * update output errors counter
+ */
+ ++sc->arpcom.ac_if.if_oerrors;
+ } else {
+ /*
+ * Update total number of successfully
+ * transmitted packets.
+ */
+ ++sc->arpcom.ac_if.if_opackets;
+ }
+
+ /*
+ * reset tx busy and output active flags
+ */
+ sc->xmit_busy = 0;
+ sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
+
+ /*
+ * clear watchdog timer
+ */
+ sc->arpcom.ac_if.if_timer = 0;
+
+ /*
+ * Add in total number of collisions on last
+ * transmission.
+ */
+ sc->arpcom.ac_if.if_collisions += collisions;
+
+ /*
+ * Decrement buffer in-use count if not zero (can only
+ * be zero if a transmitter interrupt occured while
+ * not actually transmitting).
+ * If data is ready to transmit, start it transmitting,
+ * otherwise defer until after handling receiver
+ */
+ if (sc->txb_inuse && --sc->txb_inuse)
+ ed_xmit(&sc->arpcom.ac_if);
+ }
+
+ /*
+ * Handle receiver interrupts
+ */
+ if (isr & (ED_ISR_PRX|ED_ISR_RXE|ED_ISR_OVW)) {
+ /*
+ * Overwrite warning. In order to make sure that a lockup
+ * of the local DMA hasn't occurred, we reset and
+ * re-init the NIC. The NSC manual suggests only a
+ * partial reset/re-init is necessary - but some
+ * chips seem to want more. The DMA lockup has been
+ * seen only with early rev chips - Methinks this
+ * bug was fixed in later revs. -DG
+ */
+ if (isr & ED_ISR_OVW) {
+ ++sc->arpcom.ac_if.if_ierrors;
+#ifdef DIAGNOSTIC
+ log(LOG_WARNING,
+ "ed%d: warning - receiver ring buffer overrun\n",
+ unit);
+#endif
+ /*
+ * Stop/reset/re-init NIC
+ */
+ ed_reset(unit);
+ } else {
+
+ /*
+ * Receiver Error. One or more of: CRC error, frame
+ * alignment error FIFO overrun, or missed packet.
+ */
+ if (isr & ED_ISR_RXE) {
+ ++sc->arpcom.ac_if.if_ierrors;
+#ifdef ED_DEBUG
+ printf("ed%d: receive error %x\n", unit,
+ inb(sc->nic_addr + ED_P0_RSR));
+#endif
+ }
+
+ /*
+ * Go get the packet(s)
+ * XXX - Doing this on an error is dubious
+ * because there shouldn't be any data to
+ * get (we've configured the interface to
+ * not accept packets with errors).
+ */
+
+ /*
+ * Enable 16bit access to shared memory first
+ * on WD/SMC boards.
+ */
+ if (sc->isa16bit &&
+ (sc->vendor == ED_VENDOR_WD_SMC)) {
+
+ outb(sc->asic_addr + ED_WD_LAAR,
+ (sc->wd_laar_proto |=
+ ED_WD_LAAR_M16EN));
+ (void) inb(0x84);
+ if (sc->is790) {
+ outb(sc->asic_addr + ED_WD_MSR,
+ ED_WD_MSR_MENB);
+ (void) inb(0x84);
+ }
+ }
+
+ ed_rint (unit);
+
+ /* disable 16bit access */
+ if (sc->isa16bit &&
+ (sc->vendor == ED_VENDOR_WD_SMC)) {
+
+ outb(sc->asic_addr + ED_WD_LAAR,
+ (sc->wd_laar_proto &=
+ ~ED_WD_LAAR_M16EN));
+ (void) inb(0x84);
+ if (sc->is790) {
+ outb(sc->asic_addr + ED_WD_MSR, 0x00);
+ (void) inb(0x84);
+ }
+ }
+ }
+ }
+
+ /*
+ * If it looks like the transmitter can take more data,
+ * attempt to start output on the interface.
+ * This is done after handling the receiver to
+ * give the receiver priority.
+ */
+ if ((sc->arpcom.ac_if.if_flags & IFF_OACTIVE) == 0)
+ ed_start(&sc->arpcom.ac_if);
+
+ /*
+ * return NIC CR to standard state: page 0, remote DMA complete,
+ * start (toggling the TXP bit off, even if was just set
+ * in the transmit routine, is *okay* - it is 'edge'
+ * triggered from low to high)
+ */
+ if (sc->is790) {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_STA);
+ } else {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STA);
+ }
+ /*
+ * If the Network Talley Counters overflow, read them to
+ * reset them. It appears that old 8390's won't
+ * clear the ISR flag otherwise - resulting in an
+ * infinite loop.
+ */
+ if (isr & ED_ISR_CNT) {
+ (void) inb(sc->nic_addr + ED_P0_CNTR0);
+ (void) inb(sc->nic_addr + ED_P0_CNTR1);
+ (void) inb(sc->nic_addr + ED_P0_CNTR2);
+ }
+ }
+}
+
+/*
+ * Process an ioctl request. This code needs some work - it looks
+ * pretty ugly.
+ */
+int
+ed_ioctl(ifp, command, data)
+ register struct ifnet *ifp;
+ int command;
+ caddr_t data;
+{
+ register struct ifaddr *ifa = (struct ifaddr *)data;
+ struct ed_softc *sc = &ed_softc[ifp->if_unit];
+ struct ifreq *ifr = (struct ifreq *)data;
+ int s, error = 0;
+
+ s = splimp();
+
+ switch (command) {
+
+ case SIOCSIFADDR:
+ ifp->if_flags |= IFF_UP;
+
+ switch (ifa->ifa_addr->sa_family) {
+#ifdef INET
+ case AF_INET:
+ ed_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 *)(sc->arpcom.ac_enaddr);
+ else {
+ /*
+ *
+ */
+ bcopy((caddr_t)ina->x_host.c_host,
+ (caddr_t)sc->arpcom.ac_enaddr,
+ sizeof(sc->arpcom.ac_enaddr));
+ }
+ /*
+ * Set new address
+ */
+ ed_init(ifp->if_unit);
+ break;
+ }
+#endif
+ default:
+ ed_init(ifp->if_unit);
+ break;
+ }
+ break;
+
+ case SIOCGIFADDR:
+ {
+ struct sockaddr *sa;
+ sa = (struct sockaddr *)&ifr->ifr_data;
+ bcopy((caddr_t)sc->arpcom.ac_enaddr,
+ (caddr_t) sa->sa_data, ETHER_ADDR_LEN);
+ }
+ 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)) {
+ ed_stop(ifp->if_unit);
+ 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))
+ ed_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 ed_init().
+ */
+ outb(sc->nic_addr + ED_P0_RCR,
+ ED_RCR_PRO|ED_RCR_AM|ED_RCR_AB);
+ } else {
+ /*
+ * XXX - for multicasts to work, we would need to
+ * rewrite the multicast hashing array with the
+ * proper hash (would have been destroyed above).
+ */
+ outb(sc->nic_addr + ED_P0_RCR, ED_RCR_AB);
+ }
+#endif
+ /*
+ * An unfortunate hack to provide the (required) software control
+ * of the tranceiver for 3Com boards. The ALTPHYS flag disables
+ * the tranceiver if set.
+ */
+ if (sc->vendor == ED_VENDOR_3COM) {
+ if (ifp->if_flags & IFF_ALTPHYS) {
+ outb(sc->asic_addr + ED_3COM_CR, 0);
+ } else {
+ outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_XSEL);
+ }
+ }
+
+ break;
+
+ default:
+ error = EINVAL;
+ }
+ (void) splx(s);
+ return (error);
+}
+
+/*
+ * Macro to calculate a new address within shared memory when given an offset
+ * from an address, taking into account ring-wrap.
+ */
+#define ringoffset(sc, start, off, type) \
+ ((type)( ((caddr_t)(start)+(off) >= (sc)->mem_end) ? \
+ (((caddr_t)(start)+(off))) - (sc)->mem_end \
+ + (sc)->mem_ring: \
+ ((caddr_t)(start)+(off)) ))
+
+/*
+ * Retreive packet from shared memory and send to the next level up via
+ * ether_input(). If there is a BPF listener, give a copy to BPF, too.
+ */
+static void
+ed_get_packet(sc, buf, len)
+ struct ed_softc *sc;
+ char *buf;
+ u_short len;
+{
+ struct ether_header *eh;
+ struct mbuf *m, *head = 0, *ed_ring_to_mbuf();
+ u_short off;
+ int resid;
+ u_short etype;
+ struct trailer_header trailer_header;
+
+ /* Allocate a header mbuf */
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == 0)
+ goto bad;
+ m->m_pkthdr.rcvif = &sc->arpcom.ac_if;
+ m->m_pkthdr.len = len;
+ m->m_len = 0;
+ head = m;
+
+ /* The following sillines is to make NFS happy */
+#define EROUND ((sizeof(struct ether_header) + 3) & ~3)
+#define EOFF (EROUND - sizeof(struct ether_header))
+
+ /*
+ * The following assumes there is room for
+ * the ether header in the header mbuf
+ */
+ head->m_data += EOFF;
+ eh = mtod(head, struct ether_header *);
+
+ if (sc->mem_shared)
+ bcopy(buf, mtod(head, caddr_t), sizeof(struct ether_header));
+ else
+ ed_pio_readmem(sc, buf, mtod(head, caddr_t),
+ sizeof(struct ether_header));
+ buf += sizeof(struct ether_header);
+ head->m_len += sizeof(struct ether_header);
+ len -= sizeof(struct ether_header);
+
+ etype = ntohs((u_short)eh->ether_type);
+
+ /*
+ * Deal with trailer protocol:
+ * If trailer protocol, calculate the datasize as 'off',
+ * which is also the offset to the trailer header.
+ * Set resid to the amount of packet data following the
+ * trailer header.
+ * Finally, copy residual data into mbuf chain.
+ */
+ if (etype >= ETHERTYPE_TRAIL &&
+ etype < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
+
+ off = (etype - ETHERTYPE_TRAIL) << 9;
+ if ((off + sizeof(struct trailer_header)) > len)
+ goto bad; /* insanity */
+
+ /*
+ * If we have shared memory, we can get info directly from the
+ * stored packet, otherwise we must get a local copy
+ * of the trailer header using PIO.
+ */
+ if (sc->mem_shared) {
+ eh->ether_type = *ringoffset(sc, buf, off, u_short *);
+ resid = ntohs(*ringoffset(sc, buf, off+2, u_short *));
+ } else {
+ struct trailer_header trailer_header;
+ ed_pio_readmem(sc,
+ ringoffset(sc, buf, off, caddr_t),
+ (char *) &trailer_header,
+ sizeof(trailer_header));
+ eh->ether_type = trailer_header.ether_type;
+ resid = trailer_header.ether_residual;
+ }
+
+ if ((off + resid) > len) goto bad; /* insanity */
+
+ resid -= sizeof(struct trailer_header);
+ if (resid < 0) goto bad; /* insanity */
+
+ m = ed_ring_to_mbuf(sc, ringoffset(sc, buf, off+4, char *),
+ head, resid);
+ if (m == 0) goto bad;
+
+ len = off;
+ head->m_pkthdr.len -= 4; /* subtract trailer header */
+ }
+
+ /*
+ * Pull packet off interface. Or if this was a trailer packet,
+ * the data portion is appended.
+ */
+ m = ed_ring_to_mbuf(sc, buf, m, len);
+ if (m == 0) goto bad;
+
+#if NBPFILTER > 0
+ /*
+ * Check if there's a BPF listener on this interface.
+ * If so, hand off the raw packet to bpf.
+ */
+ if (sc->bpf) {
+ bpf_mtap(sc->bpf, head);
+
+ /*
+ * 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 ((sc->arpcom.ac_if.if_flags & IFF_PROMISC) &&
+ bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr,
+ sizeof(eh->ether_dhost)) != 0 &&
+ bcmp(eh->ether_dhost, etherbroadcastaddr,
+ sizeof(eh->ether_dhost)) != 0) {
+
+ m_freem(head);
+ return;
+ }
+ }
+#endif
+
+ /*
+ * Fix up data start offset in mbuf to point past ether header
+ */
+ m_adj(head, sizeof(struct ether_header));
+
+ /*
+ * silly ether_input routine needs 'type' in host byte order
+ */
+ eh->ether_type = ntohs(eh->ether_type);
+
+ ether_input(&sc->arpcom.ac_if, eh, head);
+ return;
+
+bad: if (head)
+ m_freem(head);
+ return;
+}
+
+/*
+ * Supporting routines
+ */
+
+/*
+ * Given a NIC memory source address and a host memory destination
+ * address, copy 'amount' from NIC to host using Programmed I/O.
+ * The 'amount' is rounded up to a word - okay as long as mbufs
+ * are word sized.
+ * This routine is currently Novell-specific.
+ */
+void
+ed_pio_readmem(sc,src,dst,amount)
+ struct ed_softc *sc;
+ unsigned short src;
+ unsigned char *dst;
+ unsigned short amount;
+{
+ unsigned short tmp_amount;
+
+ /* select page 0 registers */
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STA);
+
+ /* round up to a word */
+ tmp_amount = amount;
+ if (amount & 1) ++amount;
+
+ /* set up DMA byte count */
+ outb(sc->nic_addr + ED_P0_RBCR0, amount);
+ outb(sc->nic_addr + ED_P0_RBCR1, amount>>8);
+
+ /* set up source address in NIC mem */
+ outb(sc->nic_addr + ED_P0_RSAR0, src);
+ outb(sc->nic_addr + ED_P0_RSAR1, src>>8);
+
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD0 | ED_CR_STA);
+
+ if (sc->isa16bit) {
+ insw(sc->asic_addr + ED_NOVELL_DATA, dst, amount/2);
+ } else
+ insb(sc->asic_addr + ED_NOVELL_DATA, dst, amount);
+
+}
+
+/*
+ * Stripped down routine for writing a linear buffer to NIC memory.
+ * Only used in the probe routine to test the memory. 'len' must
+ * be even.
+ */
+void
+ed_pio_writemem(sc,src,dst,len)
+ struct ed_softc *sc;
+ char *src;
+ unsigned short dst;
+ unsigned short len;
+{
+ int maxwait=100; /* about 120us */
+
+ /* select page 0 registers */
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STA);
+
+ /* reset remote DMA complete flag */
+ outb(sc->nic_addr + ED_P0_ISR, ED_ISR_RDC);
+
+ /* set up DMA byte count */
+ outb(sc->nic_addr + ED_P0_RBCR0, len);
+ outb(sc->nic_addr + ED_P0_RBCR1, len>>8);
+
+ /* set up destination address in NIC mem */
+ outb(sc->nic_addr + ED_P0_RSAR0, dst);
+ outb(sc->nic_addr + ED_P0_RSAR1, dst>>8);
+
+ /* set remote DMA write */
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD1 | ED_CR_STA);
+
+ if (sc->isa16bit)
+ outsw(sc->asic_addr + ED_NOVELL_DATA, src, len/2);
+ else
+ outsb(sc->asic_addr + ED_NOVELL_DATA, src, len);
+ /*
+ * Wait for remote DMA complete. This is necessary because on the
+ * transmit side, data is handled internally by the NIC in bursts
+ * and we can't start another remote DMA until this one completes.
+ * Not waiting causes really bad things to happen - like the NIC
+ * irrecoverably jamming the ISA bus.
+ */
+ while (((inb(sc->nic_addr + ED_P0_ISR) & ED_ISR_RDC) != ED_ISR_RDC) && --maxwait);
+}
+
+/*
+ * Write an mbuf chain to the destination NIC memory address using
+ * programmed I/O.
+ */
+u_short
+ed_pio_write_mbufs(sc,m,dst)
+ struct ed_softc *sc;
+ struct mbuf *m;
+ unsigned short dst;
+{
+ unsigned short len, mb_offset;
+ struct mbuf *mp;
+ unsigned char residual[2];
+ int maxwait=100; /* about 120us */
+
+ /* First, count up the total number of bytes to copy */
+ for (len = 0, mp = m; mp; mp = mp->m_next)
+ len += mp->m_len;
+
+ /* select page 0 registers */
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STA);
+
+ /* reset remote DMA complete flag */
+ outb(sc->nic_addr + ED_P0_ISR, ED_ISR_RDC);
+
+ /* set up DMA byte count */
+ outb(sc->nic_addr + ED_P0_RBCR0, len);
+ outb(sc->nic_addr + ED_P0_RBCR1, len>>8);
+
+ /* set up destination address in NIC mem */
+ outb(sc->nic_addr + ED_P0_RSAR0, dst);
+ outb(sc->nic_addr + ED_P0_RSAR1, dst>>8);
+
+ /* set remote DMA write */
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD1 | ED_CR_STA);
+
+ mb_offset = 0;
+ /*
+ * Transfer the mbuf chain to the NIC memory.
+ * The following code isn't too pretty. The problem is that we can only
+ * transfer words to the board, and if an mbuf has an odd number
+ * of bytes in it, this is a problem. It's not a simple matter of
+ * just removing a byte from the next mbuf (adjusting data++ and
+ * len--) because this will hose-over the mbuf chain which might
+ * be needed later for BPF. Instead, we maintain an offset
+ * (mb_offset) which let's us skip over the first byte in the
+ * following mbuf.
+ */
+ while (m) {
+ if (m->m_len - mb_offset) {
+ if (sc->isa16bit) {
+ if ((m->m_len - mb_offset) > 1)
+ outsw(sc->asic_addr + ED_NOVELL_DATA,
+ mtod(m, caddr_t) + mb_offset,
+ (m->m_len - mb_offset) / 2);
+
+ /*
+ * if odd number of bytes, get the odd byte from
+ * the next mbuf with data
+ */
+ if ((m->m_len - mb_offset) & 1) {
+ /* first the last byte in current mbuf */
+ residual[0] = *(mtod(m, caddr_t) +
+ m->m_len - 1);
+
+ /* advance past any empty mbufs */
+ while (m->m_next && (m->m_next->m_len == 0))
+ m = m->m_next;
+
+ if (m->m_next) {
+ /* remove first byte in next mbuf */
+ residual[1] = *(mtod(m->m_next, caddr_t));
+ mb_offset = 1;
+ }
+
+ outw(sc->asic_addr + ED_NOVELL_DATA,
+ *((unsigned short *) residual));
+ } else
+ mb_offset = 0;
+ } else
+ outsb(sc->asic_addr + ED_NOVELL_DATA, m->m_data, m->m_len);
+
+ }
+ m = m->m_next;
+ }
+
+ /*
+ * Wait for remote DMA complete. This is necessary because on the
+ * transmit side, data is handled internally by the NIC in bursts
+ * and we can't start another remote DMA until this one completes.
+ * Not waiting causes really bad things to happen - like the NIC
+ * irrecoverably jamming the ISA bus.
+ */
+ while (((inb(sc->nic_addr + ED_P0_ISR) & ED_ISR_RDC) != ED_ISR_RDC) && --maxwait);
+
+ if (!maxwait) {
+ log(LOG_WARNING, "ed%d: remote transmit DMA failed to complete\n",
+ sc->arpcom.ac_if.if_unit);
+ ed_reset(sc->arpcom.ac_if.if_unit);
+ }
+
+ return(len);
+}
+
+/*
+ * Given a source and destination address, copy 'amount' of a packet from
+ * the ring buffer into a linear destination buffer. Takes into account
+ * ring-wrap.
+ */
+static inline char *
+ed_ring_copy(sc,src,dst,amount)
+ struct ed_softc *sc;
+ char *src;
+ char *dst;
+ u_short amount;
+{
+ u_short tmp_amount;
+
+ /* does copy wrap to lower addr in ring buffer? */
+ if (src + amount > sc->mem_end) {
+ tmp_amount = sc->mem_end - src;
+
+ /* copy amount up to end of NIC memory */
+ if (sc->mem_shared)
+ bcopy(src,dst,tmp_amount);
+ else
+ ed_pio_readmem(sc,src,dst,tmp_amount);
+
+ amount -= tmp_amount;
+ src = sc->mem_ring;
+ dst += tmp_amount;
+ }
+
+ if (sc->mem_shared)
+ bcopy(src, dst, amount);
+ else
+ ed_pio_readmem(sc, src, dst, amount);
+
+ return(src + amount);
+}
+
+/*
+ * Copy data from receive buffer to end of mbuf chain
+ * allocate additional mbufs as needed. return pointer
+ * to last mbuf in chain.
+ * sc = ed info (softc)
+ * src = pointer in ed ring buffer
+ * dst = pointer to last mbuf in mbuf chain to copy to
+ * amount = amount of data to copy
+ */
+struct mbuf *
+ed_ring_to_mbuf(sc,src,dst,total_len)
+ struct ed_softc *sc;
+ char *src;
+ struct mbuf *dst;
+ u_short total_len;
+{
+ register struct mbuf *m = dst;
+
+ while (total_len) {
+ register u_short amount = min(total_len, M_TRAILINGSPACE(m));
+
+ if (amount == 0) { /* no more data in this mbuf, alloc another */
+ /*
+ * If there is enough data for an mbuf cluster, attempt
+ * to allocate one of those, otherwise, a regular
+ * mbuf will do.
+ * Note that a regular mbuf is always required, even if
+ * we get a cluster - getting a cluster does not
+ * allocate any mbufs, and one is needed to assign
+ * the cluster to. The mbuf that has a cluster
+ * extension can not be used to contain data - only
+ * the cluster can contain data.
+ */
+ dst = m;
+ MGET(m, M_DONTWAIT, MT_DATA);
+ if (m == 0)
+ return (0);
+
+ if (total_len >= MINCLSIZE)
+ MCLGET(m, M_DONTWAIT);
+
+ m->m_len = 0;
+ dst->m_next = m;
+ amount = min(total_len, M_TRAILINGSPACE(m));
+ }
+
+ src = ed_ring_copy(sc, src, mtod(m, caddr_t) + m->m_len, amount);
+
+ m->m_len += amount;
+ total_len -= amount;
+
+ }
+ return (m);
+}
+#endif
diff --git a/sys/dev/ed/if_edreg.h b/sys/dev/ed/if_edreg.h
new file mode 100644
index 0000000..f75e261
--- /dev/null
+++ b/sys/dev/ed/if_edreg.h
@@ -0,0 +1,962 @@
+/*
+ * National Semiconductor DS8390 NIC register definitions
+ *
+ * $Id: if_edreg.h,v 1.13 1994/02/02 14:05:58 davidg Exp $
+ *
+ * Modification history
+ *
+ * Revision 2.2 1993/11/29 16:33:39 davidg
+ * From Thomas Sandford <t.d.g.sandford@comp.brad.ac.uk>
+ * Add support for the 8013W board type
+ *
+ * Revision 2.1 1993/11/22 10:52:33 davidg
+ * patch to add support for SMC8216 (Elite-Ultra) boards
+ * from Glen H. Lowe
+ *
+ * Revision 2.0 93/09/29 00:37:15 davidg
+ * changed double buffering flag to multi buffering
+ * made changes/additions for 3c503 multi-buffering
+ * ...companion to Rev. 2.0 of 'ed' driver.
+ *
+ * Revision 1.1 93/06/23 03:01:07 davidg
+ * Initial revision
+ *
+ */
+
+/*
+ * Page 0 register offsets
+ */
+#define ED_P0_CR 0x00 /* Command Register */
+
+#define ED_P0_CLDA0 0x01 /* Current Local DMA Addr low (read) */
+#define ED_P0_PSTART 0x01 /* Page Start register (write) */
+
+#define ED_P0_CLDA1 0x02 /* Current Local DMA Addr high (read) */
+#define ED_P0_PSTOP 0x02 /* Page Stop register (write) */
+
+#define ED_P0_BNRY 0x03 /* Boundary Pointer */
+
+#define ED_P0_TSR 0x04 /* Transmit Status Register (read) */
+#define ED_P0_TPSR 0x04 /* Transmit Page Start (write) */
+
+#define ED_P0_NCR 0x05 /* Number of Collisions Reg (read) */
+#define ED_P0_TBCR0 0x05 /* Transmit Byte count, low (write) */
+
+#define ED_P0_FIFO 0x06 /* FIFO register (read) */
+#define ED_P0_TBCR1 0x06 /* Transmit Byte count, high (write) */
+
+#define ED_P0_ISR 0x07 /* Interrupt Status Register */
+
+#define ED_P0_CRDA0 0x08 /* Current Remote DMA Addr low (read) */
+#define ED_P0_RSAR0 0x08 /* Remote Start Address low (write) */
+
+#define ED_P0_CRDA1 0x09 /* Current Remote DMA Addr high (read) */
+#define ED_P0_RSAR1 0x09 /* Remote Start Address high (write) */
+
+#define ED_P0_RBCR0 0x0a /* Remote Byte Count low (write) */
+
+#define ED_P0_RBCR1 0x0b /* Remote Byte Count high (write) */
+
+#define ED_P0_RSR 0x0c /* Receive Status (read) */
+#define ED_P0_RCR 0x0c /* Receive Configuration Reg (write) */
+
+#define ED_P0_CNTR0 0x0d /* frame alignment error counter (read) */
+#define ED_P0_TCR 0x0d /* Transmit Configuration Reg (write) */
+
+#define ED_P0_CNTR1 0x0e /* CRC error counter (read) */
+#define ED_P0_DCR 0x0e /* Data Configuration Reg (write) */
+
+#define ED_P0_CNTR2 0x0f /* missed packet counter (read) */
+#define ED_P0_IMR 0x0f /* Interrupt Mask Register (write) */
+
+/*
+ * Page 1 register offsets
+ */
+#define ED_P1_CR 0x00 /* Command Register */
+#define ED_P1_PAR0 0x01 /* Physical Address Register 0 */
+#define ED_P1_PAR1 0x02 /* Physical Address Register 1 */
+#define ED_P1_PAR2 0x03 /* Physical Address Register 2 */
+#define ED_P1_PAR3 0x04 /* Physical Address Register 3 */
+#define ED_P1_PAR4 0x05 /* Physical Address Register 4 */
+#define ED_P1_PAR5 0x06 /* Physical Address Register 5 */
+#define ED_P1_CURR 0x07 /* Current RX ring-buffer page */
+#define ED_P1_MAR0 0x08 /* Multicast Address Register 0 */
+#define ED_P1_MAR1 0x09 /* Multicast Address Register 1 */
+#define ED_P1_MAR2 0x0a /* Multicast Address Register 2 */
+#define ED_P1_MAR3 0x0b /* Multicast Address Register 3 */
+#define ED_P1_MAR4 0x0c /* Multicast Address Register 4 */
+#define ED_P1_MAR5 0x0d /* Multicast Address Register 5 */
+#define ED_P1_MAR6 0x0e /* Multicast Address Register 6 */
+#define ED_P1_MAR7 0x0f /* Multicast Address Register 7 */
+
+/*
+ * Page 2 register offsets
+ */
+#define ED_P2_CR 0x00 /* Command Register */
+#define ED_P2_PSTART 0x01 /* Page Start (read) */
+#define ED_P2_CLDA0 0x01 /* Current Local DMA Addr 0 (write) */
+#define ED_P2_PSTOP 0x02 /* Page Stop (read) */
+#define ED_P2_CLDA1 0x02 /* Current Local DMA Addr 1 (write) */
+#define ED_P2_RNPP 0x03 /* Remote Next Packet Pointer */
+#define ED_P2_TPSR 0x04 /* Transmit Page Start (read) */
+#define ED_P2_LNPP 0x05 /* Local Next Packet Pointer */
+#define ED_P2_ACU 0x06 /* Address Counter Upper */
+#define ED_P2_ACL 0x07 /* Address Counter Lower */
+#define ED_P2_RCR 0x0c /* Receive Configuration Register (read) */
+#define ED_P2_TCR 0x0d /* Transmit Configuration Register (read) */
+#define ED_P2_DCR 0x0e /* Data Configuration Register (read) */
+#define ED_P2_IMR 0x0f /* Interrupt Mask Register (read) */
+
+/*
+ * Command Register (CR) definitions
+ */
+
+/*
+ * STP: SToP. Software reset command. Takes the controller offline. No
+ * packets will be received or transmitted. Any reception or
+ * transmission in progress will continue to completion before
+ * entering reset state. To exit this state, the STP bit must
+ * reset and the STA bit must be set. The software reset has
+ * executed only when indicated by the RST bit in the ISR being
+ * set.
+ */
+#define ED_CR_STP 0x01
+
+/*
+ * STA: STArt. This bit is used to activate the NIC after either power-up,
+ * or when the NIC has been put in reset mode by software command
+ * or error.
+ */
+#define ED_CR_STA 0x02
+
+/*
+ * TXP: Transmit Packet. This bit must be set to indicate transmission of
+ * a packet. TXP is internally reset either after the transmission is
+ * completed or aborted. This bit should be set only after the Transmit
+ * Byte Count and Transmit Page Start register have been programmed.
+ */
+#define ED_CR_TXP 0x04
+
+/*
+ * RD0, RD1, RD2: Remote DMA Command. These three bits control the operation
+ * of the remote DMA channel. RD2 can be set to abort any remote DMA
+ * command in progress. The Remote Byte Count registers should be cleared
+ * when a remote DMA has been aborted. The Remote Start Addresses are not
+ * restored to the starting address if the remote DMA is aborted.
+ *
+ * RD2 RD1 RD0 function
+ * 0 0 0 not allowed
+ * 0 0 1 remote read
+ * 0 1 0 remote write
+ * 0 1 1 send packet
+ * 1 X X abort
+ */
+#define ED_CR_RD0 0x08
+#define ED_CR_RD1 0x10
+#define ED_CR_RD2 0x20
+
+/*
+ * PS0, PS1: Page Select. The two bits select which register set or 'page' to
+ * access.
+ *
+ * PS1 PS0 page
+ * 0 0 0
+ * 0 1 1
+ * 1 0 2
+ * 1 1 reserved
+ */
+#define ED_CR_PS0 0x40
+#define ED_CR_PS1 0x80
+/* bit encoded aliases */
+#define ED_CR_PAGE_0 0x00 /* (for consistency) */
+#define ED_CR_PAGE_1 0x40
+#define ED_CR_PAGE_2 0x80
+
+/*
+ * Interrupt Status Register (ISR) definitions
+ */
+
+/*
+ * PRX: Packet Received. Indicates packet received with no errors.
+ */
+#define ED_ISR_PRX 0x01
+
+/*
+ * PTX: Packet Transmitted. Indicates packet transmitted with no errors.
+ */
+#define ED_ISR_PTX 0x02
+
+/*
+ * RXE: Receive Error. Indicates that a packet was received with one or more
+ * the following errors: CRC error, frame alignment error, FIFO overrun,
+ * missed packet.
+ */
+#define ED_ISR_RXE 0x04
+
+/*
+ * TXE: Transmission Error. Indicates that an attempt to transmit a packet
+ * resulted in one or more of the following errors: excessive
+ * collisions, FIFO underrun.
+ */
+#define ED_ISR_TXE 0x08
+
+/*
+ * OVW: OverWrite. Indicates a receive ring-buffer overrun. Incoming network
+ * would exceed (has exceeded?) the boundry pointer, resulting in data
+ * that was previously received and not yet read from the buffer to be
+ * overwritten.
+ */
+#define ED_ISR_OVW 0x10
+
+/*
+ * CNT: Counter Overflow. Set when the MSB of one or more of the Network Talley
+ * Counters has been set.
+ */
+#define ED_ISR_CNT 0x20
+
+/*
+ * RDC: Remote Data Complete. Indicates that a Remote DMA operation has completed.
+ */
+#define ED_ISR_RDC 0x40
+
+/*
+ * RST: Reset status. Set when the NIC enters the reset state and cleared when a
+ * Start Command is issued to the CR. This bit is also set when a receive
+ * ring-buffer overrun (OverWrite) occurs and is cleared when one or more
+ * packets have been removed from the ring. This is a read-only bit.
+ */
+#define ED_ISR_RST 0x80
+
+/*
+ * Interrupt Mask Register (IMR) definitions
+ */
+
+/*
+ * PRXE: Packet Received interrupt Enable. If set, a received packet will cause
+ * an interrupt.
+ */
+#define ED_IMR_PRXE 0x01
+
+/*
+ * PTXE: Packet Transmit interrupt Enable. If set, an interrupt is generated when
+ * a packet transmission completes.
+ */
+#define ED_IMR_PTXE 0x02
+
+/*
+ * RXEE: Receive Error interrupt Enable. If set, an interrupt will occur whenever a
+ * packet is received with an error.
+ */
+#define ED_IMR_RXEE 0x04
+
+/*
+ * TXEE: Transmit Error interrupt Enable. If set, an interrupt will occur whenever
+ * a transmission results in an error.
+ */
+#define ED_IMR_TXEE 0x08
+
+/*
+ * OVWE: OverWrite error interrupt Enable. If set, an interrupt is generated whenever
+ * the receive ring-buffer is overrun. i.e. when the boundry pointer is exceeded.
+ */
+#define ED_IMR_OVWE 0x10
+
+/*
+ * CNTE: Counter overflow interrupt Enable. If set, an interrupt is generated whenever
+ * the MSB of one or more of the Network Statistics counters has been set.
+ */
+#define ED_IMR_CNTE 0x20
+
+/*
+ * RDCE: Remote DMA Complete interrupt Enable. If set, an interrupt is generated
+ * when a remote DMA transfer has completed.
+ */
+#define ED_IMR_RDCE 0x40
+
+/*
+ * bit 7 is unused/reserved
+ */
+
+/*
+ * Data Configuration Register (DCR) definitions
+ */
+
+/*
+ * WTS: Word Transfer Select. WTS establishes byte or word transfers for
+ * both remote and local DMA transfers
+ */
+#define ED_DCR_WTS 0x01
+
+/*
+ * BOS: Byte Order Select. BOS sets the byte order for the host.
+ * Should be 0 for 80x86, and 1 for 68000 series processors
+ */
+#define ED_DCR_BOS 0x02
+
+/*
+ * LAS: Long Address Select. When LAS is 1, the contents of the remote
+ * DMA registers RSAR0 and RSAR1 are used to provide A16-A31
+ */
+#define ED_DCR_LAS 0x04
+
+/*
+ * LS: Loopback Select. When 0, loopback mode is selected. Bits D1 and D2
+ * of the TCR must also be programmed for loopback operation.
+ * When 1, normal operation is selected.
+ */
+#define ED_DCR_LS 0x08
+
+/*
+ * AR: Auto-initialize Remote. When 0, data must be removed from ring-buffer
+ * under program control. When 1, remote DMA is automatically initiated
+ * and the boundry pointer is automatically updated
+ */
+#define ED_DCR_AR 0x10
+
+/*
+ * FT0, FT1: Fifo Threshold select.
+ * FT1 FT0 Word-width Byte-width
+ * 0 0 1 word 2 bytes
+ * 0 1 2 words 4 bytes
+ * 1 0 4 words 8 bytes
+ * 1 1 8 words 12 bytes
+ *
+ * During transmission, the FIFO threshold indicates the number of bytes
+ * or words that the FIFO has filled from the local DMA before BREQ is
+ * asserted. The transmission threshold is 16 bytes minus the receiver
+ * threshold.
+ */
+#define ED_DCR_FT0 0x20
+#define ED_DCR_FT1 0x40
+
+/*
+ * bit 7 (0x80) is unused/reserved
+ */
+
+/*
+ * Transmit Configuration Register (TCR) definitions
+ */
+
+/*
+ * CRC: Inhibit CRC. If 0, CRC will be appended by the transmitter, if 0, CRC
+ * is not appended by the transmitter.
+ */
+#define ED_TCR_CRC 0x01
+
+/*
+ * LB0, LB1: Loopback control. These two bits set the type of loopback that is
+ * to be performed.
+ *
+ * LB1 LB0 mode
+ * 0 0 0 - normal operation (DCR_LS = 0)
+ * 0 1 1 - internal loopback (DCR_LS = 0)
+ * 1 0 2 - external loopback (DCR_LS = 1)
+ * 1 1 3 - external loopback (DCR_LS = 0)
+ */
+#define ED_TCR_LB0 0x02
+#define ED_TCR_LB1 0x04
+
+/*
+ * ATD: Auto Transmit Disable. Clear for normal operation. When set, allows
+ * another station to disable the NIC's transmitter by transmitting to
+ * a multicast address hashing to bit 62. Reception of a multicast address
+ * hashing to bit 63 enables the transmitter.
+ */
+#define ED_TCR_ATD 0x08
+
+/*
+ * OFST: Collision Offset enable. This bit when set modifies the backoff
+ * algorithm to allow prioritization of nodes.
+ */
+#define ED_TCR_OFST 0x10
+
+/*
+ * bits 5, 6, and 7 are unused/reserved
+ */
+
+/*
+ * Transmit Status Register (TSR) definitions
+ */
+
+/*
+ * PTX: Packet Transmitted. Indicates successful transmission of packet.
+ */
+#define ED_TSR_PTX 0x01
+
+/*
+ * bit 1 (0x02) is unused/reserved
+ */
+
+/*
+ * COL: Transmit Collided. Indicates that the transmission collided at least
+ * once with another station on the network.
+ */
+#define ED_TSR_COL 0x04
+
+/*
+ * ABT: Transmit aborted. Indicates that the transmission was aborted due to
+ * excessive collisions.
+ */
+#define ED_TSR_ABT 0x08
+
+/*
+ * CRS: Carrier Sense Lost. Indicates that carrier was lost during the
+ * transmission of the packet. (Transmission is not aborted because
+ * of a loss of carrier)
+ */
+#define ED_TSR_CRS 0x10
+
+/*
+ * FU: FIFO Underrun. Indicates that the NIC wasn't able to access bus/
+ * transmission memory before the FIFO emptied. Transmission of the
+ * packet was aborted.
+ */
+#define ED_TSR_FU 0x20
+
+/*
+ * CDH: CD Heartbeat. Indicates that the collision detection circuitry
+ * isn't working correctly during a collision heartbeat test.
+ */
+#define ED_TSR_CDH 0x40
+
+/*
+ * OWC: Out of Window Collision: Indicates that a collision occurred after
+ * a slot time (51.2us). The transmission is rescheduled just as in
+ * normal collisions.
+ */
+#define ED_TSR_OWC 0x80
+
+/*
+ * Receiver Configuration Register (RCR) definitions
+ */
+
+/*
+ * SEP: Save Errored Packets. If 0, error packets are discarded. If set to 1,
+ * packets with CRC and frame errors are not discarded.
+ */
+#define ED_RCR_SEP 0x01
+
+/*
+ * AR: Accept Runt packet. If 0, packet with less than 64 byte are discarded.
+ * If set to 1, packets with less than 64 byte are not discarded.
+ */
+#define ED_RCR_AR 0x02
+
+/*
+ * AB: Accept Broadcast. If set, packets sent to the broadcast address will be
+ * accepted.
+ */
+#define ED_RCR_AB 0x04
+
+/*
+ * AM: Accept Multicast. If set, packets sent to a multicast address are checked
+ * for a match in the hashing array. If clear, multicast packets are ignored.
+ */
+#define ED_RCR_AM 0x08
+
+/*
+ * PRO: Promiscuous Physical. If set, all packets with a physical addresses are
+ * accepted. If clear, a physical destination address must match this
+ * station's address. Note: for full promiscuous mode, RCR_AB and RCR_AM
+ * must also be set. In addition, the multicast hashing array must be set
+ * to all 1's so that all multicast addresses are accepted.
+ */
+#define ED_RCR_PRO 0x10
+
+/*
+ * MON: Monitor Mode. If set, packets will be checked for good CRC and framing,
+ * but are not stored in the ring-buffer. If clear, packets are stored (normal
+ * operation).
+ */
+#define ED_RCR_MON 0x20
+
+/*
+ * bits 6 and 7 are unused/reserved.
+ */
+
+/*
+ * Receiver Status Register (RSR) definitions
+ */
+
+/*
+ * PRX: Packet Received without error.
+ */
+#define ED_RSR_PRX 0x01
+
+/*
+ * CRC: CRC error. Indicates that a packet has a CRC error. Also set for frame
+ * alignment errors.
+ */
+#define ED_RSR_CRC 0x02
+
+/*
+ * FAE: Frame Alignment Error. Indicates that the incoming packet did not end on
+ * a byte boundry and the CRC did not match at the last byte boundry.
+ */
+#define ED_RSR_FAE 0x04
+
+/*
+ * FO: FIFO Overrun. Indicates that the FIFO was not serviced (during local DMA)
+ * causing it to overrun. Reception of the packet is aborted.
+ */
+#define ED_RSR_FO 0x08
+
+/*
+ * MPA: Missed Packet. Indicates that the received packet couldn't be stored in
+ * the ring-buffer because of insufficient buffer space (exceeding the
+ * boundry pointer), or because the transfer to the ring-buffer was inhibited
+ * by RCR_MON - monitor mode.
+ */
+#define ED_RSR_MPA 0x10
+
+/*
+ * PHY: Physical address. If 0, the packet received was sent to a physical address.
+ * If 1, the packet was accepted because of a multicast/broadcast address
+ * match.
+ */
+#define ED_RSR_PHY 0x20
+
+/*
+ * DIS: Receiver Disabled. Set to indicate that the receiver has enetered monitor
+ * mode. Cleared when the receiver exits monitor mode.
+ */
+#define ED_RSR_DIS 0x40
+
+/*
+ * DFR: Deferring. Set to indicate a 'jabber' condition. The CRS and COL inputs
+ * are active, and the transceiver has set the CD line as a result of the
+ * jabber.
+ */
+#define ED_RSR_DFR 0x80
+
+/*
+ * receive ring discriptor
+ *
+ * The National Semiconductor DS8390 Network interface controller uses
+ * the following receive ring headers. The way this works is that the
+ * memory on the interface card is chopped up into 256 bytes blocks.
+ * A contiguous portion of those blocks are marked for receive packets
+ * by setting start and end block #'s in the NIC. For each packet that
+ * is put into the receive ring, one of these headers (4 bytes each) is
+ * tacked onto the front.
+ */
+struct ed_ring {
+ struct edr_status { /* received packet status */
+ u_char rs_prx:1, /* packet received intack */
+ rs_crc:1, /* crc error */
+ rs_fae:1, /* frame alignment error */
+ rs_fo:1, /* fifo overrun */
+ rs_mpa:1, /* packet received intack */
+ rs_phy:1, /* packet received intack */
+ rs_dis:1, /* packet received intack */
+ rs_dfr:1; /* packet received intack */
+ } ed_rcv_status; /* received packet status */
+ u_char next_packet; /* pointer to next packet */
+ u_short count; /* bytes in packet (length + 4) */
+};
+
+/*
+ * Common constants
+ */
+#define ED_PAGE_SIZE 256 /* Size of RAM pages in bytes */
+#define ED_TXBUF_SIZE 6 /* Size of TX buffer in pages */
+
+/*
+ * Vendor types
+ */
+#define ED_VENDOR_WD_SMC 0x00 /* Western Digital/SMC */
+#define ED_VENDOR_3COM 0x01 /* 3Com */
+#define ED_VENDOR_NOVELL 0x02 /* Novell */
+
+/*
+ * Compile-time config flags
+ */
+/*
+ * this sets the default for enabling/disablng the tranceiver
+ */
+#define ED_FLAGS_DISABLE_TRANCEIVER 0x0001
+
+/*
+ * This forces the board to be used in 8/16bit mode even if it
+ * autoconfigs differently
+ */
+#define ED_FLAGS_FORCE_8BIT_MODE 0x0002
+#define ED_FLAGS_FORCE_16BIT_MODE 0x0004
+
+/*
+ * This disables the use of double transmit buffers.
+ */
+#define ED_FLAGS_NO_MULTI_BUFFERING 0x0008
+
+/*
+ * This forces all operations with the NIC memory to use Programmed
+ * I/O (i.e. not via shared memory)
+ */
+#define ED_FLAGS_FORCE_PIO 0x0010
+
+/*
+ * Definitions for Western digital/SMC WD80x3 series ASIC
+ */
+/*
+ * Memory Select Register (MSR)
+ */
+#define ED_WD_MSR 0
+
+/* next three definitions for Toshiba */
+#define ED_WD_MSR_POW 0x02 /* 0 = power save, 1 = normal (R/W) */
+#define ED_WD_MSR_BSY 0x04 /* gate array busy (R) */
+#define ED_WD_MSR_LEN 0x20 /* data bus width, 0 = 16 bits,
+ 1 = 8 bits (R/W) */
+#define ED_WD_MSR_ADDR 0x3f /* Memory decode bits 18-13 */
+#define ED_WD_MSR_MENB 0x40 /* Memory enable */
+#define ED_WD_MSR_RST 0x80 /* Reset board */
+
+/*
+ * Interface Configuration Register (ICR)
+ */
+#define ED_WD_ICR 1
+
+#define ED_WD_ICR_16BIT 0x01 /* 16-bit interface */
+#define ED_WD_ICR_OAR 0x02 /* select register. 0=BIO 1=EAR */
+#define ED_WD_ICR_IR2 0x04 /* high order bit of encoded IRQ */
+#define ED_WD_ICR_MSZ 0x08 /* memory size (0=8k 1=32k) */
+#define ED_WD_ICR_RLA 0x10 /* recall LAN address */
+#define ED_WD_ICR_RX7 0x20 /* recall all but i/o and LAN address */
+#define ED_WD_ICR_RIO 0x40 /* recall i/o address */
+#define ED_WD_ICR_STO 0x80 /* store to non-volatile memory */
+#ifdef TOSH_ETHER
+#define ED_WD_ICR_MEM 0xe0 /* shared mem address A15-A13 (R/W) */
+#define ED_WD_ICR_MSZ1 0x0f /* memory size, 0x08 = 64K, 0x04 = 32K,
+ 0x02 = 16K, 0x01 = 8K */
+ /* 64K can only be used if mem address
+ above 1Mb */
+ /* IAR holds address A23-A16 (R/W) */
+#endif
+
+/*
+ * IO Address Register (IAR)
+ */
+#define ED_WD_IAR 2
+
+/*
+ * EEROM Address Register
+ */
+#define ED_WD_EAR 3
+
+/*
+ * Interrupt Request Register (IRR)
+ */
+#define ED_WD_IRR 4
+
+#define ED_WD_IRR_0WS 0x01 /* use 0 wait-states on 8 bit bus */
+#define ED_WD_IRR_OUT1 0x02 /* WD83C584 pin 1 output */
+#define ED_WD_IRR_OUT2 0x04 /* WD83C584 pin 2 output */
+#define ED_WD_IRR_OUT3 0x08 /* WD83C584 pin 3 output */
+#define ED_WD_IRR_FLASH 0x10 /* Flash RAM is in the ROM socket */
+
+/*
+ * The three bits of the encoded IRQ are decoded as follows:
+ *
+ * IR2 IR1 IR0 IRQ
+ * 0 0 0 2/9
+ * 0 0 1 3
+ * 0 1 0 5
+ * 0 1 1 7
+ * 1 0 0 10
+ * 1 0 1 11
+ * 1 1 0 15
+ * 1 1 1 4
+ */
+#define ED_WD_IRR_IR0 0x20 /* bit 0 of encoded IRQ */
+#define ED_WD_IRR_IR1 0x40 /* bit 1 of encoded IRQ */
+#define ED_WD_IRR_IEN 0x80 /* Interrupt enable */
+
+/*
+ * LA Address Register (LAAR)
+ */
+#define ED_WD_LAAR 5
+
+#define ED_WD_LAAR_ADDRHI 0x1f /* bits 23-19 of RAM address */
+#define ED_WD_LAAR_0WS16 0x20 /* enable 0 wait-states on 16 bit bus */
+#define ED_WD_LAAR_L16EN 0x40 /* enable 16-bit operation */
+#define ED_WD_LAAR_M16EN 0x80 /* enable 16-bit memory access */
+
+/* i/o base offset to station address/card-ID PROM */
+#define ED_WD_PROM 8
+
+/*
+ * 83C790 specific registers
+ */
+/*
+ * Hardware Support Register (HWR) ('790)
+ */
+#define ED_WD790_HWR 4
+
+#define WD_WD790_HWR_NUKE 0x10 /* hardware reset */
+#define ED_WD790_HWR_LPRM 0x40 /* LAN PROM select */
+#define ED_WD790_HWR_SWH 0x80 /* switch register set */
+
+/*
+ * ICR790 Interrupt Control Register for the 83C790
+ */
+#define ED_WD790_ICR 6
+
+#define ED_WD790_ICR_EIL 0x01 /* enable interrupts */
+
+/*
+ * General Control Register (GCR)
+ * Enabled with SWH bit=1 in HWR register
+ */
+#define ED_WD790_GCR 0x0d
+
+#define ED_WD790_GCR_IR0 0x04 /* bit 0 of encoded IRQ */
+#define ED_WD790_GCR_IR1 0x08 /* bit 1 of encoded IRQ */
+#define ED_WD790_GCR_ZWSEN 0x20 /* zero wait state enable */
+#define ED_WD790_GCR_IR2 0x40 /* bit 2 of encoded IRQ */
+/*
+ * The three bits of the encoded IRQ are decoded as follows:
+ *
+ * IR2 IR1 IR0 IRQ
+ * 0 0 0 none
+ * 0 0 1 9
+ * 0 1 0 3
+ * 0 1 1 5
+ * 1 0 0 7
+ * 1 0 1 10
+ * 1 1 0 11
+ * 1 1 1 15
+ */
+
+/* i/o base offset to CARD ID */
+#define ED_WD_CARD_ID ED_WD_PROM+6
+
+/* Board type codes in card ID */
+#define ED_TYPE_WD8003S 0x02
+#define ED_TYPE_WD8003E 0x03
+#define ED_TYPE_WD8013EBT 0x05
+#define ED_TYPE_TOSHIBA1 0x11 /* named PCETA1 */
+#define ED_TYPE_TOSHIBA2 0x12 /* named PCETA2 */
+#define ED_TYPE_TOSHIBA3 0x13 /* named PCETB */
+#define ED_TYPE_TOSHIBA4 0x14 /* named PCETC */
+#define ED_TYPE_WD8003W 0x24
+#define ED_TYPE_WD8003EB 0x25
+#define ED_TYPE_WD8013W 0x26
+#define ED_TYPE_WD8013EP 0x27
+#define ED_TYPE_WD8013WC 0x28
+#define ED_TYPE_WD8013EPC 0x29
+#define ED_TYPE_SMC8216T 0x2a
+#define ED_TYPE_SMC8216C 0x2b
+#define ED_TYPE_WD8013EBP 0x2c
+
+/* Bit definitions in card ID */
+#define ED_WD_REV_MASK 0x1f /* Revision mask */
+#define ED_WD_SOFTCONFIG 0x20 /* Soft config */
+#define ED_WD_LARGERAM 0x40 /* Large RAM */
+#define ED_MICROCHANEL 0x80 /* Microchannel bus (vs. isa) */
+
+/*
+ * Checksum total. All 8 bytes in station address PROM will add up to this
+ */
+#ifdef TOSH_ETHER
+#define ED_WD_ROM_CHECKSUM_TOTAL 0xA5
+#else
+#define ED_WD_ROM_CHECKSUM_TOTAL 0xFF
+#endif
+
+#define ED_WD_NIC_OFFSET 0x10 /* I/O base offset to NIC */
+#define ED_WD_ASIC_OFFSET 0 /* I/O base offset to ASIC */
+#define ED_WD_IO_PORTS 32 /* # of i/o addresses used */
+
+#define ED_WD_PAGE_OFFSET 0 /* page offset for NIC access to mem */
+
+/*
+ * Definitions for 3Com 3c503
+ */
+#define ED_3COM_NIC_OFFSET 0
+#define ED_3COM_ASIC_OFFSET 0x400 /* offset to nic i/o regs */
+
+/*
+ * XXX - The I/O address range is fragmented in the 3c503; this is the
+ * number of regs at iobase.
+ */
+#define ED_3COM_IO_PORTS 16 /* # of i/o addresses used */
+
+/* tx memory starts in second bank on 8bit cards */
+#define ED_3COM_TX_PAGE_OFFSET_8BIT 0x20
+
+/* tx memory starts in first bank on 16bit cards */
+#define ED_3COM_TX_PAGE_OFFSET_16BIT 0x0
+
+/* ...and rx memory starts in second bank */
+#define ED_3COM_RX_PAGE_OFFSET_16BIT 0x20
+
+
+/*
+ * Page Start Register. Must match PSTART in NIC
+ */
+#define ED_3COM_PSTR 0
+
+/*
+ * Page Stop Register. Must match PSTOP in NIC
+ */
+#define ED_3COM_PSPR 1
+
+/*
+ * Drq Timer Register. Determines number of bytes to be transfered during
+ * a DMA burst.
+ */
+#define ED_3COM_DQTR 2
+
+/*
+ * Base Configuration Register. Read-only register which contains the
+ * board-configured I/O base address of the adapter. Bit encoded.
+ */
+#define ED_3COM_BCFR 3
+
+#define ED_3COM_BCFR_2E0 0x01
+#define ED_3COM_BCFR_2A0 0x02
+#define ED_3COM_BCFR_280 0x04
+#define ED_3COM_BCFR_250 0x08
+#define ED_3COM_BCFR_350 0x10
+#define ED_3COM_BCFR_330 0x20
+#define ED_3COM_BCFR_310 0x40
+#define ED_3COM_BCFR_300 0x80
+
+/*
+ * EPROM Configuration Register. Read-only register which contains the
+ * board-configured memory base address. Bit encoded.
+ */
+#define ED_3COM_PCFR 4
+
+#define ED_3COM_PCFR_C8000 0x10
+#define ED_3COM_PCFR_CC000 0x20
+#define ED_3COM_PCFR_D8000 0x40
+#define ED_3COM_PCFR_DC000 0x80
+
+/*
+ * GA Configuration Register. Gate-Array Configuration Register.
+ */
+#define ED_3COM_GACFR 5
+
+/*
+ * mbs2 mbs1 mbs0 start address
+ * 0 0 0 0x0000
+ * 0 0 1 0x2000
+ * 0 1 0 0x4000
+ * 0 1 1 0x6000
+ *
+ * Note that with adapters with only 8K, the setting for 0x2000 must
+ * always be used.
+ */
+#define ED_3COM_GACFR_MBS0 0x01
+#define ED_3COM_GACFR_MBS1 0x02
+#define ED_3COM_GACFR_MBS2 0x04
+
+#define ED_3COM_GACFR_RSEL 0x08 /* enable shared memory */
+#define ED_3COM_GACFR_TEST 0x10 /* for GA testing */
+#define ED_3COM_GACFR_OWS 0x20 /* select 0WS access to GA */
+#define ED_3COM_GACFR_TCM 0x40 /* Mask DMA interrupts */
+#define ED_3COM_GACFR_NIM 0x80 /* Mask NIC interrupts */
+
+/*
+ * Control Register. Miscellaneous control functions.
+ */
+#define ED_3COM_CR 6
+
+#define ED_3COM_CR_RST 0x01 /* Reset GA and NIC */
+#define ED_3COM_CR_XSEL 0x02 /* Transceiver select. BNC=1(def) AUI=0 */
+#define ED_3COM_CR_EALO 0x04 /* window EA PROM 0-15 to I/O base */
+#define ED_3COM_CR_EAHI 0x08 /* window EA PROM 16-31 to I/O base */
+#define ED_3COM_CR_SHARE 0x10 /* select interrupt sharing option */
+#define ED_3COM_CR_DBSEL 0x20 /* Double buffer select */
+#define ED_3COM_CR_DDIR 0x40 /* DMA direction select */
+#define ED_3COM_CR_START 0x80 /* Start DMA controller */
+
+/*
+ * Status Register. Miscellaneous status information.
+ */
+#define ED_3COM_STREG 7
+
+#define ED_3COM_STREG_REV 0x07 /* GA revision */
+#define ED_3COM_STREG_DIP 0x08 /* DMA in progress */
+#define ED_3COM_STREG_DTC 0x10 /* DMA terminal count */
+#define ED_3COM_STREG_OFLW 0x20 /* Overflow */
+#define ED_3COM_STREG_UFLW 0x40 /* Underflow */
+#define ED_3COM_STREG_DPRDY 0x80 /* Data port ready */
+
+/*
+ * Interrupt/DMA Configuration Register
+ */
+#define ED_3COM_IDCFR 8
+
+#define ED_3COM_IDCFR_DRQ0 0x01 /* DMA request 1 select */
+#define ED_3COM_IDCFR_DRQ1 0x02 /* DMA request 2 select */
+#define ED_3COM_IDCFR_DRQ2 0x04 /* DMA request 3 select */
+#define ED_3COM_IDCFR_UNUSED 0x08 /* not used */
+#define ED_3COM_IDCFR_IRQ2 0x10 /* Interrupt request 2 select */
+#define ED_3COM_IDCFR_IRQ3 0x20 /* Interrupt request 3 select */
+#define ED_3COM_IDCFR_IRQ4 0x40 /* Interrupt request 4 select */
+#define ED_3COM_IDCFR_IRQ5 0x80 /* Interrupt request 5 select */
+
+/*
+ * DMA Address Register MSB
+ */
+#define ED_3COM_DAMSB 9
+
+/*
+ * DMA Address Register LSB
+ */
+#define ED_3COM_DALSB 0x0a
+
+/*
+ * Vector Pointer Register 2
+ */
+#define ED_3COM_VPTR2 0x0b
+
+/*
+ * Vector Pointer Register 1
+ */
+#define ED_3COM_VPTR1 0x0c
+
+/*
+ * Vector Pointer Register 0
+ */
+#define ED_3COM_VPTR0 0x0d
+
+/*
+ * Register File Access MSB
+ */
+#define ED_3COM_RFMSB 0x0e
+
+/*
+ * Register File Access LSB
+ */
+#define ED_3COM_RFLSB 0x0f
+
+/*
+ * Definitions for Novell NE1000/2000 boards
+ */
+
+/*
+ * Board type codes
+ */
+#define ED_TYPE_NE1000 0x01
+#define ED_TYPE_NE2000 0x02
+
+/*
+ * Register offsets/total
+ */
+#define ED_NOVELL_NIC_OFFSET 0x00
+#define ED_NOVELL_ASIC_OFFSET 0x10
+#define ED_NOVELL_IO_PORTS 32
+
+/*
+ * Remote DMA data register; for reading or writing to the NIC mem
+ * via programmed I/O (offset from ASIC base)
+ */
+#define ED_NOVELL_DATA 0x00
+
+/*
+ * Reset register; reading from this register causes a board reset
+ */
+#define ED_NOVELL_RESET 0x0f
diff --git a/sys/dev/ep/if_ep.c b/sys/dev/ep/if_ep.c
new file mode 100644
index 0000000..b47f829
--- /dev/null
+++ b/sys/dev/ep/if_ep.c
@@ -0,0 +1,993 @@
+/*
+ * Copyright (c) 1993 Herb Peyerl <hpeyerl@novatel.ca>
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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: if_ep.c,v 1.9 1994/01/25 10:46:29 deraadt Exp $
+ * $Id: if_ep.c,v 1.8 1994/03/15 01:58:22 wollman Exp $
+ */
+
+#include "ep.h"
+#if NEP > 0
+
+#include "bpfilter.h"
+
+#include <sys/param.h>
+#if defined(__FreeBSD__)
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#endif
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/errno.h>
+#include <sys/syslog.h>
+#if defined(__NetBSD__)
+#include <sys/select.h>
+#endif
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.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 <machine/pio.h>
+
+#include <i386/isa/isa.h>
+#include <i386/isa/isa_device.h>
+#include <i386/isa/icu.h>
+#include <i386/isa/if_epreg.h>
+
+#define ETHER_MIN_LEN 64
+#define ETHER_MAX_LEN 1518
+#define ETHER_ADDR_LEN 6
+
+/*
+ * Ethernet software status per interface.
+ */
+struct ep_softc {
+ struct arpcom arpcom; /* Ethernet common part */
+ short ep_io_addr; /* i/o bus address */
+ char ep_connectors; /* Connectors on this card. */
+#define MAX_MBS 8 /* # of mbufs we keep around */
+ struct mbuf *mb[MAX_MBS]; /* spare mbuf storage. */
+ int next_mb; /* Which mbuf to use next. */
+ int last_mb; /* Last mbuf. */
+ int tx_start_thresh; /* Current TX_start_thresh. */
+ caddr_t bpf; /* BPF "magic cookie" */
+ char bus32bit; /* 32bit access possible */
+} ep_softc[NEP];
+
+static int epprobe __P((struct isa_device *));
+static int epattach __P((struct isa_device *));
+static int epioctl __P((struct ifnet * ifp, int, caddr_t));
+
+void epinit __P((int));
+void epintr __P((int));
+void epmbuffill __P((caddr_t));
+void epmbufempty __P((struct ep_softc *));
+void epread __P((struct ep_softc *));
+void epreset __P((int));
+void epstart __P((struct ifnet *));
+void epstop __P((int));
+void epwatchdog __P((int));
+
+struct isa_driver epdriver = {
+ epprobe,
+ epattach,
+ "ep"
+};
+
+static int send_ID_sequence __P((u_short));
+static u_short get_eeprom_data __P((int, int));
+static int is_eeprom_busy __P((struct isa_device *));
+
+/*
+ * Rudimentary support for multiple cards is here but is not
+ * currently handled. In the future we will have to add code
+ * for tagging the cards for later activation. We wanna do something
+ * about the id_port. We're limited due to current config procedure.
+ * Magnum config holds promise of a fix but we'll have to wait a bit.
+ */
+int
+epprobe(is)
+ struct isa_device *is;
+{
+ struct ep_softc *sc = &ep_softc[is->id_unit];
+ u_short k;
+ int id_port = 0x100; /* XXX */
+
+ outw(BASE + EP_COMMAND, GLOBAL_RESET);
+ DELAY(1000);
+ outb(id_port, 0xc0); /* Global reset to id_port. */
+ DELAY(1000);
+ send_ID_sequence(id_port);
+ DELAY(1000);
+
+ /*
+ * MFG_ID should have 0x6d50.
+ * PROD_ID should be 0x9[0-f]50
+ */
+ k = get_eeprom_data(id_port, EEPROM_MFG_ID);
+ if (k != MFG_ID)
+ return (0);
+ k = get_eeprom_data(id_port, EEPROM_PROD_ID);
+ if ((k & 0xf0ff) != (PROD_ID & 0xf0ff))
+ return (0);
+
+ k = get_eeprom_data(id_port, EEPROM_ADDR_CFG); /* get addr cfg */
+ k = (k & 0x1f) * 0x10 + 0x200; /* decode base addr. */
+ if (k != (u_short)is->id_iobase)
+ return (0);
+
+ k = get_eeprom_data(id_port, EEPROM_RESOURCE_CFG);
+ k >>= 12;
+ if (is->id_irq != (1 << ((k == 2) ? 9 : k)))
+ return (0);
+
+ outb(id_port, ACTIVATE_ADAPTER_TO_CONFIG);
+
+ return (0x10); /* 16 bytes of I/O space used. */
+}
+
+static int
+epattach(is)
+ struct isa_device *is;
+{
+ struct ep_softc *sc = &ep_softc[is->id_unit];
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ u_short i;
+ struct ifaddr *ifa;
+ struct sockaddr_dl *sdl;
+
+ sc->ep_io_addr = is->id_iobase;
+
+ printf("ep%d: ", is->id_unit);
+
+ sc->ep_connectors = 0;
+ i = inw(is->id_iobase + EP_W0_CONFIG_CTRL);
+ if (i & IS_AUI) {
+ printf("aui");
+ sc->ep_connectors |= AUI;
+ }
+ if (i & IS_BNC) {
+ if (sc->ep_connectors)
+ printf("/");
+ printf("bnc");
+ sc->ep_connectors |= BNC;
+ }
+ if (i & IS_UTP) {
+ if (sc->ep_connectors)
+ printf("/");
+ printf("utp");
+ sc->ep_connectors |= UTP;
+ }
+ if (!sc->ep_connectors)
+ printf("no connectors!");
+
+ /*
+ * Read the station address from the eeprom
+ */
+ for (i = 0; i < 3; i++) {
+ u_short *p;
+ GO_WINDOW(0);
+ if (is_eeprom_busy(is))
+ return(0);
+ outw(BASE + EP_W0_EEPROM_COMMAND, READ_EEPROM | i);
+ if (is_eeprom_busy(is))
+ return(0);
+ p =(u_short *)&sc->arpcom.ac_enaddr[i*2];
+ *p = htons(inw(BASE + EP_W0_EEPROM_DATA));
+ GO_WINDOW(2);
+ outw(BASE + EP_W2_ADDR_0 + (i * 2), ntohs(*p));
+ }
+ printf(" address %s\n", ether_sprintf(sc->arpcom.ac_enaddr));
+
+ ifp->if_unit = is->id_unit;
+ ifp->if_name = "ep";
+ ifp->if_mtu = ETHERMTU;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
+ ifp->if_init = epinit;
+ ifp->if_output = ether_output;
+ ifp->if_start = epstart;
+ ifp->if_ioctl = epioctl;
+ ifp->if_watchdog = epwatchdog;
+
+ if_attach(ifp);
+
+ /*
+ * Fill the hardware address into ifa_addr if we find an
+ * AF_LINK entry. We need to do this so bpf's can get the hardware
+ * addr of this card. netstat likes this too!
+ */
+ ifa = ifp->if_addrlist;
+ while ((ifa != 0) && (ifa->ifa_addr != 0) &&
+ (ifa->ifa_addr->sa_family != AF_LINK))
+ ifa = ifa->ifa_next;
+
+ if ((ifa != 0) && (ifa->ifa_addr != 0)) {
+ sdl = (struct sockaddr_dl *) ifa->ifa_addr;
+ sdl->sdl_type = IFT_ETHER;
+ sdl->sdl_alen = ETHER_ADDR_LEN;
+ sdl->sdl_slen = 0;
+ bcopy(sc->arpcom.ac_enaddr, LLADDR(sdl), ETHER_ADDR_LEN);
+ }
+#if NBPFILTER > 0
+ bpfattach(&sc->bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
+#endif
+ return 1;
+}
+
+
+/*
+ * The order in here seems important. Otherwise we may not receive
+ * interrupts. ?!
+ */
+void
+epinit(unit)
+ int unit;
+{
+ register struct ep_softc *sc = &ep_softc[unit];
+ register struct ifnet *ifp = &sc->arpcom.ac_if;
+ int s, i;
+
+ if (ifp->if_addrlist == (struct ifaddr *) 0)
+ return;
+
+ s = splimp();
+ while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS)
+ ;
+
+ GO_WINDOW(0);
+
+ /* Disable the card */
+ outw(BASE + EP_W0_CONFIG_CTRL, 0);
+
+ /* Enable the card */
+ outw(BASE + EP_W0_CONFIG_CTRL, ENABLE_DRQ_IRQ);
+
+ GO_WINDOW(2);
+
+ /* Reload the ether_addr. */
+ for (i = 0; i < 6; i++)
+ outb(BASE + EP_W2_ADDR_0 + i, sc->arpcom.ac_enaddr[i]);
+
+ outw(BASE + EP_COMMAND, RX_RESET);
+ outw(BASE + EP_COMMAND, TX_RESET);
+
+ /* Window 1 is operating window */
+ GO_WINDOW(1);
+ for (i = 0; i < 31; i++)
+ inb(BASE + EP_W1_TX_STATUS);
+
+ /* get rid of stray intr's */
+ outw(BASE + EP_COMMAND, ACK_INTR | 0xff);
+
+ outw(BASE + EP_COMMAND, SET_RD_0_MASK | S_CARD_FAILURE | S_RX_COMPLETE |
+ S_TX_COMPLETE | S_TX_AVAIL);
+ outw(BASE + EP_COMMAND, SET_INTR_MASK | S_CARD_FAILURE | S_RX_COMPLETE |
+ S_TX_COMPLETE | S_TX_AVAIL);
+
+ outw(BASE + EP_COMMAND, SET_RX_FILTER | FIL_INDIVIDUAL |
+ FIL_GROUP | FIL_BRDCST);
+
+ /*
+ * you can `ifconfig (link0|-link0) ep0' to get the following
+ * behaviour:
+ * -link0 disable AUI/UTP. enable BNC.
+ * link0 disable BNC. enable AUI. if the card has a UTP
+ * connector, that is enabled too. not sure, but it
+ * seems you have to be careful to not plug things
+ * into both AUI & UTP.
+ */
+#if defined(__NetBSD__)
+ if (!(ifp->if_flags & IFF_LINK0) && (sc->ep_connectors & BNC)) {
+#else
+ if (!(ifp->if_flags & IFF_ALTPHYS) && (sc->ep_connectors & BNC)) {
+#endif
+ outw(BASE + EP_COMMAND, START_TRANSCEIVER);
+ DELAY(1000);
+ }
+#if defined(__NetBSD__)
+ if ((ifp->if_flags & IFF_LINK0) && (sc->ep_connectors & UTP)) {
+#else
+ if ((ifp->if_flags & IFF_ALTPHYS) && (sc->ep_connectors & UTP)) {
+#endif
+ GO_WINDOW(4);
+ outw(BASE + EP_W4_MEDIA_TYPE, ENABLE_UTP);
+ GO_WINDOW(1);
+ }
+
+ outw(BASE + EP_COMMAND, RX_ENABLE);
+ outw(BASE + EP_COMMAND, TX_ENABLE);
+
+ ifp->if_flags |= IFF_RUNNING;
+ ifp->if_flags &= ~IFF_OACTIVE; /* just in case */
+ sc->tx_start_thresh = 20; /* probably a good starting point. */
+ /*
+ * Store up a bunch of mbuf's for use later. (MAX_MBS). First we
+ * free up any that we had in case we're being called from intr or
+ * somewhere else.
+ */
+ sc->last_mb = 0;
+ sc->next_mb = 0;
+ epmbuffill((caddr_t)sc, 0);
+
+ epstart(ifp);
+
+ splx(s);
+}
+
+static const char padmap[] = {0, 3, 2, 1};
+
+void
+epstart(ifp)
+ struct ifnet *ifp;
+{
+ register struct ep_softc *sc = &ep_softc[ifp->if_unit];
+ struct mbuf *m, *top;
+ int s, len, pad;
+
+ s = splimp();
+ if (sc->arpcom.ac_if.if_flags & IFF_OACTIVE) {
+ splx(s);
+ return;
+ }
+
+startagain:
+ /* Sneak a peek at the next packet */
+ m = sc->arpcom.ac_if.if_snd.ifq_head;
+ if (m == 0) {
+ splx(s);
+ return;
+ }
+#if 0
+ len = m->m_pkthdr.len;
+#else
+ for (len = 0, top = m; m; m = m->m_next)
+ len += m->m_len;
+#endif
+
+ pad = padmap[len & 3];
+
+ /*
+ * The 3c509 automatically pads short packets to minimum ethernet
+ * length, but we drop packets that are too large. Perhaps we should
+ * truncate them instead?
+ */
+ if (len + pad > ETHER_MAX_LEN) {
+ /* packet is obviously too large: toss it */
+ ++sc->arpcom.ac_if.if_oerrors;
+ IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, m);
+ m_freem(m);
+ goto readcheck;
+ }
+
+ if (inw(BASE + EP_W1_FREE_TX) < len + pad + 4) {
+ /* no room in FIFO */
+ outw(BASE + EP_COMMAND, SET_TX_AVAIL_THRESH | (len + pad + 4));
+ sc->arpcom.ac_if.if_flags |= IFF_OACTIVE;
+ splx(s);
+ return;
+ }
+ IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, m);
+ if (m == 0) { /* not really needed */
+ splx(s);
+ return;
+ }
+ outw(BASE + EP_COMMAND, SET_TX_START_THRESH |
+ (len / 4 + sc->tx_start_thresh));
+
+ outw(BASE + EP_W1_TX_PIO_WR_1, len);
+ outw(BASE + EP_W1_TX_PIO_WR_1, 0xffff); /* Second dword meaningless */
+
+ for (top = m; m != 0; m = m->m_next) {
+ if (sc->bus32bit) {
+ outsl(BASE + EP_W1_TX_PIO_WR_1, mtod(m, caddr_t),
+ m->m_len/4);
+ if (m->m_len & 3)
+ outsb(BASE + EP_W1_TX_PIO_WR_1,
+ mtod(m, caddr_t) + m->m_len/4,
+ m->m_len & 3);
+ } else {
+ outsw(BASE + EP_W1_TX_PIO_WR_1, mtod(m, caddr_t), m->m_len/2);
+ if (m->m_len & 1)
+ outb(BASE + EP_W1_TX_PIO_WR_1,
+ *(mtod(m, caddr_t) + m->m_len - 1));
+ }
+ }
+ while (pad--)
+ outb(BASE + EP_W1_TX_PIO_WR_1, 0); /* Padding */
+
+#if NBPFILTER > 0
+ if (sc->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(top, 0, sizeof(struct ether_header), ep);
+ eh = (struct ether_header *) ep;
+ ep += sizeof(struct ether_header);
+ eh->ether_type = 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(top, off, sizeof(struct trailer_header),
+ (caddr_t)&trailer_header.ether_type);
+
+ /* copy residual data */
+ resid = trailer_header.ether_residual -
+ sizeof(struct trailer_header);
+ resid = ntohs(resid);
+ m_copydata(top, off + sizeof(struct trailer_header),
+ resid, ep);
+ ep += resid;
+
+ /* copy data */
+ m_copydata(top, sizeof(struct ether_header),
+ datasize, ep);
+ ep += datasize;
+
+ /* restore original ether packet type */
+ eh->ether_type = trailer_header.ether_type;
+
+ bpf_tap(sc->bpf, ether_packet, ep - ether_packet);
+ } else
+ bpf_mtap(sc->bpf, top);
+ }
+#endif
+
+ m_freem(top);
+ ++sc->arpcom.ac_if.if_opackets;
+
+ /*
+ * Is another packet coming in? We don't want to overflow the
+ * tiny RX fifo.
+ */
+readcheck:
+ if (inw(BASE + EP_W1_RX_STATUS) & RX_BYTES_MASK) {
+ splx(s);
+ return;
+ }
+ goto startagain;
+}
+
+void
+epintr(unit)
+ int unit;
+{
+ int status, i;
+ register struct ep_softc *sc = &ep_softc[unit];
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ struct mbuf *m;
+
+ status = 0;
+checkintr:
+ status = inw(BASE + EP_STATUS) &
+ (S_TX_COMPLETE | S_TX_AVAIL | S_RX_COMPLETE | S_CARD_FAILURE);
+ if (status == 0) {
+ /* No interrupts. */
+ outw(BASE + EP_COMMAND, C_INTR_LATCH);
+ return;
+ }
+ /* important that we do this first. */
+ outw(BASE + EP_COMMAND, ACK_INTR | status);
+
+ if (status & S_TX_AVAIL) {
+ status &= ~S_TX_AVAIL;
+ inw(BASE + EP_W1_FREE_TX);
+ sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
+ epstart(&sc->arpcom.ac_if);
+ }
+ if (status & S_RX_COMPLETE) {
+ status &= ~S_RX_COMPLETE;
+ epread(sc);
+ }
+ if (status & S_CARD_FAILURE) {
+ printf("ep%d: reset (status: %x)\n", unit, status);
+ outw(BASE + EP_COMMAND, C_INTR_LATCH);
+ epinit(unit);
+ return;
+ }
+ if (status & S_TX_COMPLETE) {
+ status &= ~S_TX_COMPLETE;
+ /*
+ * We need to read TX_STATUS until we get a 0 status in
+ * order to turn off the interrupt flag.
+ */
+ while ((i = inb(BASE + EP_W1_TX_STATUS)) & TXS_COMPLETE) {
+ outw(BASE + EP_W1_TX_STATUS, 0x0);
+ if (i & (TXS_MAX_COLLISION | TXS_JABBER | TXS_UNDERRUN)) {
+ if (i & TXS_MAX_COLLISION)
+ ++sc->arpcom.ac_if.if_collisions;
+ if (i & (TXS_JABBER | TXS_UNDERRUN)) {
+ outw(BASE + EP_COMMAND, TX_RESET);
+ if (i & TXS_UNDERRUN) {
+ if (sc->tx_start_thresh < ETHER_MAX_LEN) {
+ sc->tx_start_thresh += 20;
+ outw(BASE + EP_COMMAND,
+ SET_TX_START_THRESH |
+ sc->tx_start_thresh);
+ }
+ }
+ }
+ outw(BASE + EP_COMMAND, TX_ENABLE);
+ ++sc->arpcom.ac_if.if_oerrors;
+ }
+ }
+ epstart(ifp);
+ }
+ goto checkintr;
+}
+
+void
+epread(sc)
+ register struct ep_softc *sc;
+{
+ struct ether_header *eh;
+ struct mbuf *mcur, *m, *m0, *top;
+ int totlen, lenthisone;
+ int save_totlen;
+ u_short etype;
+ int off, resid;
+ int count, spinwait;
+ int i;
+
+ totlen = inw(BASE + EP_W1_RX_STATUS);
+ off = 0;
+ top = 0;
+
+ if (totlen & ERR_RX) {
+ ++sc->arpcom.ac_if.if_ierrors;
+ goto out;
+ }
+ save_totlen = totlen &= RX_BYTES_MASK; /* Lower 11 bits = RX bytes. */
+
+ m = sc->mb[sc->next_mb];
+ sc->mb[sc->next_mb] = 0;
+
+ if (m == 0) {
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == 0)
+ goto out;
+ } else {
+ /* Convert one of our saved mbuf's */
+ sc->next_mb = (sc->next_mb + 1) % MAX_MBS;
+ m->m_data = m->m_pktdat;
+ m->m_flags = M_PKTHDR;
+ }
+
+ top = m0 = m; /* We assign top so we can "goto out" */
+#define EROUND ((sizeof(struct ether_header) + 3) & ~3)
+#define EOFF (EROUND - sizeof(struct ether_header))
+ m0->m_data += EOFF;
+ /* Read what should be the header. */
+ insw(BASE + EP_W1_RX_PIO_RD_1,
+ mtod(m0, caddr_t), sizeof(struct ether_header) / 2);
+ m->m_len = sizeof(struct ether_header);
+ totlen -= sizeof(struct ether_header);
+ /*
+ * mostly deal with trailer here. (untested)
+ * We do this in a couple of parts. First we check for a trailer, if
+ * we have one we convert the mbuf back to a regular mbuf and set the offset and
+ * subtract sizeof(struct ether_header) from the pktlen.
+ * After we've read the packet off the interface (all except for the trailer
+ * header, we then get a header mbuf, read the trailer into it, and fix up
+ * the mbuf pointer chain.
+ */
+ eh = mtod(m, struct ether_header *);
+ eh->ether_type = etype = ntohs((u_short) eh->ether_type);
+ if (etype >= ETHERTYPE_TRAIL &&
+ etype < ETHERTYPE_TRAIL + ETHERTYPE_NTRAILER) {
+ m->m_data = m->m_dat; /* Convert back to regular mbuf. */
+ m->m_flags = 0; /* This sucks but non-trailers are the norm */
+ off = (etype - ETHERTYPE_TRAIL) * 512;
+ if (off >= ETHERMTU) {
+ m_freem(m);
+ return; /* sanity */
+ }
+ totlen -= sizeof(struct ether_header); /* We don't read the trailer */
+ m->m_data += 2 * sizeof(u_short); /* Get rid of type & len */
+ }
+ while (totlen > 0) {
+ lenthisone = min(totlen, M_TRAILINGSPACE(m));
+ if (lenthisone == 0) { /* no room in this one */
+ mcur = m;
+ m = sc->mb[sc->next_mb];
+ sc->mb[sc->next_mb] = 0;
+ if (!m) {
+ MGET(m, M_DONTWAIT, MT_DATA);
+ if (m == 0)
+ goto out;
+ } else {
+ timeout(epmbuffill, (caddr_t)sc, 0);
+ sc->next_mb = (sc->next_mb + 1) % MAX_MBS;
+ }
+ if (totlen >= MINCLSIZE)
+ MCLGET(m, M_DONTWAIT);
+ m->m_len = 0;
+ mcur->m_next = m;
+ lenthisone = min(totlen, M_TRAILINGSPACE(m));
+ }
+ if (sc->bus32bit) {
+ insl(BASE + EP_W1_RX_PIO_RD_1, mtod(m, caddr_t) + m->m_len,
+ lenthisone / 4);
+ m->m_len += (lenthisone & ~3);
+ if (lenthisone & 3)
+ insb(BASE + EP_W1_RX_PIO_RD_1,
+ mtod(m, caddr_t) + m->m_len,
+ lenthisone & 3);
+ m->m_len += (lenthisone & 3);
+ } else {
+ insw(BASE + EP_W1_RX_PIO_RD_1, mtod(m, caddr_t) + m->m_len,
+ lenthisone / 2);
+ m->m_len += lenthisone;
+ if (lenthisone & 1)
+ *(mtod(m, caddr_t) + m->m_len - 1) = inb(BASE + EP_W1_RX_PIO_RD_1);
+ }
+ totlen -= lenthisone;
+ }
+ if (off) {
+ top = sc->mb[sc->next_mb];
+ sc->mb[sc->next_mb] = 0;
+ if (top == 0) {
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (top == 0) {
+ top = m0;
+ goto out;
+ }
+ } else {
+ /* Convert one of our saved mbuf's */
+ sc->next_mb = (sc->next_mb + 1) % MAX_MBS;
+ top->m_data = top->m_pktdat;
+ top->m_flags = M_PKTHDR;
+ }
+ insw(BASE + EP_W1_RX_PIO_RD_1, mtod(top, caddr_t),
+ sizeof(struct ether_header));
+ top->m_next = m0;
+ top->m_len = sizeof(struct ether_header);
+ /* XXX Accomodate for type and len from beginning of trailer */
+ top->m_pkthdr.len = save_totlen - (2 * sizeof(u_short));
+ } else {
+ top = m0;
+ top->m_pkthdr.len = save_totlen;
+ }
+
+ top->m_pkthdr.rcvif = &sc->arpcom.ac_if;
+ outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK);
+ while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS)
+ ;
+ ++sc->arpcom.ac_if.if_ipackets;
+#if NBPFILTER > 0
+ if (sc->bpf) {
+ bpf_mtap(sc->bpf, top);
+
+ /*
+ * 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.
+ */
+ if ((sc->arpcom.ac_if.if_flags & IFF_PROMISC) &&
+ (eh->ether_dhost[0] & 1) == 0 &&
+ bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr,
+ sizeof(eh->ether_dhost)) != 0 &&
+ bcmp(eh->ether_dhost, etherbroadcastaddr,
+ sizeof(eh->ether_dhost)) != 0) {
+ m_freem(top);
+ return;
+ }
+ }
+#endif
+ m_adj(top, sizeof(struct ether_header));
+ ether_input(&sc->arpcom.ac_if, eh, top);
+ return;
+
+out: outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK);
+ while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS)
+ ;
+ if (top)
+ m_freem(top);
+
+}
+
+
+/*
+ * Look familiar?
+ */
+static int
+epioctl(ifp, cmd, data)
+ register struct ifnet *ifp;
+ int cmd;
+ caddr_t data;
+{
+ register struct ifaddr *ifa = (struct ifaddr *) data;
+ struct ep_softc *sc = &ep_softc[ifp->if_unit];
+ struct ifreq *ifr = (struct ifreq *) data;
+ int s, error = 0;
+
+ switch (cmd) {
+ case SIOCSIFADDR:
+ ifp->if_flags |= IFF_UP;
+ switch (ifa->ifa_addr->sa_family) {
+#ifdef INET
+ case AF_INET:
+ epinit(ifp->if_unit); /* before arpwhohas */
+ ((struct arpcom *) ifp)->ac_ipaddr = IA_SIN(ifa)->sin_addr;
+ arpwhohas((struct arpcom *) ifp, &IA_SIN(ifa)->sin_addr);
+ break;
+#endif
+#ifdef NS
+ case AF_NS:
+ {
+ register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
+
+ if (ns_nullhost(*ina))
+ ina->x_host =
+ *(union ns_host *)(sc->arpcom.ac_enaddr);
+ else {
+ ifp->if_flags &= ~IFF_RUNNING;
+ bcopy((caddr_t) ina->x_host.c_host,
+ (caddr_t)sc->arpcom.ac_enaddr,
+ sizeof(sc->arpcom.ac_enaddr));
+ }
+ epinit(ifp->if_unit);
+ break;
+ }
+#endif
+ default:
+ epinit(ifp->if_unit);
+ break;
+ }
+ break;
+ case SIOCSIFFLAGS:
+ if ((ifp->if_flags & IFF_UP) == 0 && ifp->if_flags & IFF_RUNNING) {
+ ifp->if_flags &= ~IFF_RUNNING;
+ epstop(ifp->if_unit);
+ epmbufempty(sc);
+ break;
+ }
+ if (ifp->if_flags & IFF_UP && (ifp->if_flags & IFF_RUNNING) == 0)
+ epinit(ifp->if_unit);
+ break;
+#ifdef notdef
+ case SIOCGHWADDR:
+ bcopy((caddr_t) sc->sc_addr, (caddr_t) &ifr->ifr_data,
+ sizeof(sc->sc_addr));
+ break;
+#endif
+ default:
+ error = EINVAL;
+ }
+ return (error);
+}
+
+void
+epreset(unit)
+ int unit;
+{
+ int s = splimp();
+
+ epstop(unit);
+ epinit(unit);
+ splx(s);
+}
+
+void
+epwatchdog(unit)
+ int unit;
+{
+ struct ep_softc *sc = &ep_softc[unit];
+
+ log(LOG_ERR, "ep%d: watchdog\n", unit);
+ ++sc->arpcom.ac_if.if_oerrors;
+
+ epreset(unit);
+}
+
+void
+epstop(unit)
+ int unit;
+{
+ struct ep_softc *sc = &ep_softc[unit];
+
+ outw(BASE + EP_COMMAND, RX_DISABLE);
+ outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK);
+ while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS)
+ ;
+ outw(BASE + EP_COMMAND, TX_DISABLE);
+ outw(BASE + EP_COMMAND, STOP_TRANSCEIVER);
+ outw(BASE + EP_COMMAND, RX_RESET);
+ outw(BASE + EP_COMMAND, TX_RESET);
+ outw(BASE + EP_COMMAND, C_INTR_LATCH);
+ outw(BASE + EP_COMMAND, SET_RD_0_MASK);
+ outw(BASE + EP_COMMAND, SET_INTR_MASK);
+ outw(BASE + EP_COMMAND, SET_RX_FILTER);
+}
+
+
+/*
+ * This is adapted straight from the book. There's probably a better way.
+ */
+static int
+send_ID_sequence(port)
+ u_short port;
+{
+ char cx, al;
+
+ cx = 0x0ff;
+ al = 0x0ff;
+
+ outb(port, 0x0);
+ DELAY(1000);
+ outb(port, 0x0);
+ DELAY(1000);
+
+loop1: cx--;
+ outb(port, al);
+ if (!(al & 0x80)) {
+ al = al << 1;
+ goto loop1;
+ }
+ al = al << 1;
+ al ^= 0xcf;
+ if (cx)
+ goto loop1;
+
+ return(1);
+}
+
+
+/*
+ * We get eeprom data from the id_port given an offset into the
+ * eeprom. Basically; after the ID_sequence is sent to all of
+ * the cards; they enter the ID_CMD state where they will accept
+ * command requests. 0x80-0xbf loads the eeprom data. We then
+ * read the port 16 times and with every read; the cards check
+ * for contention (ie: if one card writes a 0 bit and another
+ * writes a 1 bit then the host sees a 0. At the end of the cycle;
+ * each card compares the data on the bus; if there is a difference
+ * then that card goes into ID_WAIT state again). In the meantime;
+ * one bit of data is returned in the AX register which is conveniently
+ * returned to us by inb(). Hence; we read 16 times getting one
+ * bit of data with each read.
+ */
+static u_short
+get_eeprom_data(id_port, offset)
+ int id_port;
+ int offset;
+{
+ int i, data = 0;
+ outb(id_port, 0x80 + offset);
+ DELAY(1000);
+ for (i = 0; i < 16; i++)
+ data = (data << 1) | (inw(id_port) & 1);
+ return (data);
+}
+
+static int
+is_eeprom_busy(is)
+ struct isa_device *is;
+{
+ int i = 0, j;
+ register struct ep_softc *sc = &ep_softc[is->id_unit];
+
+ while (i++ < 100) {
+ j = inw(BASE + EP_W0_EEPROM_COMMAND);
+ if (j & EEPROM_BUSY)
+ DELAY(100);
+ else
+ break;
+ }
+ if (i >= 100) {
+ printf("\nep%d: eeprom failed to come ready.\n", is->id_unit);
+ return (1);
+ }
+ if (j & EEPROM_TST_MODE) {
+ printf("\nep%d: 3c509 in test mode. Erase pencil mark!\n", is->id_unit);
+ return (1);
+ }
+ return (0);
+}
+
+void
+epmbuffill(sp)
+ caddr_t sp;
+{
+ struct ep_softc *sc = (struct ep_softc *)sp;
+ int s, i;
+
+ s = splimp();
+ i = sc->last_mb;
+ do {
+ if(sc->mb[i] == NULL)
+ MGET(sc->mb[i], M_DONTWAIT, MT_DATA);
+ if(sc->mb[i] == NULL)
+ break;
+ i = (i + 1) % MAX_MBS;
+ } while (i != sc->next_mb);
+ sc->last_mb = i;
+ splx(s);
+}
+
+static void
+epmbufempty(sc)
+ struct ep_softc *sc;
+{
+ int s, i;
+
+ s = splimp();
+ for (i = 0; i<MAX_MBS; i++) {
+ if (sc->mb[i]) {
+ m_freem(sc->mb[i]);
+ sc->mb[i] = NULL;
+ }
+ }
+ sc->last_mb = sc->next_mb = 0;
+ untimeout(epmbuffill, sc);
+ splx(s);
+}
+
+#endif /* NEP > 0 */
diff --git a/sys/dev/ep/if_epreg.h b/sys/dev/ep/if_epreg.h
new file mode 100644
index 0000000..f0b4cd9
--- /dev/null
+++ b/sys/dev/ep/if_epreg.h
@@ -0,0 +1,295 @@
+/*
+ * Copyright (c) 1993 Herb Peyerl (hpeyerl@novatel.ca)
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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: if_epreg.h,v 1.1 1993/12/14 04:26:47 hpeyerl Exp $
+ */
+/**************************************************************************
+ * *
+ * These define the EEPROM data structure. They are used in the probe
+ * function to verify the existance of the adapter after having sent
+ * the ID_Sequence.
+ *
+ * There are others but only the ones we use are defined here.
+ *
+ **************************************************************************/
+
+#define EEPROM_NODE_ADDR_0 0x0 /* Word */
+#define EEPROM_NODE_ADDR_1 0x1 /* Word */
+#define EEPROM_NODE_ADDR_2 0x2 /* Word */
+#define EEPROM_PROD_ID 0x3 /* 0x9[0-f]50 */
+#define EEPROM_MFG_ID 0x7 /* 0x6d50 */
+#define EEPROM_ADDR_CFG 0x8 /* Base addr */
+#define EEPROM_RESOURCE_CFG 0x9 /* IRQ. Bits 12-15 */
+
+/**************************************************************************
+ * *
+ * These are the registers for the 3Com 3c509 and their bit patterns when *
+ * applicable. They have been taken out the the "EtherLink III Parallel *
+ * Tasking EISA and ISA Technical Reference" "Beta Draft 10/30/92" manual *
+ * from 3com. *
+ * *
+ **************************************************************************/
+
+#define EP_COMMAND 0x0e /* Write. BASE+0x0e is always a command reg. */
+#define EP_STATUS 0x0e /* Read. BASE+0x0e is always status reg. */
+#define EP_WINDOW 0x0f /* Read. BASE+0x0f is always window reg. */
+/*
+ * Window 0 registers. Setup.
+ */
+ /* Write */
+#define EP_W0_EEPROM_DATA 0x0c
+#define EP_W0_EEPROM_COMMAND 0x0a
+#define EP_W0_RESOURCE_CFG 0x08
+#define EP_W0_ADDRESS_CFG 0x06
+#define EP_W0_CONFIG_CTRL 0x04
+ /* Read */
+#define EP_W0_PRODUCT_ID 0x02
+#define EP_W0_MFG_ID 0x00
+
+/*
+ * Window 1 registers. Operating Set.
+ */
+ /* Write */
+#define EP_W1_TX_PIO_WR_2 0x02
+#define EP_W1_TX_PIO_WR_1 0x00
+ /* Read */
+#define EP_W1_FREE_TX 0x0c
+#define EP_W1_TX_STATUS 0x0b /* byte */
+#define EP_W1_TIMER 0x0a /* byte */
+#define EP_W1_RX_STATUS 0x08
+#define EP_W1_RX_PIO_RD_2 0x02
+#define EP_W1_RX_PIO_RD_1 0x00
+
+/*
+ * Window 2 registers. Station Address Setup/Read
+ */
+ /* Read/Write */
+#define EP_W2_ADDR_5 0x05
+#define EP_W2_ADDR_4 0x04
+#define EP_W2_ADDR_3 0x03
+#define EP_W2_ADDR_2 0x02
+#define EP_W2_ADDR_1 0x01
+#define EP_W2_ADDR_0 0x00
+
+/*
+ * Window 3 registers. FIFO Management.
+ */
+ /* Read */
+#define EP_W3_FREE_TX 0x0c
+#define EP_W3_FREE_RX 0x0a
+
+/*
+ * Window 4 registers. Diagnostics.
+ */
+ /* Read/Write */
+#define EP_W4_MEDIA_TYPE 0x0a
+#define EP_W4_CTRLR_STATUS 0x08
+#define EP_W4_NET_DIAG 0x06
+#define EP_W4_FIFO_DIAG 0x04
+#define EP_W4_HOST_DIAG 0x02
+#define EP_W4_TX_DIAG 0x00
+
+/*
+ * Window 5 Registers. Results and Internal status.
+ */
+ /* Read */
+#define EP_W5_READ_0_MASK 0x0c
+#define EP_W5_INTR_MASK 0x0a
+#define EP_W5_RX_FILTER 0x08
+#define EP_W5_RX_EARLY_THRESH 0x06
+#define EP_W5_TX_AVAIL_THRESH 0x02
+#define EP_W5_TX_START_THRESH 0x00
+
+/*
+ * Window 6 registers. Statistics.
+ */
+ /* Read/Write */
+#define TX_TOTAL_OK 0x0c
+#define RX_TOTAL_OK 0x0a
+#define TX_DEFERRALS 0x08
+#define RX_FRAMES_OK 0x07
+#define TX_FRAMES_OK 0x06
+#define RX_OVERRUNS 0x05
+#define TX_COLLISIONS 0x04
+#define TX_AFTER_1_COLLISION 0x03
+#define TX_AFTER_X_COLLISIONS 0x02
+#define TX_NO_SQE 0x01
+#define TX_CD_LOST 0x00
+
+/****************************************
+ *
+ * Register definitions.
+ *
+ ****************************************/
+
+/*
+ * Command register. All windows.
+ *
+ * 16 bit register.
+ * 15-11: 5-bit code for command to be executed.
+ * 10-0: 11-bit arg if any. For commands with no args;
+ * this can be set to anything.
+ */
+#define GLOBAL_RESET (u_short) 0x0000 /* Wait at least 1ms after issuing */
+#define WINDOW_SELECT (u_short) (0x1<<11)
+#define START_TRANSCEIVER (u_short) (0x2<<11) /* Read ADDR_CFG reg to determine
+ whether this is needed. If so;
+ wait 800 uSec before using trans-
+ ceiver. */
+#define RX_DISABLE (u_short) (0x3<<11) /* state disabled on power-up */
+#define RX_ENABLE (u_short) (0x4<<11)
+#define RX_RESET (u_short) (0x5<<11)
+#define RX_DISCARD_TOP_PACK (u_short) (0x8<<11)
+#define TX_ENABLE (u_short) (0x9<<11)
+#define TX_DISABLE (u_short) (0xa<<11)
+#define TX_RESET (u_short) (0xb<<11)
+#define REQ_INTR (u_short) (0xc<<11)
+ /*
+ * The following C_* acknowledge the various interrupts.
+ * Some of them don't do anything. See the manual.
+ */
+#define ACK_INTR (u_short) (0x6800)
+# define C_INTR_LATCH (u_short) (ACK_INTR|0x1)
+# define C_CARD_FAILURE (u_short) (ACK_INTR|0x2)
+# define C_TX_COMPLETE (u_short) (ACK_INTR|0x4)
+# define C_TX_AVAIL (u_short) (ACK_INTR|0x8)
+# define C_RX_COMPLETE (u_short) (ACK_INTR|0x10)
+# define C_RX_EARLY (u_short) (ACK_INTR|0x20)
+# define C_INT_RQD (u_short) (ACK_INTR|0x40)
+# define C_UPD_STATS (u_short) (ACK_INTR|0x80)
+#define SET_INTR_MASK (u_short) (0xe<<11)
+#define SET_RD_0_MASK (u_short) (0xf<<11)
+#define SET_RX_FILTER (u_short) (0x10<<11)
+# define FIL_INDIVIDUAL (u_short) (0x1)
+# define FIL_GROUP (u_short) (0x2)
+# define FIL_BRDCST (u_short) (0x4)
+# define FIL_ALL (u_short) (0x8)
+#define SET_RX_EARLY_THRESH (u_short) (0x11<<11)
+#define SET_TX_AVAIL_THRESH (u_short) (0x12<<11)
+#define SET_TX_START_THRESH (u_short) (0x13<<11)
+#define STATS_ENABLE (u_short) (0x15<<11)
+#define STATS_DISABLE (u_short) (0x16<<11)
+#define STOP_TRANSCEIVER (u_short) (0x17<<11)
+
+/*
+ * Status register. All windows.
+ *
+ * 15-13: Window number(0-7).
+ * 12: Command_in_progress.
+ * 11: reserved.
+ * 10: reserved.
+ * 9: reserved.
+ * 8: reserved.
+ * 7: Update Statistics.
+ * 6: Interrupt Requested.
+ * 5: RX Early.
+ * 4: RX Complete.
+ * 3: TX Available.
+ * 2: TX Complete.
+ * 1: Adapter Failure.
+ * 0: Interrupt Latch.
+ */
+#define S_INTR_LATCH (u_short) (0x1)
+#define S_CARD_FAILURE (u_short) (0x2)
+#define S_TX_COMPLETE (u_short) (0x4)
+#define S_TX_AVAIL (u_short) (0x8)
+#define S_RX_COMPLETE (u_short) (0x10)
+#define S_RX_EARLY (u_short) (0x20)
+#define S_INT_RQD (u_short) (0x40)
+#define S_UPD_STATS (u_short) (0x80)
+#define S_COMMAND_IN_PROGRESS (u_short) (0x1000)
+
+/*
+ * FIFO Registers. RX Status.
+ *
+ * 15: Incomplete or FIFO empty.
+ * 14: 1: Error in RX Packet 0: Incomplete or no error.
+ * 13-11: Type of error.
+ * 1000 = Overrun.
+ * 1011 = Run Packet Error.
+ * 1100 = Alignment Error.
+ * 1101 = CRC Error.
+ * 1001 = Oversize Packet Error (>1514 bytes)
+ * 0010 = Dribble Bits.
+ * (all other error codes, no errors.)
+ *
+ * 10-0: RX Bytes (0-1514)
+ */
+#define ERR_INCOMPLETE (u_short) (0x8000)
+#define ERR_RX (u_short) (0x4000)
+#define ERR_RX_PACKET (u_short) (0x2000)
+#define ERR_OVERRUN (u_short) (0x1000)
+#define ERR_RUNT (u_short) (0x1300)
+#define ERR_ALIGNMENT (u_short) (0x1400)
+#define ERR_CRC (u_short) (0x1500)
+#define ERR_OVERSIZE (u_short) (0x1100)
+#define ERR_DRIBBLE (u_short) (0x200)
+
+/*
+ * TX Status
+ *
+ * Reports the transmit status of a completed transmission. Writing this
+ * register pops the transmit completion stack.
+ *
+ * Window 1/Port 0x0b.
+ *
+ * 7: Complete
+ * 6: Interrupt on successful transmission requested.
+ * 5: Jabber Error (TP Only, TX Reset required. )
+ * 4: Underrun (TX Reset required. )
+ * 3: Maximum Collisions.
+ * 2: TX Status Overflow.
+ * 1-0: Undefined.
+ *
+ */
+#define TXS_COMPLETE 0x80
+#define TXS_INTR_REQ 0x40
+#define TXS_JABBER 0x20
+#define TXS_UNDERRUN 0x10
+#define TXS_MAX_COLLISION 0x8
+#define TXS_STATUS_OVERFLOW 0x4
+
+/*
+ * Misc defines for various things.
+ */
+#define TAG_ADAPTER_0 0xd0
+#define ACTIVATE_ADAPTER_TO_CONFIG 0xff
+#define ENABLE_DRQ_IRQ 0x0001
+#define MFG_ID 0x6d50
+#define PROD_ID 0x9150
+#define BASE sc->ep_io_addr
+#define GO_WINDOW(x) outw(BASE+EP_COMMAND, WINDOW_SELECT|x)
+#define AUI 0x1
+#define BNC 0x2
+#define UTP 0x4
+#define IS_AUI (1<<13)
+#define IS_BNC (1<<12)
+#define IS_UTP (1<<9)
+#define EEPROM_BUSY (1<<15)
+#define EEPROM_TST_MODE (1<<14)
+#define READ_EEPROM (1<<7)
+#define ETHER_ADDR_LEN 6
+#define ETHER_MAX 1536
+#define ENABLE_UTP 0xc0
+#define DISABLE_UTP 0x0
+#define RX_BYTES_MASK (u_short) (0x07ff)
diff --git a/sys/dev/fdc/fdc.c b/sys/dev/fdc/fdc.c
new file mode 100644
index 0000000..259d451
--- /dev/null
+++ b/sys/dev/fdc/fdc.c
@@ -0,0 +1,1255 @@
+/*#define DEBUG 1*/
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Don Ahn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)fd.c 7.4 (Berkeley) 5/25/91
+ * $Id: fd.c,v 1.24 1994/03/08 16:25:29 nate Exp $
+ *
+ */
+
+#include "ft.h"
+#if NFT < 1
+#undef NFDC
+#endif
+#include "fd.h"
+
+#if NFDC > 0
+
+#include <sys/param.h>
+#include <sys/dkbad.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/conf.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <machine/ioctl_fd.h>
+#include <sys/disklabel.h>
+#include <sys/buf.h>
+#include <sys/uio.h>
+#include <sys/malloc.h>
+#include <sys/syslog.h>
+#include "i386/isa/isa.h"
+#include "i386/isa/isa_device.h"
+#include "i386/isa/fdreg.h"
+#include "i386/isa/fdc.h"
+#include "i386/isa/icu.h"
+#include "i386/isa/rtc.h"
+
+#if NFT > 0
+extern int ftopen(), ftintr(), ftattach(), ftclose(), ftioctl();
+#endif
+
+#define b_cylin b_resid
+#define FDBLK 512
+
+/* misuse a flag to identify format operation */
+#define B_FORMAT B_XXX
+
+#define NUMTYPES 14
+#define NUMDENS (NUMTYPES - 6)
+
+/* This defines (-1) must match index for fd_types */
+#define F_TAPE_TYPE 0x020 /* bit for fd_types to indicate tape */
+#define NO_TYPE 0 /* must match NO_TYPE in ft.c */
+#define FD_1720 1
+#define FD_1480 2
+#define FD_1440 3
+#define FD_1200 4
+#define FD_820 5
+#define FD_800 6
+#define FD_720 7
+#define FD_360 8
+
+#define FD_1480in5_25 9
+#define FD_1440in5_25 10
+#define FD_820in5_25 11
+#define FD_800in5_25 12
+#define FD_720in5_25 13
+#define FD_360in5_25 14
+
+
+struct fd_type fd_types[NUMTYPES] =
+{
+{ 21,2,0xFF,0x04,82,3444,1,FDC_500KBPS,2,0x0C,2 }, /* 1.72M in HD 3.5in */
+{ 18,2,0xFF,0x1B,82,2952,1,FDC_500KBPS,2,0x6C,1 }, /* 1.48M in HD 3.5in */
+{ 18,2,0xFF,0x1B,80,2880,1,FDC_500KBPS,2,0x6C,1 }, /* 1.44M in HD 3.5in */
+{ 15,2,0xFF,0x1B,80,2400,1,FDC_500KBPS,2,0x54,1 }, /* 1.2M in HD 5.25/3.5 */
+{ 10,2,0xFF,0x10,82,1640,1,FDC_250KBPS,2,0x2E,1 }, /* 820K in HD 3.5in */
+{ 10,2,0xFF,0x10,80,1600,1,FDC_250KBPS,2,0x2E,1 }, /* 800K in HD 3.5in */
+{ 9,2,0xFF,0x20,80,1440,1,FDC_250KBPS,2,0x50,1 }, /* 720K in HD 3.5in */
+{ 9,2,0xFF,0x2A,40, 720,1,FDC_250KBPS,2,0x50,1 }, /* 360K in DD 5.25in */
+
+{ 18,2,0xFF,0x02,82,2952,1,FDC_500KBPS,2,0x02,2 }, /* 1.48M in HD 5.25in */
+{ 18,2,0xFF,0x02,80,2880,1,FDC_500KBPS,2,0x02,2 }, /* 1.44M in HD 5.25in */
+{ 10,2,0xFF,0x10,82,1640,1,FDC_300KBPS,2,0x2E,1 }, /* 820K in HD 5.25in */
+{ 10,2,0xFF,0x10,80,1600,1,FDC_300KBPS,2,0x2E,1 }, /* 800K in HD 5.25in */
+{ 9,2,0xFF,0x20,80,1440,1,FDC_300KBPS,2,0x50,1 }, /* 720K in HD 5.25in */
+{ 9,2,0xFF,0x23,40, 720,2,FDC_300KBPS,2,0x50,1 }, /* 360K in HD 5.25in */
+};
+
+#define DRVS_PER_CTLR 2 /* 2 floppies */
+/***********************************************************************\
+* Per controller structure. *
+\***********************************************************************/
+struct fdc_data fdc_data[NFDC];
+
+/***********************************************************************\
+* Per drive structure. *
+* N per controller (DRVS_PER_CTLR) *
+\***********************************************************************/
+struct fd_data {
+ struct fdc_data *fdc; /* pointer to controller structure */
+ int fdsu; /* this units number on this controller */
+ int type; /* Drive type (HD, DD */
+ struct fd_type *ft; /* pointer to the type descriptor */
+ int flags;
+#define FD_OPEN 0x01 /* it's open */
+#define FD_ACTIVE 0x02 /* it's active */
+#define FD_MOTOR 0x04 /* motor should be on */
+#define FD_MOTOR_WAIT 0x08 /* motor coming up */
+ int skip;
+ int hddrv;
+ int track; /* where we think the head is */
+} fd_data[NFD];
+
+/***********************************************************************\
+* Throughout this file the following conventions will be used: *
+* fd is a pointer to the fd_data struct for the drive in question *
+* fdc is a pointer to the fdc_data struct for the controller *
+* fdu is the floppy drive unit number *
+* fdcu is the floppy controller unit number *
+* fdsu is the floppy drive unit number on that controller. (sub-unit) *
+\***********************************************************************/
+
+#define id_physid id_scsiid /* this biotab field doubles as a field */
+ /* for the physical unit number on the controller */
+
+static int retrier(fdcu_t);
+
+#define DEVIDLE 0
+#define FINDWORK 1
+#define DOSEEK 2
+#define SEEKCOMPLETE 3
+#define IOCOMPLETE 4
+#define RECALCOMPLETE 5
+#define STARTRECAL 6
+#define RESETCTLR 7
+#define SEEKWAIT 8
+#define RECALWAIT 9
+#define MOTORWAIT 10
+#define IOTIMEDOUT 11
+
+#ifdef DEBUG
+char *fdstates[] =
+{
+"DEVIDLE",
+"FINDWORK",
+"DOSEEK",
+"SEEKCOMPLETE",
+"IOCOMPLETE",
+"RECALCOMPLETE",
+"STARTRECAL",
+"RESETCTLR",
+"SEEKWAIT",
+"RECALWAIT",
+"MOTORWAIT",
+"IOTIMEDOUT"
+};
+
+
+int fd_debug = 1;
+#define TRACE0(arg) if(fd_debug) printf(arg)
+#define TRACE1(arg1,arg2) if(fd_debug) printf(arg1,arg2)
+#else /* DEBUG */
+#define TRACE0(arg)
+#define TRACE1(arg1,arg2)
+#endif /* DEBUG */
+
+static void fdstart(fdcu_t);
+void fdintr(fdcu_t);
+static void fd_turnoff(caddr_t);
+
+/****************************************************************************/
+/* autoconfiguration stuff */
+/****************************************************************************/
+static int fdprobe(struct isa_device *);
+static int fdattach(struct isa_device *);
+
+struct isa_driver fdcdriver = {
+ fdprobe, fdattach, "fdc",
+};
+
+/*
+ * probe for existance of controller
+ */
+int
+fdprobe(dev)
+ struct isa_device *dev;
+{
+ fdcu_t fdcu = dev->id_unit;
+ if(fdc_data[fdcu].flags & FDC_ATTACHED)
+ {
+ printf("fdc: same unit (%d) used multiple times\n",fdcu);
+ return 0;
+ }
+
+ fdc_data[fdcu].baseport = dev->id_iobase;
+
+ /* First - lets reset the floppy controller */
+
+ outb(dev->id_iobase+fdout,0);
+ DELAY(100);
+ outb(dev->id_iobase+fdout,FDO_FRST);
+
+ /* see if it can handle a command */
+ if (out_fdc(fdcu,NE7CMD_SPECIFY) < 0)
+ {
+ return(0);
+ }
+ out_fdc(fdcu,0xDF);
+ out_fdc(fdcu,2);
+ return (IO_FDCSIZE);
+}
+
+/*
+ * wire controller into system, look for floppy units
+ */
+int
+fdattach(dev)
+ struct isa_device *dev;
+{
+ unsigned fdt,st0, cyl;
+ int hdr;
+ fdu_t fdu;
+ fdcu_t fdcu = dev->id_unit;
+ fdc_p fdc = fdc_data + fdcu;
+ fd_p fd;
+ int fdsu;
+ struct isa_device *fdup;
+
+ fdc->fdcu = fdcu;
+ fdc->flags |= FDC_ATTACHED;
+ fdc->dmachan = dev->id_drq;
+ fdc->state = DEVIDLE;
+ hdr = 0;
+ printf("fdc%d:", fdcu);
+
+ /* check for each floppy drive */
+ for (fdup = isa_biotab_fdc; fdup->id_driver != 0; fdup++) {
+ if (fdup->id_iobase != dev->id_iobase)
+ continue;
+ fdu = fdup->id_unit;
+ fd = &fd_data[fdu];
+ if (fdu >= (NFD+NFT))
+ continue;
+ fdsu = fdup->id_physid;
+ /* look up what bios thinks we have */
+ switch (fdu) {
+ case 0: fdt = (rtcin(RTC_FDISKETTE) & 0xf0);
+ break;
+ case 1: fdt = ((rtcin(RTC_FDISKETTE) << 4) & 0xf0);
+ break;
+ default: fdt = RTCFDT_NONE;
+ break;
+ }
+ /* is there a unit? */
+ if ((fdt == RTCFDT_NONE)
+#if NFT > 0
+ || (fdsu >= DRVS_PER_CTLR)) {
+#else
+ ) {
+ fd->type = NO_TYPE;
+#endif
+#if NFT > 0
+ /* If BIOS says no floppy, or > 2nd device */
+ /* Probe for and attach a floppy tape. */
+ if (ftattach(dev, fdup))
+ continue;
+ if (fdsu < DRVS_PER_CTLR)
+ fd->type = NO_TYPE;
+#endif
+ continue;
+ }
+
+#ifdef notyet
+ /* select it */
+ fd_turnon1(fdu);
+ spinwait(1000); /* 1 sec */
+ out_fdc(fdcu,NE7CMD_RECAL); /* Recalibrate Function */
+ out_fdc(fdcu,fdsu);
+ spinwait(1000); /* 1 sec */
+
+ /* anything responding */
+ out_fdc(fdcu,NE7CMD_SENSEI);
+ st0 = in_fdc(fdcu);
+ cyl = in_fdc(fdcu);
+ if (st0 & 0xd0)
+ continue;
+
+#endif
+ fd->track = -2;
+ fd->fdc = fdc;
+ fd->fdsu = fdsu;
+ printf(" [%d: fd%d: ", fdsu, fdu);
+
+ switch (fdt) {
+ case RTCFDT_12M:
+ printf("1.2MB 5.25in]");
+ fd->type = FD_1200;
+ break;
+ case RTCFDT_144M:
+ printf("1.44MB 3.5in]");
+ fd->type = FD_1440;
+ break;
+ case RTCFDT_360K:
+ printf("360KB 5.25in]");
+ fd->type = FD_360;
+ break;
+ case RTCFDT_720K:
+ printf("720KB 3.5in]");
+ fd->type = FD_720;
+ break;
+ default:
+ printf("unknown]");
+ fd->type = NO_TYPE;
+ break;
+ }
+
+ fd_turnoff((caddr_t)fdu);
+ hdr = 1;
+ }
+ printf("\n");
+
+ /* Set transfer to 500kbps */
+ outb(fdc->baseport+fdctl,0); /*XXX*/
+ return 1;
+}
+
+int
+fdsize(dev)
+ dev_t dev;
+{
+ return(0);
+}
+
+/****************************************************************************/
+/* fdstrategy */
+/****************************************************************************/
+void fdstrategy(struct buf *bp)
+{
+ register struct buf *dp,*dp0,*dp1;
+ long nblocks,blknum;
+ int s;
+ fdcu_t fdcu;
+ fdu_t fdu;
+ fdc_p fdc;
+ fd_p fd;
+
+ fdu = FDUNIT(minor(bp->b_dev));
+ fd = &fd_data[fdu];
+ fdc = fd->fdc;
+ fdcu = fdc->fdcu;
+
+#if NFT > 0
+ /* check for controller already busy with tape */
+ if (fdc->flags & FDC_TAPE_BUSY) {
+ bp->b_error = EBUSY;
+ bp->b_flags |= B_ERROR;
+ return;
+ }
+#endif
+ if ((fdu >= NFD) || (bp->b_blkno < 0)) {
+ printf("fdstrat: fdu = %d, blkno = %d, bcount = %d\n",
+ fdu, bp->b_blkno, bp->b_bcount);
+ pg("fd:error in fdstrategy");
+ bp->b_error = EINVAL;
+ bp->b_flags |= B_ERROR;
+ goto bad;
+ }
+ /*
+ * Set up block calculations.
+ */
+ blknum = (unsigned long) bp->b_blkno * DEV_BSIZE/FDBLK;
+ nblocks = fd->ft->size;
+ if (blknum + (bp->b_bcount / FDBLK) > nblocks) {
+ if (blknum == nblocks) {
+ bp->b_resid = bp->b_bcount;
+ } else {
+ bp->b_error = ENOSPC;
+ bp->b_flags |= B_ERROR;
+ }
+ goto bad;
+ }
+ bp->b_cylin = blknum / (fd->ft->sectrac * fd->ft->heads);
+ bp->b_pblkno = bp->b_blkno;
+ dp = &(fdc->head);
+ s = splbio();
+ disksort(dp, bp);
+ untimeout((timeout_func_t)fd_turnoff, (caddr_t)fdu); /* a good idea */
+ fdstart(fdcu);
+ splx(s);
+ return;
+
+bad:
+ biodone(bp);
+ return;
+}
+
+/****************************************************************************/
+/* motor control stuff */
+/* remember to not deselect the drive we're working on */
+/****************************************************************************/
+void
+set_motor(fdcu, fdu, reset)
+ fdcu_t fdcu;
+ fdu_t fdu;
+ int reset;
+{
+ int m0,m1;
+ int selunit;
+ fd_p fd;
+ if(fd = fdc_data[fdcu].fd)/* yes an assign! */
+ {
+ selunit = fd->fdsu;
+ }
+ else
+ {
+ selunit = 0;
+ }
+ m0 = fd_data[fdcu * DRVS_PER_CTLR + 0].flags & FD_MOTOR;
+ m1 = fd_data[fdcu * DRVS_PER_CTLR + 1].flags & FD_MOTOR;
+ outb(fdc_data[fdcu].baseport+fdout,
+ selunit
+ | (reset ? 0 : (FDO_FRST|FDO_FDMAEN))
+ | (m0 ? FDO_MOEN0 : 0)
+ | (m1 ? FDO_MOEN1 : 0));
+ TRACE1("[0x%x->fdout]",(
+ selunit
+ | (reset ? 0 : (FDO_FRST|FDO_FDMAEN))
+ | (m0 ? FDO_MOEN0 : 0)
+ | (m1 ? FDO_MOEN1 : 0)));
+}
+
+static void
+fd_turnoff(caddr_t arg1)
+{
+ fdu_t fdu = (fdu_t)arg1;
+ int s;
+
+ fd_p fd = fd_data + fdu;
+ s = splbio();
+ fd->flags &= ~FD_MOTOR;
+ set_motor(fd->fdc->fdcu,fd->fdsu,0);
+ splx(s);
+}
+
+void
+fd_motor_on(caddr_t arg1)
+{
+ fdu_t fdu = (fdu_t)arg1;
+ int s;
+
+ fd_p fd = fd_data + fdu;
+ s = splbio();
+ fd->flags &= ~FD_MOTOR_WAIT;
+ if((fd->fdc->fd == fd) && (fd->fdc->state == MOTORWAIT))
+ {
+ fdintr(fd->fdc->fdcu);
+ }
+ splx(s);
+}
+
+static void fd_turnon1(fdu_t);
+
+void
+fd_turnon(fdu)
+ fdu_t fdu;
+{
+ fd_p fd = fd_data + fdu;
+ if(!(fd->flags & FD_MOTOR))
+ {
+ fd_turnon1(fdu);
+ fd->flags |= FD_MOTOR_WAIT;
+ timeout((timeout_func_t)fd_motor_on, (caddr_t)fdu, hz); /* in 1 sec its ok */
+ }
+}
+
+static void
+fd_turnon1(fdu_t fdu)
+{
+ fd_p fd = fd_data + fdu;
+ fd->flags |= FD_MOTOR;
+ set_motor(fd->fdc->fdcu,fd->fdsu,0);
+}
+
+/****************************************************************************/
+/* fdc in/out */
+/****************************************************************************/
+int
+in_fdc(fdcu)
+ fdcu_t fdcu;
+{
+ int baseport = fdc_data[fdcu].baseport;
+ int i, j = 100000;
+ while ((i = inb(baseport+fdsts) & (NE7_DIO|NE7_RQM))
+ != (NE7_DIO|NE7_RQM) && j-- > 0)
+ if (i == NE7_RQM) return -1;
+ if (j <= 0)
+ return(-1);
+#ifdef DEBUG
+ i = inb(baseport+fddata);
+ TRACE1("[fddata->0x%x]",(unsigned char)i);
+ return(i);
+#else
+ return inb(baseport+fddata);
+#endif
+}
+
+int
+out_fdc(fdcu, x)
+ fdcu_t fdcu;
+ int x;
+{
+ int baseport = fdc_data[fdcu].baseport;
+ int i;
+
+ /* Check that the direction bit is set */
+ i = 100000;
+ while ((inb(baseport+fdsts) & NE7_DIO) && i-- > 0);
+ if (i <= 0) return (-1); /* Floppy timed out */
+
+ /* Check that the floppy controller is ready for a command */
+ i = 100000;
+ while ((inb(baseport+fdsts) & NE7_RQM) == 0 && i-- > 0);
+ if (i <= 0) return (-1); /* Floppy timed out */
+
+ /* Send the command and return */
+ outb(baseport+fddata,x);
+ TRACE1("[0x%x->fddata]",x);
+ return (0);
+}
+
+/****************************************************************************/
+/* fdopen/fdclose */
+/****************************************************************************/
+int
+Fdopen(dev, flags)
+ dev_t dev;
+ int flags;
+{
+ fdu_t fdu = FDUNIT(minor(dev));
+ int type = FDTYPE(minor(dev));
+ fdc_p fdc;
+
+#if NFT > 0
+ /* check for a tape open */
+ if (type & F_TAPE_TYPE)
+ return(ftopen(dev, flags));
+#endif
+ /* check bounds */
+ if (fdu >= NFD)
+ return(ENXIO);
+ fdc = fd_data[fdu].fdc;
+ if ((fdc == NULL) || (fd_data[fdu].type == NO_TYPE))
+ return(ENXIO);
+ if (type > NUMDENS)
+ return(ENXIO);
+ if (type == 0)
+ type = fd_data[fdu].type;
+ else {
+ if (type != fd_data[fdu].type) {
+ switch (fd_data[fdu].type) {
+ case FD_360:
+ return(ENXIO);
+ case FD_720:
+ if ( type != FD_820
+ && type != FD_800
+ )
+ return(ENXIO);
+ break;
+ case FD_1200:
+ switch (type) {
+ case FD_1480:
+ type = FD_1480in5_25;
+ break;
+ case FD_1440:
+ type = FD_1440in5_25;
+ break;
+ case FD_820:
+ type = FD_820in5_25;
+ break;
+ case FD_800:
+ type = FD_800in5_25;
+ break;
+ case FD_720:
+ type = FD_720in5_25;
+ break;
+ case FD_360:
+ type = FD_360in5_25;
+ break;
+ default:
+ return(ENXIO);
+ }
+ break;
+ case FD_1440:
+ if ( type != FD_1720
+ && type != FD_1480
+ && type != FD_1200
+ && type != FD_820
+ && type != FD_800
+ && type != FD_720
+ )
+ return(ENXIO);
+ break;
+ }
+ }
+ }
+ fd_data[fdu].ft = fd_types + type - 1;
+ fd_data[fdu].flags |= FD_OPEN;
+
+ return 0;
+}
+
+int
+fdclose(dev, flags)
+ dev_t dev;
+ int flags;
+{
+ fdu_t fdu = FDUNIT(minor(dev));
+ int type = FDTYPE(minor(dev));
+
+#if NFT > 0
+ if (type & F_TAPE_TYPE)
+ return ftclose(0);
+#endif
+ fd_data[fdu].flags &= ~FD_OPEN;
+ return(0);
+}
+
+
+/***************************************************************\
+* fdstart *
+* We have just queued something.. if the controller is not busy *
+* then simulate the case where it has just finished a command *
+* So that it (the interrupt routine) looks on the queue for more*
+* work to do and picks up what we just added. *
+* If the controller is already busy, we need do nothing, as it *
+* will pick up our work when the present work completes *
+\***************************************************************/
+static void
+fdstart(fdcu)
+ fdcu_t fdcu;
+{
+ register struct buf *dp,*bp;
+ int s;
+ fdu_t fdu;
+
+ s = splbio();
+ if(fdc_data[fdcu].state == DEVIDLE)
+ {
+ fdintr(fdcu);
+ }
+ splx(s);
+}
+
+static void
+fd_timeout(caddr_t arg1)
+{
+ fdcu_t fdcu = (fdcu_t)arg1;
+ fdu_t fdu = fdc_data[fdcu].fdu;
+ int st0, st3, cyl;
+ struct buf *dp,*bp;
+ int s;
+
+ dp = &fdc_data[fdcu].head;
+ s = splbio();
+ bp = dp->b_actf;
+
+ out_fdc(fdcu,NE7CMD_SENSED);
+ out_fdc(fdcu,fd_data[fdu].hddrv);
+ st3 = in_fdc(fdcu);
+
+ out_fdc(fdcu,NE7CMD_SENSEI);
+ st0 = in_fdc(fdcu);
+ cyl = in_fdc(fdcu);
+ printf("fd%d: Operation timeout ST0 %b cyl %d ST3 %b\n",
+ fdu,
+ st0,
+ NE7_ST0BITS,
+ cyl,
+ st3,
+ NE7_ST3BITS);
+
+ if (bp)
+ {
+ retrier(fdcu);
+ fdc_data[fdcu].status[0] = 0xc0;
+ fdc_data[fdcu].state = IOTIMEDOUT;
+ if( fdc_data[fdcu].retry < 6)
+ fdc_data[fdcu].retry = 6;
+ }
+ else
+ {
+ fdc_data[fdcu].fd = (fd_p) 0;
+ fdc_data[fdcu].fdu = -1;
+ fdc_data[fdcu].state = DEVIDLE;
+ }
+ fdintr(fdcu);
+ splx(s);
+}
+
+/* just ensure it has the right spl */
+static void
+fd_pseudointr(caddr_t arg1, int arg2)
+{
+ fdcu_t fdcu = (fdcu_t)arg1;
+ int s;
+ s = splbio();
+ fdintr(fdcu);
+ splx(s);
+}
+
+/***********************************************************************\
+* fdintr *
+* keep calling the state machine until it returns a 0 *
+* ALWAYS called at SPLBIO *
+\***********************************************************************/
+void
+fdintr(fdcu_t fdcu)
+{
+ fdc_p fdc = fdc_data + fdcu;
+#if NFT > 0
+ fdu_t fdu = fdc->fdu;
+
+ if (fdc->flags & FDC_TAPE_BUSY)
+ (ftintr(fdu));
+ else
+#endif
+ while(fdstate(fdcu, fdc))
+ ;
+}
+
+/***********************************************************************\
+* The controller state machine. *
+* if it returns a non zero value, it should be called again immediatly *
+\***********************************************************************/
+int
+fdstate(fdcu, fdc)
+ fdcu_t fdcu;
+ fdc_p fdc;
+{
+ int read, format, head, trac, sec = 0, i = 0, s, sectrac, cyl, st0;
+ unsigned long blknum;
+ fdu_t fdu = fdc->fdu;
+ fd_p fd;
+ register struct buf *dp,*bp;
+ struct fd_formb *finfo = NULL;
+
+ dp = &(fdc->head);
+ bp = dp->b_actf;
+ if(!bp)
+ {
+ /***********************************************\
+ * nothing left for this controller to do *
+ * Force into the IDLE state, *
+ \***********************************************/
+ fdc->state = DEVIDLE;
+ if(fdc->fd)
+ {
+ printf("unexpected valid fd pointer (fdu = %d)\n"
+ ,fdc->fdu);
+ fdc->fd = (fd_p) 0;
+ fdc->fdu = -1;
+ }
+ TRACE1("[fdc%d IDLE]",fdcu);
+ return(0);
+ }
+ fdu = FDUNIT(minor(bp->b_dev));
+ fd = fd_data + fdu;
+ if (fdc->fd && (fd != fdc->fd))
+ {
+ printf("confused fd pointers\n");
+ }
+ read = bp->b_flags & B_READ;
+ format = bp->b_flags & B_FORMAT;
+ if(format)
+ finfo = (struct fd_formb *)bp->b_un.b_addr;
+ TRACE1("fd%d",fdu);
+ TRACE1("[%s]",fdstates[fdc->state]);
+ TRACE1("(0x%x)",fd->flags);
+ untimeout((timeout_func_t)fd_turnoff, (caddr_t)fdu);
+ timeout((timeout_func_t)fd_turnoff, (caddr_t)fdu, 4 * hz);
+ switch (fdc->state)
+ {
+ case DEVIDLE:
+ case FINDWORK: /* we have found new work */
+ fdc->retry = 0;
+ fd->skip = 0;
+ fdc->fd = fd;
+ fdc->fdu = fdu;
+ outb(fdc->baseport+fdctl, fd->ft->trans);
+ /*******************************************************\
+ * If the next drive has a motor startup pending, then *
+ * it will start up in it's own good time *
+ \*******************************************************/
+ if(fd->flags & FD_MOTOR_WAIT)
+ {
+ fdc->state = MOTORWAIT;
+ return(0); /* come back later */
+ }
+ /*******************************************************\
+ * Maybe if it's not starting, it SHOULD be starting *
+ \*******************************************************/
+ if (!(fd->flags & FD_MOTOR))
+ {
+ fdc->state = MOTORWAIT;
+ fd_turnon(fdu);
+ return(0);
+ }
+ else /* at least make sure we are selected */
+ {
+ set_motor(fdcu,fd->fdsu,0);
+ }
+ fdc->state = DOSEEK;
+ break;
+ case DOSEEK:
+ if (bp->b_cylin == fd->track)
+ {
+ fdc->state = SEEKCOMPLETE;
+ break;
+ }
+ out_fdc(fdcu,NE7CMD_SEEK); /* Seek function */
+ out_fdc(fdcu,fd->fdsu); /* Drive number */
+ out_fdc(fdcu,bp->b_cylin * fd->ft->steptrac);
+ fd->track = -2;
+ fdc->state = SEEKWAIT;
+ timeout((timeout_func_t)fd_timeout, (caddr_t)fdcu, 2 * hz);
+ return(0); /* will return later */
+ case SEEKWAIT:
+ untimeout((timeout_func_t)fd_timeout, (caddr_t)fdcu);
+ /* allow heads to settle */
+ timeout((timeout_func_t)fd_pseudointr, (caddr_t)fdcu, hz / 50);
+ fdc->state = SEEKCOMPLETE;
+ return(0); /* will return later */
+ break;
+
+ case SEEKCOMPLETE : /* SEEK DONE, START DMA */
+ /* Make sure seek really happened*/
+ if(fd->track == -2)
+ {
+ int descyl = bp->b_cylin * fd->ft->steptrac;
+ out_fdc(fdcu,NE7CMD_SENSEI);
+ i = in_fdc(fdcu);
+ cyl = in_fdc(fdcu);
+ if (cyl != descyl)
+ {
+ printf("fd%d: Seek to cyl %d failed; am at cyl %d (ST0 = 0x%x)\n",
+ fdu, descyl, cyl, i, NE7_ST0BITS);
+ return(retrier(fdcu));
+ }
+ }
+
+ fd->track = bp->b_cylin;
+ if(format)
+ fd->skip = (char *)&(finfo->fd_formb_cylno(0))
+ - (char *)finfo;
+ isa_dmastart(bp->b_flags, bp->b_un.b_addr+fd->skip,
+ format ? bp->b_bcount : FDBLK, fdc->dmachan);
+ blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK
+ + fd->skip/FDBLK;
+ sectrac = fd->ft->sectrac;
+ sec = blknum % (sectrac * fd->ft->heads);
+ head = sec / sectrac;
+ sec = sec % sectrac + 1;
+/*XXX*/ fd->hddrv = ((head&1)<<2)+fdu;
+
+ if(format)
+ {
+ /* formatting */
+ out_fdc(fdcu,/* NE7CMD_FORMAT */ 0x4d);
+ out_fdc(fdcu,head << 2 | fdu);
+ out_fdc(fdcu,finfo->fd_formb_secshift);
+ out_fdc(fdcu,finfo->fd_formb_nsecs);
+ out_fdc(fdcu,finfo->fd_formb_gaplen);
+ out_fdc(fdcu,finfo->fd_formb_fillbyte);
+ }
+ else
+ {
+ if (read)
+ {
+ out_fdc(fdcu,NE7CMD_READ); /* READ */
+ }
+ else
+ {
+ out_fdc(fdcu,NE7CMD_WRITE); /* WRITE */
+ }
+ out_fdc(fdcu,head << 2 | fdu); /* head & unit */
+ out_fdc(fdcu,fd->track); /* track */
+ out_fdc(fdcu,head);
+ out_fdc(fdcu,sec); /* sector XXX +1? */
+ out_fdc(fdcu,fd->ft->secsize); /* sector size */
+ out_fdc(fdcu,sectrac); /* sectors/track */
+ out_fdc(fdcu,fd->ft->gap); /* gap size */
+ out_fdc(fdcu,fd->ft->datalen); /* data length */
+ }
+ fdc->state = IOCOMPLETE;
+ timeout((timeout_func_t)fd_timeout, (caddr_t)fdcu, 2 * hz);
+ return(0); /* will return later */
+ case IOCOMPLETE: /* IO DONE, post-analyze */
+ untimeout((timeout_func_t)fd_timeout, (caddr_t)fdcu);
+ for(i=0;i<7;i++)
+ {
+ fdc->status[i] = in_fdc(fdcu);
+ }
+ case IOTIMEDOUT: /*XXX*/
+ isa_dmadone(bp->b_flags, bp->b_un.b_addr+fd->skip,
+ format ? bp->b_bcount : FDBLK, fdc->dmachan);
+ if (fdc->status[0]&0xF8)
+ {
+ if (fdc->status[1] & 0x10) {
+ /*
+ * Operation not completed in reasonable time.
+ * Just restart it, don't increment retry count.
+ * (vak)
+ */
+ fdc->state = SEEKCOMPLETE;
+ return (1);
+ }
+ return(retrier(fdcu));
+ }
+ /* All OK */
+ fd->skip += FDBLK;
+ if (!format && fd->skip < bp->b_bcount)
+ {
+ /* set up next transfer */
+ blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK
+ + fd->skip/FDBLK;
+ bp->b_cylin = (blknum / (fd->ft->sectrac * fd->ft->heads));
+ fdc->state = DOSEEK;
+ }
+ else
+ {
+ /* ALL DONE */
+ fd->skip = 0;
+ bp->b_resid = 0;
+ dp->b_actf = bp->b_actf;
+ biodone(bp);
+ fdc->fd = (fd_p) 0;
+ fdc->fdu = -1;
+ fdc->state = FINDWORK;
+ }
+ return(1);
+ case RESETCTLR:
+ /* Try a reset, keep motor on */
+ set_motor(fdcu,fd->fdsu,1);
+ DELAY(100);
+ set_motor(fdcu,fd->fdsu,0);
+ outb(fdc->baseport+fdctl,fd->ft->trans);
+ TRACE1("[0x%x->fdctl]",fd->ft->trans);
+ fdc->retry++;
+ fdc->state = STARTRECAL;
+ break;
+ case STARTRECAL:
+ out_fdc(fdcu,NE7CMD_SPECIFY); /* specify command */
+ out_fdc(fdcu,0xDF);
+ out_fdc(fdcu,2);
+ out_fdc(fdcu,NE7CMD_RECAL); /* Recalibrate Function */
+ out_fdc(fdcu,fdu);
+ fdc->state = RECALWAIT;
+ return(0); /* will return later */
+ case RECALWAIT:
+ /* allow heads to settle */
+ timeout((timeout_func_t)fd_pseudointr, (caddr_t)fdcu, hz / 30);
+ fdc->state = RECALCOMPLETE;
+ return(0); /* will return later */
+ case RECALCOMPLETE:
+ out_fdc(fdcu,NE7CMD_SENSEI);
+ st0 = in_fdc(fdcu);
+ cyl = in_fdc(fdcu);
+ if (cyl != 0)
+ {
+ printf("fd%d: recal failed ST0 %b cyl %d\n", fdu,
+ st0, NE7_ST0BITS, cyl);
+ return(retrier(fdcu));
+ }
+ fd->track = 0;
+ /* Seek (probably) necessary */
+ fdc->state = DOSEEK;
+ return(1); /* will return immediatly */
+ case MOTORWAIT:
+ if(fd->flags & FD_MOTOR_WAIT)
+ {
+ return(0); /* time's not up yet */
+ }
+ fdc->state = DOSEEK;
+ return(1); /* will return immediatly */
+ default:
+ printf("Unexpected FD int->");
+ out_fdc(fdcu,NE7CMD_SENSEI);
+ st0 = in_fdc(fdcu);
+ cyl = in_fdc(fdcu);
+ printf("ST0 = %lx, PCN = %lx\n",i,sec);
+ out_fdc(fdcu,0x4A);
+ out_fdc(fdcu,fd->fdsu);
+ for(i=0;i<7;i++) {
+ fdc->status[i] = in_fdc(fdcu);
+ }
+ printf("intr status :%lx %lx %lx %lx %lx %lx %lx ",
+ fdc->status[0],
+ fdc->status[1],
+ fdc->status[2],
+ fdc->status[3],
+ fdc->status[4],
+ fdc->status[5],
+ fdc->status[6] );
+ return(0);
+ }
+ return(1); /* Come back immediatly to new state */
+}
+
+static int
+retrier(fdcu)
+ fdcu_t fdcu;
+{
+ fdc_p fdc = fdc_data + fdcu;
+ register struct buf *dp,*bp;
+
+ dp = &(fdc->head);
+ bp = dp->b_actf;
+
+ switch(fdc->retry)
+ {
+ case 0: case 1: case 2:
+ fdc->state = SEEKCOMPLETE;
+ break;
+ case 3: case 4: case 5:
+ fdc->state = STARTRECAL;
+ break;
+ case 6:
+ fdc->state = RESETCTLR;
+ break;
+ case 7:
+ break;
+ default:
+ {
+ dev_t sav_b_dev = bp->b_dev;
+ /* Trick diskerr */
+ bp->b_dev = makedev(major(bp->b_dev), (FDUNIT(minor(bp->b_dev))<<3)|3);
+ diskerr(bp, "fd", "hard error", LOG_PRINTF,
+ fdc->fd->skip, (struct disklabel *)NULL);
+ bp->b_dev = sav_b_dev;
+ printf(" (ST0 %b ", fdc->status[0], NE7_ST0BITS);
+ printf(" ST1 %b ", fdc->status[1], NE7_ST1BITS);
+ printf(" ST2 %b ", fdc->status[2], NE7_ST2BITS);
+ printf("cyl %d hd %d sec %d)\n",
+ fdc->status[3], fdc->status[4], fdc->status[5]);
+ }
+ bp->b_flags |= B_ERROR;
+ bp->b_error = EIO;
+ bp->b_resid = bp->b_bcount - fdc->fd->skip;
+ dp->b_actf = bp->b_actf;
+ fdc->fd->skip = 0;
+ biodone(bp);
+ fdc->state = FINDWORK;
+ fdc->fd = (fd_p) 0;
+ fdc->fdu = -1;
+ /* XXX abort current command, if any. */
+ return(1);
+ }
+ fdc->retry++;
+ return(1);
+}
+
+static int
+fdformat(dev, finfo, p)
+ dev_t dev;
+ struct fd_formb *finfo;
+ struct proc *p;
+{
+ fdu_t fdu;
+ fd_p fd;
+
+ struct buf *bp;
+ int rv = 0, s;
+
+ fdu = FDUNIT(minor(dev));
+ fd = &fd_data[fdu];
+
+ /* set up a buffer header for fdstrategy() */
+ bp = (struct buf *)malloc(sizeof(struct buf), M_TEMP, M_NOWAIT);
+ if(bp == 0)
+ return ENOBUFS;
+ bzero((void *)bp, sizeof(struct buf));
+ bp->b_flags = B_BUSY | B_PHYS | B_FORMAT;
+ bp->b_proc = p;
+ bp->b_dev = dev;
+
+ /*
+ * calculate a fake blkno, so fdstrategy() would initiate a
+ * seek to the requested cylinder
+ */
+ bp->b_blkno = (finfo->cyl * (fd->ft->sectrac * fd->ft->heads)
+ + finfo->head * fd->ft->sectrac) * FDBLK / DEV_BSIZE;
+
+ bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs;
+ bp->b_un.b_addr = (caddr_t)finfo;
+
+ /* now do the format */
+ fdstrategy(bp);
+
+ /* ...and wait for it to complete */
+ s = splbio();
+ while(!(bp->b_flags & B_DONE))
+ {
+ rv = tsleep((caddr_t)bp, PRIBIO, "fdform", 20 * hz);
+ if(rv == EWOULDBLOCK)
+ break;
+ }
+ splx(s);
+
+ if(rv == EWOULDBLOCK)
+ {
+ /* timed out */
+ biodone(bp);
+ rv = EIO;
+ }
+ free(bp, M_TEMP);
+ return rv;
+}
+
+/*
+ * fdioctl() from jc@irbs.UUCP (John Capo)
+ * i386/i386/conf.c needs to have fdioctl() declared and remove the line that
+ * defines fdioctl to be enxio.
+ *
+ * TODO: Reformat.
+ * Think about allocating buffer off stack.
+ * Don't pass uncast 0's and NULL's to read/write/setdisklabel().
+ * Watch out for NetBSD's different *disklabel() interface.
+ *
+ * Added functionality for floppy formatting
+ * joerg_wunsch@uriah.sax.de (Joerg Wunsch)
+ */
+
+int
+fdioctl (dev, cmd, addr, flag, p)
+ dev_t dev;
+ int cmd;
+ caddr_t addr;
+ int flag;
+ struct proc *p;
+{
+ struct fd_type *fdt;
+ struct disklabel *dl;
+ char buffer[DEV_BSIZE];
+ int error;
+
+#if NFT > 0
+ int type = FDTYPE(minor(dev));
+
+ /* check for a tape ioctl */
+ if (type & F_TAPE_TYPE)
+ return ftioctl(dev, cmd, addr, flag, p);
+#endif
+
+ error = 0;
+
+ switch (cmd)
+ {
+ case DIOCGDINFO:
+ bzero(buffer, sizeof (buffer));
+ dl = (struct disklabel *)buffer;
+ dl->d_secsize = FDBLK;
+ fdt = fd_data[FDUNIT(minor(dev))].ft;
+ dl->d_secpercyl = fdt->size / fdt->tracks;
+ dl->d_type = DTYPE_FLOPPY;
+
+ if (readdisklabel(dev, fdstrategy, dl, NULL, 0, 0) == NULL)
+ error = 0;
+ else
+ error = EINVAL;
+
+ *(struct disklabel *)addr = *dl;
+ break;
+
+ case DIOCSDINFO:
+ if ((flag & FWRITE) == 0)
+ error = EBADF;
+ break;
+
+ case DIOCWLABEL:
+ if ((flag & FWRITE) == 0)
+ error = EBADF;
+ break;
+
+ case DIOCWDINFO:
+ if ((flag & FWRITE) == 0)
+ {
+ error = EBADF;
+ break;
+ }
+
+ dl = (struct disklabel *)addr;
+
+ if (error = setdisklabel ((struct disklabel *)buffer,
+ dl, 0, NULL))
+ break;
+
+ error = writedisklabel(dev, fdstrategy,
+ (struct disklabel *)buffer, NULL);
+ break;
+
+ case FD_FORM:
+ if((flag & FWRITE) == 0)
+ error = EBADF; /* must be opened for writing */
+ else if(((struct fd_formb *)addr)->format_version !=
+ FD_FORMAT_VERSION)
+ error = EINVAL; /* wrong version of formatting prog */
+ else
+ error = fdformat(dev, (struct fd_formb *)addr, p);
+ break;
+
+ case FD_GTYPE: /* get drive type */
+ *(struct fd_type *)addr = *fd_data[FDUNIT(minor(dev))].ft;
+ break;
+
+ default:
+ error = EINVAL;
+ break;
+ }
+ return (error);
+}
+
+#endif
diff --git a/sys/dev/fdc/fdcreg.h b/sys/dev/fdc/fdcreg.h
new file mode 100644
index 0000000..5deb02c
--- /dev/null
+++ b/sys/dev/fdc/fdcreg.h
@@ -0,0 +1,65 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)fdreg.h 7.1 (Berkeley) 5/9/91
+ * $Id: fdreg.h,v 1.3 1994/02/07 04:27:10 alm Exp $
+ */
+
+/*
+ * AT floppy controller registers and bitfields
+ */
+
+/* uses NEC765 controller */
+#include "../i386/isa/ic/nec765.h"
+
+/* registers */
+#define fdout 2 /* Digital Output Register (W) */
+#define FDO_FDSEL 0x03 /* floppy device select */
+#define FDO_FRST 0x04 /* floppy controller reset */
+#define FDO_FDMAEN 0x08 /* enable floppy DMA and Interrupt */
+#define FDO_MOEN0 0x10 /* motor enable drive 0 */
+#define FDO_MOEN1 0x20 /* motor enable drive 1 */
+#define FDO_MOEN2 0x30 /* motor enable drive 2 */
+#define FDO_MOEN3 0x40 /* motor enable drive 3 */
+
+#define fdsts 4 /* NEC 765 Main Status Register (R) */
+#define fddata 5 /* NEC 765 Data Register (R/W) */
+
+#define fdctl 7 /* Control Register (W) */
+#define FDC_500KBPS 0x00 /* 500KBPS MFM drive transfer rate */
+#define FDC_300KBPS 0x01 /* 300KBPS MFM drive transfer rate */
+#define FDC_250KBPS 0x02 /* 250KBPS MFM drive transfer rate */
+#define FDC_125KBPS 0x03 /* 125KBPS FM drive transfer rate */
+
+#define fdin 7 /* Digital Input Register (R) */
+#define FDI_DCHG 0x80 /* diskette has been changed */
+
diff --git a/sys/dev/ic/i8237.h b/sys/dev/ic/i8237.h
new file mode 100644
index 0000000..2199e73
--- /dev/null
+++ b/sys/dev/ic/i8237.h
@@ -0,0 +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 */
+
diff --git a/sys/dev/ic/i82586.h b/sys/dev/ic/i82586.h
new file mode 100644
index 0000000..577313d
--- /dev/null
+++ b/sys/dev/ic/i82586.h
@@ -0,0 +1,325 @@
+/*-
+ * Copyright (c) 1992, University of Vermont and State Agricultural College.
+ * Copyright (c) 1992, Garrett A. Wollman.
+ * 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
+ * Vermont and State Agricultural College and Garrett A. Wollman.
+ * 4. Neither the name of the University nor the name of the author
+ * 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 UNIVERSITY OR AUTHOR 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$
+ */
+
+/*
+ * Intel 82586 Ethernet chip
+ * Register, bit, and structure definitions.
+ *
+ * Written by GAW with reference to the Clarkson Packet Driver code for this
+ * chip written by Russ Nelson and others.
+ */
+
+struct ie_en_addr {
+ u_char data[6];
+};
+
+/*
+ * This is the master configuration block. It tells the hardware where all
+ * the rest of the stuff is.
+ */
+struct ie_sys_conf_ptr {
+ u_short mbz; /* must be zero */
+ u_char ie_bus_use; /* true if 8-bit only */
+ u_char mbz2[5]; /* must be zero */
+ caddr_t ie_iscp_ptr; /* 24-bit physaddr of ISCP */
+};
+
+/*
+ * Note that this is wired in hardware; the SCP is always located here, no
+ * matter what.
+ */
+#define IE_SCP_ADDR 0xfffff4
+
+/*
+ * The tells the hardware where all the rest of the stuff is, too.
+ * FIXME: some of these should be re-commented after we figure out their
+ * REAL function.
+ */
+struct ie_int_sys_conf_ptr {
+ u_char ie_busy; /* zeroed after init */
+ u_char mbz;
+ u_short ie_scb_offset; /* 16-bit physaddr of next struct */
+ caddr_t ie_base; /* 24-bit physaddr for all 16-bit vars */
+};
+
+/*
+ * This FINALLY tells the hardware what to do and where to put it.
+ */
+struct ie_sys_ctl_block {
+ u_short ie_status; /* status word */
+ u_short ie_command; /* command word */
+ u_short ie_command_list; /* 16-pointer to command block list */
+ u_short ie_recv_list; /* 16-pointer to receive frame list */
+ u_short ie_err_crc; /* CRC errors */
+ u_short ie_err_align; /* Alignment errors */
+ u_short ie_err_resource; /* Resource errors */
+ u_short ie_err_overrun; /* Overrun errors */
+};
+
+/* Command values */
+#define IE_RU_COMMAND 0x0070 /* mask for RU command */
+#define IE_RU_NOP 0 /* for completeness */
+#define IE_RU_START 0x0010 /* start receive unit command */
+#define IE_RU_ENABLE 0x0020 /* enable receiver command */
+#define IE_RU_DISABLE 0x0030 /* disable receiver command */
+#define IE_RU_ABORT 0x0040 /* abort current receive operation */
+
+#define IE_CU_COMMAND 0x0700 /* mask for CU command */
+#define IE_CU_NOP 0 /* included for completeness */
+#define IE_CU_START 0x0100 /* do-command command */
+#define IE_CU_RESUME 0x0200 /* resume a suspended cmd list */
+#define IE_CU_STOP 0x0300 /* SUSPEND was already taken */
+#define IE_CU_ABORT 0x0400 /* abort current command */
+
+#define IE_ACK_COMMAND 0xf000 /* mask for ACK command */
+#define IE_ACK_CX 0x8000 /* ack IE_ST_DONE */
+#define IE_ACK_FR 0x4000 /* ack IE_ST_RECV */
+#define IE_ACK_CNA 0x2000 /* ack IE_ST_ALLDONE */
+#define IE_ACK_RNR 0x1000 /* ack IE_ST_RNR */
+
+#define IE_ACTION_COMMAND(x) (((x) & IE_CU_COMMAND) == IE_CU_START)
+ /* is this command an action command? */
+
+/* Status values */
+#define IE_ST_WHENCE 0xf000 /* mask for cause of interrupt */
+#define IE_ST_DONE 0x8000 /* command with I bit completed */
+#define IE_ST_RECV 0x4000 /* frame received */
+#define IE_ST_ALLDONE 0x2000 /* all commands completed */
+#define IE_ST_RNR 0x1000 /* receive not ready */
+
+#define IE_CU_STATUS 0x700 /* mask for command unit status */
+#define IE_CU_ACTIVE 0x200 /* command unit is active */
+#define IE_CU_SUSPEND 0x100 /* command unit is suspended */
+
+#define IE_RU_STATUS 0x70 /* mask for receiver unit status */
+#define IE_RU_SUSPEND 0x10 /* receiver is suspended */
+#define IE_RU_NOSPACE 0x20 /* receiver has no resources */
+#define IE_RU_READY 0x40 /* reveiver is ready */
+
+/*
+ * This is filled in partially by the chip, partially by us.
+ */
+struct ie_recv_frame_desc {
+ u_short ie_fd_status; /* status for this frame */
+ u_short ie_fd_last; /* end of frame list flag */
+ u_short ie_fd_next; /* 16-pointer to next RFD */
+ u_short ie_fd_buf_desc; /* 16-pointer to list of buffer desc's */
+ struct ie_en_addr dest; /* destination ether */
+ struct ie_en_addr src; /* source ether */
+ u_short ie_length; /* 802 length/Ether type */
+ u_short mbz; /* must be zero */
+};
+
+#define IE_FD_LAST 0x8000 /* last rfd in list */
+#define IE_FD_SUSP 0x4000 /* suspend RU after receipt */
+
+#define IE_FD_COMPLETE 0x8000 /* frame is complete */
+#define IE_FD_BUSY 0x4000 /* frame is busy */
+#define IE_FD_OK 0x2000 /* frame is bad */
+#define IE_FD_RNR 0x0200 /* receiver out of resources here */
+
+/*
+ * linked list of buffers...
+ */
+struct ie_recv_buf_desc {
+ u_short ie_rbd_actual; /* status for this buffer */
+ u_short ie_rbd_next; /* 16-pointer to next RBD */
+ caddr_t ie_rbd_buffer; /* 24-pointer to buffer for this RBD */
+ u_short ie_rbd_length; /* length of the buffer */
+ u_short mbz; /* must be zero */
+};
+
+#define IE_RBD_LAST 0x8000 /* last buffer */
+#define IE_RBD_USED 0x4000 /* this buffer has data */
+/*
+ * All commands share this in common.
+ */
+struct ie_cmd_common {
+ u_short ie_cmd_status; /* status of this command */
+ u_short ie_cmd_cmd; /* command word */
+ u_short ie_cmd_link; /* link to next command */
+};
+
+#define IE_STAT_COMPL 0x8000 /* command is completed */
+#define IE_STAT_BUSY 0x4000 /* command is running now */
+#define IE_STAT_OK 0x2000 /* command completed successfully */
+
+#define IE_CMD_NOP 0x0000 /* NOP */
+#define IE_CMD_IASETUP 0x0001 /* initial address setup */
+#define IE_CMD_CONFIG 0x0002 /* configure command */
+#define IE_CMD_MCAST 0x0003 /* multicast setup command */
+#define IE_CMD_XMIT 0x0004 /* transmit command */
+#define IE_CMD_TDR 0x0005 /* time-domain reflectometer command */
+#define IE_CMD_DUMP 0x0006 /* dump command */
+#define IE_CMD_DIAGNOSE 0x0007 /* diagnostics command */
+
+#define IE_CMD_LAST 0x8000 /* this is the last command in the list */
+#define IE_CMD_SUSPEND 0x4000 /* suspend CU after this command */
+#define IE_CMD_INTR 0x2000 /* post an interrupt after completion */
+
+/*
+ * This is the command to transmit a frame.
+ */
+struct ie_xmit_cmd {
+ struct ie_cmd_common com; /* common part */
+#define ie_xmit_status com.ie_cmd_status
+
+ u_short ie_xmit_desc; /* 16-pointer to buffer descriptor */
+ struct ie_en_addr ie_xmit_addr; /* destination address */
+
+ u_short ie_xmit_length; /* 802.3 length/Ether type field */
+};
+
+#define IE_XS_MAXCOLL 0x000f /* number of collisions during transmit */
+#define IE_XS_EXCMAX 0x0020 /* exceeded maximum number of collisions */
+#define IE_XS_SQE 0x0040 /* SQE positive */
+#define IE_XS_DEFERRED 0x0080 /* transmission deferred */
+#define IE_XS_UNDERRUN 0x0100 /* DMA underrun */
+#define IE_XS_LOSTCTS 0x0200 /* Lost CTS */
+#define IE_XS_NOCARRIER 0x0400 /* No Carrier */
+#define IE_XS_LATECOLL 0x0800 /* Late collision */
+
+/*
+ * This is a buffer descriptor for a frame to be transmitted.
+ */
+
+struct ie_xmit_buf {
+ u_short ie_xmit_flags; /* see below */
+ u_short ie_xmit_next; /* 16-pointer to next desc. */
+ caddr_t ie_xmit_buf; /* 24-pointer to the actual buffer */
+};
+
+#define IE_XMIT_LAST 0x8000 /* this TBD is the last one */
+/* The rest of the `flags' word is actually the length. */
+
+/*
+ * Multicast setup command.
+ */
+
+#define MAXMCAST 50 /* must fit in transmit buffer */
+
+struct ie_mcast_cmd {
+ struct ie_cmd_common com; /* common part */
+#define ie_mcast_status com.ie_cmd_status
+
+ u_short ie_mcast_bytes; /* size (in bytes) of multicast addresses */
+ struct ie_en_addr ie_mcast_addrs[MAXMCAST + 1]; /* space for them */
+};
+
+/*
+ * Time Domain Reflectometer command.
+ */
+
+struct ie_tdr_cmd {
+ struct ie_cmd_common com; /* common part */
+#define ie_tdr_status com.ie_cmd_status
+
+ u_short ie_tdr_time; /* error bits and time */
+};
+
+#define IE_TDR_SUCCESS 0x8000 /* TDR succeeded without error */
+#define IE_TDR_XCVR 0x4000 /* detected a transceiver problem */
+#define IE_TDR_OPEN 0x2000 /* detected an open */
+#define IE_TDR_SHORT 0x1000 /* TDR detected a short */
+#define IE_TDR_TIME 0x07ff /* mask for reflection time */
+
+/*
+ * Initial Address Setup command
+ */
+struct ie_iasetup_cmd {
+ struct ie_cmd_common com;
+#define ie_iasetup_status com.ie_cmd_status
+
+ struct ie_en_addr ie_address;
+};
+
+/*
+ * Configuration command
+ */
+struct ie_config_cmd {
+ struct ie_cmd_common com; /* common part */
+#define ie_config_status com.ie_cmd_status
+
+ u_char ie_config_count; /* byte count (0x0c) */
+ u_char ie_fifo; /* fifo (8) */
+ u_char ie_save_bad; /* save bad frames (0x40) */
+ u_char ie_addr_len; /* address length (0x2e) (AL-LOC == 1) */
+ u_char ie_priority; /* priority and backoff (0x0) */
+ u_char ie_ifs; /* inter-frame spacing (0x60) */
+ u_char ie_slot_low; /* slot time, LSB (0x0) */
+ u_char ie_slot_high; /* slot time, MSN, and retries (0xf2) */
+ u_char ie_promisc; /* 1 if promiscuous, else 0 */
+ u_char ie_crs_cdt; /* CSMA/CD parameters (0x0) */
+ u_char ie_min_len; /* min frame length (0x40) */
+ u_char ie_junk; /* stuff for 82596 (0xff) */
+};
+
+/*
+ * Here are a few useful functions. We could have done these as macros,
+ * but since we have the inline facility, it makes sense to use that
+ * instead.
+ */
+inline void
+ie_setup_config(volatile struct ie_config_cmd *cmd,
+ int promiscuous, int manchester) {
+ cmd->ie_config_count = 0x0c;
+ cmd->ie_fifo = 8;
+ cmd->ie_save_bad = 0x40;
+ cmd->ie_addr_len = 0x2e;
+ cmd->ie_priority = 0;
+ cmd->ie_ifs = 0x60;
+ cmd->ie_slot_low = 0;
+ cmd->ie_slot_high = 0xf2;
+ cmd->ie_promisc = !!promiscuous | manchester << 2;
+ cmd->ie_crs_cdt = 0;
+ cmd->ie_min_len = 64;
+ cmd->ie_junk = 0xff;
+}
+
+inline caddr_t
+Align(caddr_t ptr) {
+ unsigned long l = (unsigned long)ptr;
+ l = (l + 3) & ~3L;
+ return (caddr_t)l;
+}
+
+inline void
+ie_ack(volatile struct ie_sys_ctl_block *scb,
+ u_int mask, int unit,
+ void (*ca)(int)) {
+ scb->ie_command = scb->ie_status & mask;
+ (*ca)(unit);
+}
diff --git a/sys/dev/ic/nec765.h b/sys/dev/ic/nec765.h
new file mode 100644
index 0000000..1895db7
--- /dev/null
+++ b/sys/dev/ic/nec765.h
@@ -0,0 +1,72 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)nec765.h 7.1 (Berkeley) 5/9/91
+ * $Id$
+ */
+
+/*
+ * Nec 765 floppy disc controller definitions
+ */
+
+/* Main status register */
+#define NE7_DAB 0x01 /* Diskette drive A is seeking, thus busy */
+#define NE7_DBB 0x02 /* Diskette drive B is seeking, thus busy */
+#define NE7_CB 0x10 /* Diskette Controller Busy */
+#define NE7_NDM 0x20 /* Diskette Controller in Non Dma Mode */
+#define NE7_DIO 0x40 /* Diskette Controller Data register I/O */
+#define NE7_RQM 0x80 /* Diskette Controller ReQuest for Master */
+
+/* Status register ST0 */
+#define NE7_ST0BITS "\020\010invld\007abnrml\006seek_cmplt\005drv_chck\004drive_rdy\003top_head"
+
+/* Status register ST1 */
+#define NE7_ST1BITS "\020\010end_of_cyl\006bad_crc\005data_overrun\003sec_not_fnd\002write_protect\001no_am"
+
+/* Status register ST2 */
+#define NE7_ST2BITS "\020\007ctrl_mrk\006bad_crc\005wrong_cyl\004scn_eq\003scn_not_fnd\002bad_cyl\001no_dam"
+
+/* Status register ST3 */
+#define NE7_ST3BITS "\020\010fault\007write_protect\006drdy\005tk0\004two_side\003side_sel\002"
+
+/* Commands */
+#define NE7CMD_SPECIFY 3 /* specify drive parameters - requires unit
+ parameters byte */
+#define NE7CMD_SENSED 4 /* sense drive - requires unit select byte */
+#define NE7CMD_WRITE 0xc5 /* write - requires eight additional bytes */
+#define NE7CMD_READ 0xe6 /* read - requires eight additional bytes */
+#define NE7CMD_FORMAT 0x4c /* format - requires five additional bytes */
+#define NE7CMD_RECAL 7 /* recalibrate drive - requires
+ unit select byte */
+#define NE7CMD_SENSEI 8 /* sense controller interrupt status */
+#define NE7CMD_SEEK 15 /* seek drive - requires unit select byte
+ and new cyl byte */
diff --git a/sys/dev/ic/ns16550.h b/sys/dev/ic/ns16550.h
new file mode 100644
index 0000000..ff59757
--- /dev/null
+++ b/sys/dev/ic/ns16550.h
@@ -0,0 +1,51 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)ns16550.h 7.1 (Berkeley) 5/9/91
+ * $Id$
+ */
+
+/*
+ * NS16550 UART registers
+ */
+
+#define com_data 0 /* data register (R/W) */
+#define com_dlbl 0 /* divisor latch low (W) */
+#define com_dlbh 1 /* divisor latch high (W) */
+#define com_ier 1 /* interrupt enable (W) */
+#define com_iir 2 /* interrupt identification (R) */
+#define com_fifo 2 /* FIFO control (W) */
+#define com_lctl 3 /* line control register (R/W) */
+#define com_cfcr 3 /* line control register (R/W) */
+#define com_mcr 4 /* modem control register (R/W) */
+#define com_lsr 5 /* line status register (R/W) */
+#define com_msr 6 /* modem status register (R/W) */
diff --git a/sys/dev/ie/if_ie.c b/sys/dev/ie/if_ie.c
new file mode 100644
index 0000000..fbb1d5e
--- /dev/null
+++ b/sys/dev/ie/if_ie.c
@@ -0,0 +1,1801 @@
+/*-
+ * Copyright (c) 1992, 1993, University of Vermont and State
+ * Agricultural College.
+ * Copyright (c) 1992, 1993, Garrett A. Wollman.
+ *
+ * Portions:
+ * Copyright (c) 1990, 1991, William F. Jolitz
+ * Copyright (c) 1990, The Regents of the University of California
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * Vermont and State Agricultural College and Garrett A. Wollman,
+ * by William F. Jolitz, by the University of California,
+ * Berkeley, by Larwence Berkeley Laboratory, and its contributors.
+ * 4. Neither the names of the Universities nor the names of the authors
+ * 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 UNIVERSITY OR AUTHORS 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: if_ie.c,v 1.2 1993/11/25 01:31:36 wollman Exp $
+ */
+
+/*
+ * Intel 82586 Ethernet chip
+ * Register, bit, and structure definitions.
+ *
+ * Written by GAW with reference to the Clarkson Packet Driver code for this
+ * chip written by Russ Nelson and others.
+ *
+ * BPF support code stolen directly from hpdev/if_le.c, supplied with
+ * tcpdump.
+ */
+
+/*
+ * The i82586 is a very versatile chip, found in many implementations.
+ * Programming this chip is mostly the same, but certain details differ
+ * from card to card. This driver is written so that different cards
+ * can be automatically detected at run-time. Currently, only the
+ * AT&T EN100/StarLAN 10 series are supported.
+ */
+
+/*
+Mode of operation:
+
+We run the 82586 in a standard Ethernet mode. We keep NFRAMES received
+frame descriptors around for the receiver to use, and NBUFFS associated
+receive buffer descriptors, both in a circular list. Whenever a frame is
+received, we rotate both lists as necessary. (The 586 treats both lists
+as a simple queue.) We also keep a transmit command around so that packets
+can be sent off quickly.
+
+We configure the adapter in AL-LOC = 1 mode, which means that the
+Ethernet/802.3 MAC header is placed at the beginning of the receive buffer
+rather than being split off into various fields in the RFD. This also
+means that we must include this header in the transmit buffer as well.
+
+By convention, all transmit commands, and only transmit commands, shall
+have the I (IE_CMD_INTR) bit set in the command. This way, when an
+interrupt arrives at ieintr(), it is immediately possible to tell
+what precisely caused it. ANY OTHER command-sending routines should
+run at splimp(), and should post an acknowledgement to every interrupt
+they generate.
+
+The 82586 has a 24-bit address space internally, and the adaptor's
+memory is located at the top of this region. However, the value we are
+given in configuration is normally the *bottom* of the adaptor RAM. So,
+we must go through a few gyrations to come up with a kernel virtual address
+which represents the actual beginning of the 586 address space. First,
+we autosize the RAM by running through several possible sizes and trying
+to initialize the adapter under the assumption that the selected size
+is correct. Then, knowing the correct RAM size, we set up our pointers
+in ie_softc[unit]. `iomem' represents the computed base of the 586
+address space. `iomembot' represents the actual configured base
+of adapter RAM. Finally, `iosize' represents the calculated size
+of 586 RAM. Then, when laying out commands, we use the interval
+[iomembot, iomembot + iosize); to make 24-pointers, we subtract
+iomem, and to make 16-pointers, we subtract iomem and and with 0xffff.
+
+*/
+
+#include "ie.h"
+#if NIE > 0
+
+#include "param.h"
+#include "systm.h"
+#include "mbuf.h"
+#include "protosw.h"
+#include "socket.h"
+#include "ioctl.h"
+#include "errno.h"
+#include "syslog.h"
+
+#include "net/if.h"
+#include "net/if_types.h"
+#include "net/if_dl.h"
+#include "net/route.h"
+
+#include "bpfilter.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
+
+#include "i386/isa/isa.h"
+#include "i386/isa/isa_device.h"
+#include "i386/isa/ic/i82586.h"
+#include "i386/isa/if_iereg.h"
+#include "i386/isa/icu.h"
+
+#include "vm/vm.h"
+
+#if NBPFILTER > 0
+#include "net/bpf.h"
+#include "net/bpfdesc.h"
+#endif
+
+#if (NBPFILTER > 0) || defined(MULTICAST)
+#define FILTER
+static struct mbuf *last_not_for_us;
+#endif
+
+#ifdef DEBUG
+#define IED_RINT 1
+#define IED_TINT 2
+#define IED_RNR 4
+#define IED_CNA 8
+#define IED_READFRAME 16
+int ie_debug = IED_RNR;
+#endif
+
+#ifndef ETHERMINLEN
+#define ETHERMINLEN 60
+#endif
+
+#define IE_BUF_LEN 1512 /* length of transmit buffer */
+
+/* Forward declaration */
+struct ie_softc;
+
+static int ieprobe(struct isa_device *dvp);
+static int ieattach(struct isa_device *dvp);
+static void ieinit(int unit);
+static int ieioctl(struct ifnet *ifp, int command, caddr_t data);
+static void iestart(struct ifnet *ifp);
+static void sl_reset_586(int unit);
+static void sl_chan_attn(int unit);
+static void iereset(int unit);
+static void ie_readframe(int unit, struct ie_softc *ie, int bufno);
+static void ie_drop_packet_buffer(int unit, struct ie_softc *ie);
+static void sl_read_ether(int unit, unsigned char addr[6]);
+static void find_ie_mem_size(int unit);
+static int command_and_wait(int unit, int command, void volatile *pcmd, int);
+static int ierint(int unit, struct ie_softc *ie);
+static int ietint(int unit, struct ie_softc *ie);
+static int iernr(int unit, struct ie_softc *ie);
+static void start_receiver(int unit);
+static int ieget(int, struct ie_softc *, struct mbuf **,
+ struct ether_header *, int *);
+static caddr_t setup_rfa(caddr_t ptr, struct ie_softc *ie);
+static int mc_setup(int, caddr_t, volatile struct ie_sys_ctl_block *);
+#ifdef MULTICAST
+static void ie_mc_reset(int unit);
+#endif
+
+#ifdef DEBUG
+void print_rbd(volatile struct ie_recv_buf_desc *rbd);
+
+int in_ierint = 0;
+int in_ietint = 0;
+#endif
+
+/*
+ * This tells the autoconf code how to set us up.
+ */
+struct isa_driver iedriver = {
+ ieprobe, ieattach, "ie",
+};
+
+enum ie_hardware {
+ IE_STARLAN10,
+ IE_EN100,
+ IE_SLFIBER,
+ IE_UNKNOWN
+};
+
+const char *ie_hardware_names[] = {
+ "StarLAN 10",
+ "EN100",
+ "StarLAN Fiber",
+ "Unknown"
+};
+
+/*
+sizeof(iscp) == 1+1+2+4 == 8
+sizeof(scb) == 2+2+2+2+2+2+2+2 == 16
+NFRAMES * sizeof(rfd) == NFRAMES*(2+2+2+2+6+6+2+2) == NFRAMES*24 == 384
+sizeof(xmit_cmd) == 2+2+2+2+6+2 == 18
+sizeof(transmit buffer) == 1512
+sizeof(transmit buffer desc) == 8
+-----
+1946
+
+NBUFFS * sizeof(rbd) == NBUFFS*(2+2+4+2+2) == NBUFFS*12
+NBUFFS * IE_RBUF_SIZE == NBUFFS*256
+
+NBUFFS should be (16384 - 1946) / (256 + 12) == 14438 / 268 == 53
+
+With NBUFFS == 48, this leaves us 1574 bytes for another command or
+more buffers. Another transmit command would be 18+8+1512 == 1538
+---just barely fits!
+
+Obviously all these would have to be reduced for smaller memory sizes.
+With a larger memory, it would be possible to roughly double the number of
+both transmit and receive buffers.
+*/
+
+#define NFRAMES 16 /* number of frames to allow for receive */
+#define NBUFFS 48 /* number of buffers to allocate */
+#define IE_RBUF_SIZE 256 /* size of each buffer, MUST BE POWER OF TWO */
+
+/*
+ * Ethernet status, per interface.
+ */
+struct ie_softc {
+ struct arpcom arpcom;
+ void (*ie_reset_586)(int);
+ void (*ie_chan_attn)(int);
+ enum ie_hardware hard_type;
+ int hard_vers;
+
+ u_short port;
+ caddr_t iomem;
+ caddr_t iomembot;
+ unsigned iosize;
+
+ int want_mcsetup;
+ int promisc;
+ volatile struct ie_int_sys_conf_ptr *iscp;
+ volatile struct ie_sys_ctl_block *scb;
+ volatile struct ie_recv_frame_desc *rframes[NFRAMES];
+ volatile struct ie_recv_buf_desc *rbuffs[NBUFFS];
+ volatile char *cbuffs[NBUFFS];
+ int rfhead, rftail, rbhead, rbtail;
+
+ volatile struct ie_xmit_cmd *xmit_cmds[2];
+ volatile struct ie_xmit_buf *xmit_buffs[2];
+ int xmit_count;
+ u_char *xmit_cbuffs[2];
+
+ struct ie_en_addr mcast_addrs[MAXMCAST + 1];
+ int mcast_count;
+
+#if NBPFILTER > 0
+ caddr_t ie_bpf;
+#endif
+
+} ie_softc[NIE];
+
+#define MK_24(base, ptr) ((caddr_t)((u_long)ptr - (u_long)base))
+#define MK_16(base, ptr) ((u_short)(u_long)MK_24(base, ptr))
+
+#define PORT ie_softc[unit].port
+#define MEM ie_softc[unit].iomem
+
+
+int ieprobe(dvp)
+ struct isa_device *dvp;
+{
+ int unit = dvp->id_unit;
+ u_char c;
+
+ ie_softc[unit].port = dvp->id_iobase;
+ ie_softc[unit].iomembot = dvp->id_maddr;
+ ie_softc[unit].iomem = 0;
+
+ c = inb(PORT + IEATT_REVISION);
+ switch(SL_BOARD(c)) {
+ case SL10_BOARD:
+ ie_softc[unit].hard_type = IE_STARLAN10;
+ ie_softc[unit].ie_reset_586 = sl_reset_586;
+ ie_softc[unit].ie_chan_attn = sl_chan_attn;
+ break;
+ case EN100_BOARD:
+ ie_softc[unit].hard_type = IE_EN100;
+ ie_softc[unit].ie_reset_586 = sl_reset_586;
+ ie_softc[unit].ie_chan_attn = sl_chan_attn;
+ break;
+ case SLFIBER_BOARD:
+ ie_softc[unit].hard_type = IE_SLFIBER;
+ ie_softc[unit].ie_reset_586 = sl_reset_586;
+ ie_softc[unit].ie_chan_attn = sl_chan_attn;
+ break;
+
+ /*
+ * Anything else is not recognized or cannot be used.
+ */
+ default:
+ return 0;
+ }
+
+ ie_softc[unit].hard_vers = SL_REV(c);
+
+ /*
+ * Divine memory size on-board the card. Ususally 16k.
+ */
+ find_ie_mem_size(unit);
+
+ if(!ie_softc[unit].iosize) {
+ return 0;
+ }
+
+ dvp->id_msize = ie_softc[unit].iosize;
+
+ switch(ie_softc[unit].hard_type) {
+ case IE_EN100:
+ case IE_STARLAN10:
+ case IE_SLFIBER:
+ sl_read_ether(unit, ie_softc[unit].arpcom.ac_enaddr);
+ break;
+
+ default:
+ printf("ie%d: unknown AT&T board type code %d\n", unit,
+ ie_softc[unit].hard_type);
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * Taken almost exactly from Bill's if_is.c, then modified beyond recognition.
+ */
+int
+ieattach(dvp)
+ struct isa_device *dvp;
+{
+ int unit = dvp->id_unit;
+ struct ie_softc *ie = &ie_softc[unit];
+ struct ifnet *ifp = &ie->arpcom.ac_if;
+
+ ifp->if_unit = unit;
+ ifp->if_name = iedriver.name;
+ ifp->if_mtu = ETHERMTU;
+ printf("<%s R%d> ethernet address %s",
+ ie_hardware_names[ie_softc[unit].hard_type],
+ ie_softc[unit].hard_vers + 1,
+ ether_sprintf(ie->arpcom.ac_enaddr));
+
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
+#ifdef MULTICAST
+ ifp->if_flags |= IFF_MULTICAST;
+#endif /* MULTICAST */
+
+ ifp->if_init = ieinit;
+ ifp->if_output = ether_output;
+ ifp->if_start = iestart;
+ ifp->if_ioctl = ieioctl;
+ ifp->if_reset = iereset;
+ ifp->if_type = IFT_ETHER;
+ ifp->if_addrlen = 6;
+ ifp->if_hdrlen = 14;
+
+#if NBPFILTER > 0
+ printf("\n");
+ bpfattach(&ie_softc[unit].ie_bpf, ifp, DLT_EN10MB,
+ sizeof(struct ether_header));
+#endif
+
+ if_attach(ifp);
+ {
+ struct ifaddr *ifa = ifp->if_addrlist;
+ struct sockaddr_dl *sdl;
+ while(ifa && ifa->ifa_addr && ifa->ifa_addr->sa_family != AF_LINK)
+ ifa = ifa->ifa_next;
+
+ if(!ifa || !ifa->ifa_addr) return 1;
+
+ /* Provide our ether address to the higher layers */
+ sdl = (struct sockaddr_dl *)ifa->ifa_addr;
+ sdl->sdl_type = IFT_ETHER;
+ sdl->sdl_alen = 6;
+ sdl->sdl_slen = 0;
+ bcopy(ie->arpcom.ac_enaddr, LLADDR(sdl), 6);
+ return 1;
+ }
+}
+
+/*
+ * What to do upon receipt of an interrupt.
+ */
+int ieintr(unit)
+ int unit;
+{
+ register struct ie_softc *ie = &ie_softc[unit];
+ register u_short status;
+
+ status = ie->scb->ie_status;
+
+loop:
+ if(status & (IE_ST_RECV | IE_ST_RNR)) {
+#ifdef DEBUG
+ in_ierint++;
+ if(ie_debug & IED_RINT)
+ printf("ie%d: rint\n", unit);
+#endif
+ ierint(unit, ie);
+#ifdef DEBUG
+ in_ierint--;
+#endif
+ }
+
+ if(status & IE_ST_DONE) {
+#ifdef DEBUG
+ in_ietint++;
+ if(ie_debug & IED_TINT)
+ printf("ie%d: tint\n", unit);
+#endif
+ ietint(unit, ie);
+#ifdef DEBUG
+ in_ietint--;
+#endif
+ }
+
+ if(status & IE_ST_RNR) {
+#ifdef DEBUG
+ if(ie_debug & IED_RNR)
+ printf("ie%d: rnr\n", unit);
+#endif
+ iernr(unit, ie);
+ }
+
+#ifdef DEBUG
+ if((status & IE_ST_ALLDONE)
+ && (ie_debug & IED_CNA))
+ printf("ie%d: cna\n", unit);
+#endif
+
+ /* Don't ack interrupts which we didn't receive */
+ ie_ack(ie->scb, IE_ST_WHENCE & status, unit, ie->ie_chan_attn);
+
+ if((status = ie->scb->ie_status) & IE_ST_WHENCE)
+ goto loop;
+
+ return unit;
+}
+
+/*
+ * Process a received-frame interrupt.
+ */
+static int ierint(unit, ie)
+ int unit;
+ struct ie_softc *ie;
+{
+ int i, status;
+ static int timesthru = 1024;
+
+ i = ie->rfhead;
+ while(1) {
+ status = ie->rframes[i]->ie_fd_status;
+
+ if((status & IE_FD_COMPLETE) && (status & IE_FD_OK)) {
+ ie->arpcom.ac_if.if_ipackets++;
+ if(!--timesthru) {
+ ie->arpcom.ac_if.if_ierrors += ie->scb->ie_err_crc + ie->scb->ie_err_align +
+ ie->scb->ie_err_resource + ie->scb->ie_err_overrun;
+ ie->scb->ie_err_crc = 0;
+ ie->scb->ie_err_align = 0;
+ ie->scb->ie_err_resource = 0;
+ ie->scb->ie_err_overrun = 0;
+ timesthru = 1024;
+ }
+ ie_readframe(unit, ie, i);
+ } else {
+ if(status & IE_FD_RNR) {
+ if(!(ie->scb->ie_status & IE_RU_READY)) {
+ ie->rframes[0]->ie_fd_next = MK_16(MEM, ie->rbuffs[0]);
+ ie->scb->ie_recv_list = MK_16(MEM, ie->rframes[0]);
+ command_and_wait(unit, IE_RU_START, 0, 0);
+ }
+ }
+ break;
+ }
+ i = (i + 1) % NFRAMES;
+ }
+ return 0;
+}
+
+/*
+ * Process a command-complete interrupt. These are only generated by
+ * the transmission of frames. This routine is deceptively simple, since
+ * most of the real work is done by iestart().
+ */
+static int ietint(unit, ie)
+ int unit;
+ struct ie_softc *ie;
+{
+ int status;
+ int i;
+
+ ie->arpcom.ac_if.if_timer = 0;
+ ie->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
+
+ for(i = 0; i < ie->xmit_count; i++) {
+ status = ie->xmit_cmds[i]->ie_xmit_status;
+
+ if(status & IE_XS_LATECOLL) {
+ printf("ie%d: late collision\n", unit);
+ ie->arpcom.ac_if.if_collisions++;
+ ie->arpcom.ac_if.if_oerrors++;
+ } else if(status & IE_XS_NOCARRIER) {
+ printf("ie%d: no carrier\n", unit);
+ ie->arpcom.ac_if.if_oerrors++;
+ } else if(status & IE_XS_LOSTCTS) {
+ printf("ie%d: lost CTS\n", unit);
+ ie->arpcom.ac_if.if_oerrors++;
+ } else if(status & IE_XS_UNDERRUN) {
+ printf("ie%d: DMA underrun\n", unit);
+ ie->arpcom.ac_if.if_oerrors++;
+ } else if(status & IE_XS_EXCMAX) {
+ printf("ie%d: too many collisions\n", unit);
+ ie->arpcom.ac_if.if_collisions += 16;
+ ie->arpcom.ac_if.if_oerrors++;
+ } else {
+ ie->arpcom.ac_if.if_opackets++;
+ ie->arpcom.ac_if.if_collisions += status & IE_XS_MAXCOLL;
+ }
+ }
+ ie->xmit_count = 0;
+
+ /*
+ * If multicast addresses were added or deleted while we were transmitting,
+ * ie_mc_reset() set the want_mcsetup flag indicating that we should do it.
+ */
+ if(ie->want_mcsetup) {
+ mc_setup(unit, (caddr_t)ie->xmit_cbuffs[0], ie->scb);
+ ie->want_mcsetup = 0;
+ }
+
+ /* Wish I knew why this seems to be necessary... */
+ ie->xmit_cmds[0]->ie_xmit_status |= IE_STAT_COMPL;
+
+ iestart(&ie->arpcom.ac_if);
+ return 0; /* shouldn't be necessary */
+}
+
+/*
+ * Process a receiver-not-ready interrupt. I believe that we get these
+ * when there aren't enough buffers to go around. For now (FIXME), we
+ * just restart the receiver, and hope everything's ok.
+ */
+static int iernr(unit, ie)
+ int unit;
+ struct ie_softc *ie;
+{
+#ifdef doesnt_work
+ setup_rfa((caddr_t)ie->rframes[0], ie);
+
+ ie->scb->ie_recv_list = MK_16(MEM, ie_softc[unit].rframes[0]);
+ command_and_wait(unit, IE_RU_START, 0, 0);
+#else
+ /* This doesn't work either, but it doesn't hang either. */
+ command_and_wait(unit, IE_RU_DISABLE, 0, 0); /* just in case */
+ setup_rfa((caddr_t)ie->rframes[0], ie); /* ignore cast-qual */
+
+ ie->scb->ie_recv_list = MK_16(MEM, ie_softc[unit].rframes[0]);
+ command_and_wait(unit, IE_RU_START, 0, 0); /* was ENABLE */
+
+#endif
+ ie_ack(ie->scb, IE_ST_WHENCE, unit, ie->ie_chan_attn);
+
+ ie->arpcom.ac_if.if_ierrors++;
+ return 0;
+}
+
+#ifdef FILTER
+/*
+ * Compare two Ether/802 addresses for equality, inlined and
+ * unrolled for speed. I'd love to have an inline assembler
+ * version of this...
+ */
+static inline int ether_equal(u_char *one, u_char *two) {
+ if(one[0] != two[0]) return 0;
+ if(one[1] != two[1]) return 0;
+ if(one[2] != two[2]) return 0;
+ if(one[3] != two[3]) return 0;
+ if(one[4] != two[4]) return 0;
+ if(one[5] != two[5]) return 0;
+ return 1;
+}
+
+/*
+ * Check for a valid address. to_bpf is filled in with one of the following:
+ * 0 -> BPF doesn't get this packet
+ * 1 -> BPF does get this packet
+ * 2 -> BPF does get this packet, but we don't
+ * Return value is true if the packet is for us, and false otherwise.
+ *
+ * This routine is a mess, but it's also critical that it be as fast
+ * as possible. It could be made cleaner if we can assume that the
+ * only client which will fiddle with IFF_PROMISC is BPF. This is
+ * probably a good assumption, but we do not make it here. (Yet.)
+ */
+static inline int check_eh(struct ie_softc *ie,
+ struct ether_header *eh,
+ int *to_bpf) {
+ int i;
+
+ switch(ie->promisc) {
+ case IFF_ALLMULTI:
+ /*
+ * Receiving all multicasts, but no unicasts except those destined for us.
+ */
+#if NBPFILTER > 0
+ *to_bpf = (ie->ie_bpf != 0); /* BPF gets this packet if anybody cares */
+#endif
+ if(eh->ether_dhost[0] & 1) {
+ return 1;
+ }
+ if(ether_equal(eh->ether_dhost, ie->arpcom.ac_enaddr)) return 1;
+ return 0;
+
+ case IFF_PROMISC:
+ /*
+ * Receiving all packets. These need to be passed on to BPF.
+ */
+#if NBPFILTER > 0
+ *to_bpf = (ie->ie_bpf != 0);
+#endif
+ /* If for us, accept and hand up to BPF */
+ if(ether_equal(eh->ether_dhost, ie->arpcom.ac_enaddr)) return 1;
+
+#if NBPFILTER > 0
+ if(*to_bpf) *to_bpf = 2; /* we don't need to see it */
+#endif
+
+#ifdef MULTICAST
+ /*
+ * Not a multicast, so BPF wants to see it but we don't.
+ */
+ if(!(eh->ether_dhost[0] & 1)) return 1;
+
+ /*
+ * If it's one of our multicast groups, accept it and pass it
+ * up.
+ */
+ for(i = 0; i < ie->mcast_count; i++) {
+ if(ether_equal(eh->ether_dhost, (u_char *)&ie->mcast_addrs[i])) {
+#if NBPFILTER > 0
+ if(*to_bpf) *to_bpf = 1;
+#endif
+ return 1;
+ }
+ }
+#endif /* MULTICAST */
+ return 1;
+
+ case IFF_ALLMULTI | IFF_PROMISC:
+ /*
+ * Acting as a multicast router, and BPF running at the same time.
+ * Whew! (Hope this is a fast machine...)
+ */
+#if NBPFILTER > 0
+ *to_bpf = (ie->ie_bpf != 0);
+#endif
+ /* We want to see multicasts. */
+ if(eh->ether_dhost[0] & 1) return 1;
+
+ /* We want to see our own packets */
+ if(ether_equal(eh->ether_dhost, ie->arpcom.ac_enaddr)) return 1;
+
+ /* Anything else goes to BPF but nothing else. */
+#if NBPFILTER > 0
+ if(*to_bpf) *to_bpf = 2;
+#endif
+ return 1;
+
+ default:
+ /*
+ * Only accept unicast packets destined for us, or multicasts
+ * for groups that we belong to. For now, we assume that the
+ * '586 will only return packets that we asked it for. This
+ * isn't strictly true (it uses hashing for the multicast filter),
+ * but it will do in this case, and we want to get out of here
+ * as quickly as possible.
+ */
+#if NBPFILTER > 0
+ *to_bpf = (ie->ie_bpf != 0);
+#endif
+ return 1;
+ }
+ return 0;
+}
+#endif /* FILTER */
+
+/*
+ * We want to isolate the bits that have meaning... This assumes that
+ * IE_RBUF_SIZE is an even power of two. If somehow the act_len exceeds
+ * the size of the buffer, then we are screwed anyway.
+ */
+static inline int ie_buflen(struct ie_softc *ie, int head) {
+ return (ie->rbuffs[head]->ie_rbd_actual
+ & (IE_RBUF_SIZE | (IE_RBUF_SIZE - 1)));
+}
+
+static inline int ie_packet_len(int unit, struct ie_softc *ie) {
+ int i;
+ int head = ie->rbhead;
+ int acc = 0;
+
+ do {
+ if(!(ie->rbuffs[ie->rbhead]->ie_rbd_actual & IE_RBD_USED)) {
+#ifdef DEBUG
+ print_rbd(ie->rbuffs[ie->rbhead]);
+#endif
+ log(LOG_ERR, "ie%d: receive descriptors out of sync at %d\n",
+ unit, ie->rbhead);
+ iereset(unit);
+ return -1;
+ }
+
+ i = ie->rbuffs[head]->ie_rbd_actual & IE_RBD_LAST;
+
+ acc += ie_buflen(ie, head);
+ head = (head + 1) % NBUFFS;
+ } while(!i);
+
+ return acc;
+}
+
+/*
+ * Read data off the interface, and turn it into an mbuf chain.
+ *
+ * This code is DRAMATICALLY different from the previous version; this
+ * version tries to allocate the entire mbuf chain up front, given the
+ * length of the data available. This enables us to allocate mbuf
+ * clusters in many situations where before we would have had a long
+ * chain of partially-full mbufs. This should help to speed up the
+ * operation considerably. (Provided that it works, of course.)
+ */
+static inline int ieget(unit, ie, mp, ehp, to_bpf)
+ int unit;
+ struct ie_softc *ie;
+ struct mbuf **mp;
+ struct ether_header *ehp;
+ int *to_bpf;
+{
+ struct mbuf *m, *top, **mymp;
+ int i;
+ int offset;
+ int totlen, resid;
+ int thismboff;
+ int head;
+
+ totlen = ie_packet_len(unit, ie);
+ if(totlen <= 0) return -1;
+
+ i = ie->rbhead;
+
+ /*
+ * Snarf the Ethernet header.
+ */
+ bcopy((caddr_t)ie->cbuffs[i], (caddr_t)ehp, sizeof *ehp);
+ /* ignore cast-qual warning here */
+
+ /*
+ * As quickly as possible, check if this packet is for us.
+ * If not, don't waste a single cycle copying the rest of the
+ * packet in.
+ * This is only a consideration when FILTER is defined; i.e., when
+ * we are either running BPF or doing multicasting.
+ */
+#ifdef FILTER
+ if(!check_eh(ie, ehp, to_bpf)) {
+ ie_drop_packet_buffer(unit, ie);
+ ie->arpcom.ac_if.if_ierrors--; /* just this case, it's not an error */
+ return -1;
+ }
+#endif
+ totlen -= (offset = sizeof *ehp);
+
+ MGETHDR(*mp, M_DONTWAIT, MT_DATA);
+ if(!*mp) {
+ ie_drop_packet_buffer(unit, ie);
+ return -1;
+ }
+
+ m = *mp;
+ m->m_pkthdr.rcvif = &ie->arpcom.ac_if;
+ m->m_len = MHLEN;
+ resid = m->m_pkthdr.len = totlen;
+ top = 0;
+ mymp = &top;
+
+ /*
+ * This loop goes through and allocates mbufs for all the data we will
+ * be copying in. It does not actually do the copying yet.
+ */
+ do { /* while(resid > 0) */
+ /*
+ * Try to allocate an mbuf to hold the data that we have. If we
+ * already allocated one, just get another one and stick it on the
+ * end (eventually). If we don't already have one, try to allocate
+ * an mbuf cluster big enough to hold the whole packet, if we think it's
+ * reasonable, or a single mbuf which may or may not be big enough.
+ * Got that?
+ */
+ if(top) {
+ MGET(m, M_DONTWAIT, MT_DATA);
+ if(!m) {
+ m_freem(top);
+ ie_drop_packet_buffer(unit, ie);
+ return -1;
+ }
+ m->m_len = MLEN;
+ }
+
+ if(resid >= MINCLSIZE) {
+ MCLGET(m, M_DONTWAIT);
+ if(m->m_flags & M_EXT)
+ m->m_len = min(resid, MCLBYTES);
+ } else {
+ if(resid < m->m_len) {
+ if(!top && resid + max_linkhdr <= m->m_len)
+ m->m_data += max_linkhdr;
+ m->m_len = resid;
+ }
+ }
+ resid -= m->m_len;
+ *mymp = m;
+ mymp = &m->m_next;
+ } while(resid > 0);
+
+ resid = totlen;
+ m = top;
+ thismboff = 0;
+ head = ie->rbhead;
+
+ /*
+ * Now we take the mbuf chain (hopefully only one mbuf most of the
+ * time) and stuff the data into it. There are no possible failures
+ * at or after this point.
+ */
+ while(resid > 0) { /* while there's stuff left */
+ int thislen = ie_buflen(ie, head) - offset;
+
+ /*
+ * If too much data for the current mbuf, then fill the current one
+ * up, go to the next one, and try again.
+ */
+ if(thislen > m->m_len - thismboff) {
+ int newlen = m->m_len - thismboff;
+ bcopy((caddr_t)(ie->cbuffs[head] + offset),
+ mtod(m, caddr_t) + thismboff, (unsigned)newlen);
+ /* ignore cast-qual warning */
+ m = m->m_next;
+ thismboff = 0; /* new mbuf, so no offset */
+ offset += newlen; /* we are now this far into the packet */
+ resid -= newlen; /* so there is this much left to get */
+ continue;
+ }
+
+ /*
+ * If there is more than enough space in the mbuf to hold the
+ * contents of this buffer, copy everything in, advance pointers,
+ * and so on.
+ */
+ if(thislen < m->m_len - thismboff) {
+ bcopy((caddr_t)(ie->cbuffs[head] + offset), /* ignore warning */
+ mtod(m, caddr_t) + thismboff, (unsigned)thislen);
+ thismboff += thislen; /* we are this far into the mbuf */
+ resid -= thislen; /* and this much is left */
+ goto nextbuf;
+ }
+
+ /*
+ * Otherwise, there is exactly enough space to put this buffer's
+ * contents into the current mbuf. Do the combination of the above
+ * actions.
+ */
+ bcopy((caddr_t)(ie->cbuffs[head] + offset), /* ignore warning */
+ mtod(m, caddr_t) + thismboff, (unsigned)thislen);
+ m = m->m_next;
+ thismboff = 0; /* new mbuf, start at the beginning */
+ resid -= thislen; /* and we are this far through */
+
+ /*
+ * Advance all the pointers. We can get here from either of the
+ * last two cases, but never the first.
+ */
+nextbuf:
+ offset = 0;
+ ie->rbuffs[head]->ie_rbd_actual = 0;
+ ie->rbuffs[head]->ie_rbd_length |= IE_RBD_LAST;
+ ie->rbhead = head = (head + 1) % NBUFFS;
+ ie->rbuffs[ie->rbtail]->ie_rbd_length &= ~IE_RBD_LAST;
+ ie->rbtail = (ie->rbtail + 1) % NBUFFS;
+ }
+
+ /*
+ * Unless something changed strangely while we were doing the copy,
+ * we have now copied everything in from the shared memory.
+ * This means that we are done.
+ */
+ return 0;
+}
+
+/*
+ * Read frame NUM from unit UNIT (pre-cached as IE).
+ *
+ * This routine reads the RFD at NUM, and copies in the buffers from
+ * the list of RBD, then rotates the RBD and RFD lists so that the receiver
+ * doesn't start complaining. Trailers are DROPPED---there's no point
+ * in wasting time on confusing code to deal with them. Hopefully,
+ * this machine will never ARP for trailers anyway.
+ */
+static void ie_readframe(unit, ie, num)
+ int unit;
+ struct ie_softc *ie;
+ int num; /* frame number to read */
+{
+ struct ie_recv_frame_desc rfd;
+ struct mbuf *m = 0;
+ struct ether_header eh;
+#if NBPFILTER > 0
+ int bpf_gets_it = 0;
+#endif
+
+ bcopy((caddr_t)(ie->rframes[num]), &rfd, sizeof(struct ie_recv_frame_desc));
+
+ /* Immediately advance the RFD list, since we we have copied ours now. */
+ ie->rframes[num]->ie_fd_status = 0;
+ ie->rframes[num]->ie_fd_last |= IE_FD_LAST;
+ ie->rframes[ie->rftail]->ie_fd_last &= ~IE_FD_LAST;
+ ie->rftail = (ie->rftail + 1) % NFRAMES;
+ ie->rfhead = (ie->rfhead + 1) % NFRAMES;
+
+ if(rfd.ie_fd_status & IE_FD_OK) {
+ if(
+#if NBPFILTER > 0
+ ieget(unit, ie, &m, &eh, &bpf_gets_it)
+#else
+ ieget(unit, ie, &m, &eh, (int *)0)
+#endif
+ ) {
+ ie->arpcom.ac_if.if_ierrors++; /* this counts as an error */
+ return;
+ }
+ }
+
+#ifdef DEBUG
+ if(ie_debug & IED_READFRAME) {
+ printf("ie%d: frame from ether %s type %x\n", unit,
+ ether_sprintf(eh.ether_shost), (unsigned)eh.ether_type);
+ }
+ if(ntohs(eh.ether_type) > ETHERTYPE_TRAIL
+ && ntohs(eh.ether_type) < (ETHERTYPE_TRAIL + ETHERTYPE_NTRAILER))
+ printf("received trailer!\n");
+#endif
+
+ if(!m) return;
+
+#ifdef FILTER
+ if(last_not_for_us) {
+ m_freem(last_not_for_us);
+ last_not_for_us = 0;
+ }
+
+#if NBPFILTER > 0
+ /*
+ * Check for a BPF filter; if so, hand it up.
+ * Note that we have to stick an extra mbuf up front, because
+ * bpf_mtap expects to have the ether header at the front.
+ * It doesn't matter that this results in an ill-formatted mbuf chain,
+ * since BPF just looks at the data. (It doesn't try to free the mbuf,
+ * tho' it will make a copy for tcpdump.)
+ */
+ if(bpf_gets_it) {
+ struct mbuf m0;
+ m0.m_len = sizeof eh;
+ m0.m_data = (caddr_t)&eh;
+ m0.m_next = m;
+
+ /* Pass it up */
+ bpf_mtap(ie->ie_bpf, &m0);
+ }
+ /*
+ * A signal passed up from the filtering code indicating that the
+ * packet is intended for BPF but not for the protocol machinery.
+ * We can save a few cycles by not handing it off to them.
+ */
+ if(bpf_gets_it == 2) {
+ last_not_for_us = m;
+ return;
+ }
+#endif /* NBPFILTER > 0 */
+ /*
+ * In here there used to be code to check destination addresses upon
+ * receipt of a packet. We have deleted that code, and replaced it
+ * with code to check the address much earlier in the cycle, before
+ * copying the data in; this saves us valuable cycles when operating
+ * as a multicast router or when using BPF.
+ */
+#endif /* FILTER */
+
+ eh.ether_type = ntohs(eh.ether_type);
+
+ /*
+ * Finally pass this packet up to higher layers.
+ */
+ ether_input(&ie->arpcom.ac_if, &eh, m);
+}
+
+static void ie_drop_packet_buffer(int unit, struct ie_softc *ie) {
+ int i;
+
+ do {
+ /*
+ * This means we are somehow out of sync. So, we reset the
+ * adapter.
+ */
+ if(!(ie->rbuffs[ie->rbhead]->ie_rbd_actual & IE_RBD_USED)) {
+#ifdef DEBUG
+ print_rbd(ie->rbuffs[ie->rbhead]);
+#endif
+ log(LOG_ERR, "ie%d: receive descriptors out of sync at %d\n",
+ unit, ie->rbhead);
+ iereset(unit);
+ return;
+ }
+
+ i = ie->rbuffs[ie->rbhead]->ie_rbd_actual & IE_RBD_LAST;
+
+ ie->rbuffs[ie->rbhead]->ie_rbd_length |= IE_RBD_LAST;
+ ie->rbuffs[ie->rbhead]->ie_rbd_actual = 0;
+ ie->rbhead = (ie->rbhead + 1) % NBUFFS;
+ ie->rbuffs[ie->rbtail]->ie_rbd_length &= ~IE_RBD_LAST;
+ ie->rbtail = (ie->rbtail + 1) % NBUFFS;
+ } while(!i);
+}
+
+
+/*
+ * Start transmission on an interface.
+ */
+static void
+iestart(ifp)
+ struct ifnet *ifp;
+{
+ struct ie_softc *ie = &ie_softc[ifp->if_unit];
+ struct mbuf *m0, *m;
+ unsigned char *buffer;
+ u_short len;
+ /* This is not really volatile, in this routine, but it makes gcc happy. */
+ volatile u_short *bptr = &ie->scb->ie_command_list;
+
+ if(!(ifp->if_flags & IFF_RUNNING))
+ return;
+ if(ifp->if_flags & IFF_OACTIVE)
+ return;
+
+ do {
+ IF_DEQUEUE(&ie->arpcom.ac_if.if_snd, m);
+ if(!m)
+ break;
+
+ buffer = ie->xmit_cbuffs[ie->xmit_count];
+ len = 0;
+
+ for(m0 = m; m && len < IE_BUF_LEN; m = m->m_next) {
+ bcopy(mtod(m, caddr_t), buffer, m->m_len);
+ buffer += m->m_len;
+ len += m->m_len;
+ }
+
+ m_freem(m0);
+ len = max(len, ETHERMINLEN);
+
+#if NBPFILTER > 0
+ /*
+ * See if bpf is listening on this interface, let it see the packet
+ * before we commit it to the wire.
+ */
+ if(ie->ie_bpf)
+ bpf_tap(ie->ie_bpf, ie->xmit_cbuffs[ie->xmit_count], len);
+#endif
+
+ ie->xmit_buffs[ie->xmit_count]->ie_xmit_flags = IE_XMIT_LAST | len;
+ ie->xmit_buffs[ie->xmit_count]->ie_xmit_next = 0xffff;
+ ie->xmit_buffs[ie->xmit_count]->ie_xmit_buf =
+ MK_24(ie->iomem, ie->xmit_cbuffs[ie->xmit_count]);
+
+ ie->xmit_cmds[ie->xmit_count]->com.ie_cmd_cmd = IE_CMD_XMIT;
+ ie->xmit_cmds[ie->xmit_count]->ie_xmit_status = 0;
+ ie->xmit_cmds[ie->xmit_count]->ie_xmit_desc =
+ MK_16(ie->iomem, ie->xmit_buffs[ie->xmit_count]);
+
+ *bptr = MK_16(ie->iomem, ie->xmit_cmds[ie->xmit_count]);
+ bptr = &ie->xmit_cmds[ie->xmit_count]->com.ie_cmd_link;
+ ie->xmit_count++;
+ } while(ie->xmit_count < 2);
+
+ /*
+ * If we queued up anything for transmission, send it.
+ */
+ if(ie->xmit_count) {
+ ie->xmit_cmds[ie->xmit_count - 1]->com.ie_cmd_cmd |=
+ IE_CMD_LAST | IE_CMD_INTR;
+
+ /*
+ * By passing the command pointer as a null, we tell
+ * command_and_wait() to pretend that this isn't an action
+ * command. I wish I understood what was happening here.
+ */
+ command_and_wait(ifp->if_unit, IE_CU_START, 0, 0);
+ ifp->if_flags |= IFF_OACTIVE;
+ }
+
+ return;
+}
+
+/*
+ * Check to see if there's an 82586 out there.
+ */
+int check_ie_present(unit, where, size)
+ int unit;
+ caddr_t where;
+ unsigned size;
+{
+ volatile struct ie_sys_conf_ptr *scp;
+ volatile struct ie_int_sys_conf_ptr *iscp;
+ volatile struct ie_sys_ctl_block *scb;
+ u_long realbase;
+ int s;
+
+ s = splimp();
+
+ realbase = (u_long)where + size - (1 << 24);
+
+ scp = (volatile struct ie_sys_conf_ptr *)(realbase + IE_SCP_ADDR);
+ bzero((char *)scp, sizeof *scp); /* ignore cast-qual */
+
+ /*
+ * First we put the ISCP at the bottom of memory; this tests to make
+ * sure that our idea of the size of memory is the same as the controller's.
+ * This is NOT where the ISCP will be in normal operation.
+ */
+ iscp = (volatile struct ie_int_sys_conf_ptr *)where;
+ bzero((char *)iscp, sizeof *iscp); /* ignore cast-qual */
+
+ scb = (volatile struct ie_sys_ctl_block *)where;
+ bzero((char *)scb, sizeof *scb); /* ignore cast-qual */
+
+ scp->ie_bus_use = 0; /* 16-bit */
+ scp->ie_iscp_ptr = (caddr_t)((volatile caddr_t)iscp - /* ignore cast-qual */
+ (volatile caddr_t)realbase);
+
+ iscp->ie_busy = 1;
+ iscp->ie_scb_offset = MK_16(realbase, scb) + 256;
+
+ (*ie_softc[unit].ie_reset_586)(unit);
+ (*ie_softc[unit].ie_chan_attn)(unit);
+
+ DELAY(100); /* wait a while... */
+
+ if(iscp->ie_busy) {
+ splx(s);
+ return 0;
+ }
+
+ /*
+ * Now relocate the ISCP to its real home, and reset the controller
+ * again.
+ */
+ iscp = (void *)Align((caddr_t)(realbase + IE_SCP_ADDR -
+ sizeof(struct ie_int_sys_conf_ptr)));
+ bzero((char *)iscp, sizeof *iscp); /* ignore cast-qual */
+
+ scp->ie_iscp_ptr = (caddr_t)((caddr_t)iscp - (caddr_t)realbase);
+ /* ignore cast-qual */
+
+ iscp->ie_busy = 1;
+ iscp->ie_scb_offset = MK_16(realbase, scb);
+
+ (*ie_softc[unit].ie_reset_586)(unit);
+ (*ie_softc[unit].ie_chan_attn)(unit);
+
+ DELAY(100);
+
+ if(iscp->ie_busy) {
+ splx(s);
+ return 0;
+ }
+
+ ie_softc[unit].iosize = size;
+ ie_softc[unit].iomem = (caddr_t)realbase;
+
+ ie_softc[unit].iscp = iscp;
+ ie_softc[unit].scb = scb;
+
+ /*
+ * Acknowledge any interrupts we may have caused...
+ */
+ ie_ack(scb, IE_ST_WHENCE, unit, ie_softc[unit].ie_chan_attn);
+ splx(s);
+
+ return 1;
+}
+
+/*
+ * Divine the memory size of ie board UNIT.
+ * Better hope there's nothing important hiding just below the ie card...
+ */
+static void find_ie_mem_size(unit)
+ int unit;
+{
+ unsigned size;
+
+ ie_softc[unit].iosize = 0;
+
+ for(size = 65536; size >= 16384; size -= 16384) {
+ if(check_ie_present(unit, ie_softc[unit].iomembot, size)) {
+ return;
+ }
+ }
+
+ return;
+}
+
+void sl_reset_586(unit)
+ int unit;
+{
+ outb(PORT + IEATT_RESET, 0);
+}
+
+void sl_chan_attn(unit)
+ int unit;
+{
+ outb(PORT + IEATT_ATTN, 0);
+}
+
+void sl_read_ether(unit, addr)
+ int unit;
+ unsigned char addr[6];
+{
+ int i;
+
+ for(i = 0; i < 6; i++)
+ addr[i] = inb(PORT + i);
+}
+
+
+static void
+iereset(unit)
+ int unit;
+{
+ int s = splimp();
+
+ if(unit >= NIE) {
+ splx(s);
+ return;
+ }
+
+ printf("ie%d: reset\n", unit);
+ ie_softc[unit].arpcom.ac_if.if_flags &= ~IFF_UP;
+ ieioctl(&ie_softc[unit].arpcom.ac_if, SIOCSIFFLAGS, 0);
+
+ /*
+ * Stop i82586 dead in its tracks.
+ */
+ if(command_and_wait(unit, IE_RU_ABORT | IE_CU_ABORT, 0, 0))
+ printf("ie%d: abort commands timed out\n", unit);
+
+ if(command_and_wait(unit, IE_RU_DISABLE | IE_CU_STOP, 0, 0))
+ printf("ie%d: disable commands timed out\n", unit);
+
+#ifdef notdef
+ if(!check_ie_present(unit, ie_softc[unit].iomembot, ie_softc[unit].iosize))
+ panic("ie disappeared!\n");
+#endif
+
+ ie_softc[unit].arpcom.ac_if.if_flags |= IFF_UP;
+ ieioctl(&ie_softc[unit].arpcom.ac_if, SIOCSIFFLAGS, 0);
+
+ splx(s);
+ return;
+}
+
+/*
+ * This is called if we time out.
+ */
+static void
+chan_attn_timeout(rock)
+ caddr_t rock;
+{
+ *(int *)rock = 1;
+}
+
+/*
+ * Send a command to the controller and wait for it to either
+ * complete or be accepted, depending on the command. If the
+ * command pointer is null, then pretend that the command is
+ * not an action command. If the command pointer is not null,
+ * and the command is an action command, wait for
+ * ((volatile struct ie_cmd_common *)pcmd)->ie_cmd_status & MASK
+ * to become true.
+ */
+static int command_and_wait(unit, cmd, pcmd, mask)
+ int unit;
+ int cmd;
+ volatile void *pcmd;
+ int mask;
+{
+ volatile struct ie_cmd_common *cc = pcmd;
+ volatile int timedout = 0;
+ extern int hz;
+
+ ie_softc[unit].scb->ie_command = (u_short)cmd;
+
+ if(IE_ACTION_COMMAND(cmd) && pcmd) {
+ (*ie_softc[unit].ie_chan_attn)(unit);
+
+ /*
+ * According to the packet driver, the minimum timeout should be
+ * .369 seconds, which we round up to .37.
+ */
+ timeout(chan_attn_timeout, (caddr_t)&timedout, 37 * hz / 100);
+ /* ignore cast-qual */
+
+ /*
+ * Now spin-lock waiting for status. This is not a very nice
+ * thing to do, but I haven't figured out how, or indeed if, we
+ * can put the process waiting for action to sleep. (We may
+ * be getting called through some other timeout running in the
+ * kernel.)
+ */
+ while(1) {
+ if((cc->ie_cmd_status & mask) || timedout)
+ break;
+ }
+
+ untimeout(chan_attn_timeout, (caddr_t)&timedout);
+ /* ignore cast-qual */
+
+ return timedout;
+ } else {
+
+ /*
+ * Otherwise, just wait for the command to be accepted.
+ */
+ (*ie_softc[unit].ie_chan_attn)(unit);
+
+ while(ie_softc[unit].scb->ie_command)
+ ; /* spin lock */
+
+ return 0;
+ }
+}
+
+/*
+ * Run the time-domain reflectometer...
+ */
+static void run_tdr(unit, cmd)
+ int unit;
+ struct ie_tdr_cmd *cmd;
+{
+ int result;
+
+ cmd->com.ie_cmd_status = 0;
+ cmd->com.ie_cmd_cmd = IE_CMD_TDR | IE_CMD_LAST;
+ cmd->com.ie_cmd_link = 0xffff;
+ cmd->ie_tdr_time = 0;
+
+ ie_softc[unit].scb->ie_command_list = MK_16(MEM, cmd);
+ cmd->ie_tdr_time = 0;
+
+ if(command_and_wait(unit, IE_CU_START, cmd, IE_STAT_COMPL))
+ result = 0x2000;
+ else
+ result = cmd->ie_tdr_time;
+
+ ie_ack(ie_softc[unit].scb, IE_ST_WHENCE, unit,
+ ie_softc[unit].ie_chan_attn);
+
+ if(result & IE_TDR_SUCCESS)
+ return;
+
+ if(result & IE_TDR_XCVR) {
+ printf("ie%d: transceiver problem\n", unit);
+ } else if(result & IE_TDR_OPEN) {
+ printf("ie%d: TDR detected an open %d clocks away\n", unit,
+ result & IE_TDR_TIME);
+ } else if(result & IE_TDR_SHORT) {
+ printf("ie%d: TDR detected a short %d clocks away\n", unit,
+ result & IE_TDR_TIME);
+ } else {
+ printf("ie%d: TDR returned unknown status %x\n", result);
+ }
+}
+
+static void start_receiver(unit)
+ int unit;
+{
+ int s = splimp();
+
+ ie_softc[unit].scb->ie_recv_list = MK_16(MEM, ie_softc[unit].rframes[0]);
+ command_and_wait(unit, IE_RU_START, 0, 0);
+
+ ie_ack(ie_softc[unit].scb, IE_ST_WHENCE, unit, ie_softc[unit].ie_chan_attn);
+
+ splx(s);
+}
+
+/*
+ * Here is a helper routine for iernr() and ieinit(). This sets up
+ * the RFA.
+ */
+static caddr_t setup_rfa(caddr_t ptr, struct ie_softc *ie) {
+ volatile struct ie_recv_frame_desc *rfd = (void *)ptr;
+ volatile struct ie_recv_buf_desc *rbd;
+ int i;
+ int unit = ie - &ie_softc[0];
+
+ /* First lay them out */
+ for(i = 0; i < NFRAMES; i++) {
+ ie->rframes[i] = rfd;
+ bzero((char *)rfd, sizeof *rfd); /* ignore cast-qual */
+ rfd++;
+ }
+
+ ptr = (caddr_t)Align((caddr_t)rfd); /* ignore cast-qual */
+
+ /* Now link them together */
+ for(i = 0; i < NFRAMES; i++) {
+ ie->rframes[i]->ie_fd_next =
+ MK_16(MEM, ie->rframes[(i + 1) % NFRAMES]);
+ }
+
+ /* Finally, set the EOL bit on the last one. */
+ ie->rframes[NFRAMES - 1]->ie_fd_last |= IE_FD_LAST;
+
+ /*
+ * Now lay out some buffers for the incoming frames. Note that
+ * we set aside a bit of slop in each buffer, to make sure that
+ * we have enough space to hold a single frame in every buffer.
+ */
+ rbd = (void *)ptr;
+
+ for(i = 0; i < NBUFFS; i++) {
+ ie->rbuffs[i] = rbd;
+ bzero((char *)rbd, sizeof *rbd); /* ignore cast-qual */
+ ptr = (caddr_t)Align(ptr + sizeof *rbd);
+ rbd->ie_rbd_length = IE_RBUF_SIZE;
+ rbd->ie_rbd_buffer = MK_24(MEM, ptr);
+ ie->cbuffs[i] = (void *)ptr;
+ ptr += IE_RBUF_SIZE;
+ rbd = (void *)ptr;
+ }
+
+ /* Now link them together */
+ for(i = 0; i < NBUFFS; i++) {
+ ie->rbuffs[i]->ie_rbd_next = MK_16(MEM, ie->rbuffs[(i + 1) % NBUFFS]);
+ }
+
+ /* Tag EOF on the last one */
+ ie->rbuffs[NBUFFS - 1]->ie_rbd_length |= IE_RBD_LAST;
+
+ /* We use the head and tail pointers on receive to keep track of
+ * the order in which RFDs and RBDs are used. */
+ ie->rfhead = 0;
+ ie->rftail = NFRAMES - 1;
+ ie->rbhead = 0;
+ ie->rbtail = NBUFFS - 1;
+
+ ie->scb->ie_recv_list = MK_16(MEM, ie->rframes[0]);
+ ie->rframes[0]->ie_fd_buf_desc = MK_16(MEM, ie->rbuffs[0]);
+
+ ptr = Align(ptr);
+ return ptr;
+}
+
+/*
+ * Run the multicast setup command.
+ * Call at splimp().
+ */
+static int mc_setup(int unit, caddr_t ptr,
+ volatile struct ie_sys_ctl_block *scb) {
+ struct ie_softc *ie = &ie_softc[unit];
+ volatile struct ie_mcast_cmd *cmd = (void *)ptr;
+
+ cmd->com.ie_cmd_status = 0;
+ cmd->com.ie_cmd_cmd = IE_CMD_MCAST | IE_CMD_LAST;
+ cmd->com.ie_cmd_link = 0xffff;
+
+ /* ignore cast-qual */
+ bcopy((caddr_t)ie->mcast_addrs, (caddr_t)cmd->ie_mcast_addrs,
+ ie->mcast_count * sizeof *ie->mcast_addrs);
+
+ cmd->ie_mcast_bytes = ie->mcast_count * 6; /* grrr... */
+
+ scb->ie_command_list = MK_16(MEM, cmd);
+ if(command_and_wait(unit, IE_CU_START, cmd, IE_STAT_COMPL)
+ || !(cmd->com.ie_cmd_status & IE_STAT_OK)) {
+ printf("ie%d: multicast address setup command failed\n", unit);
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * This routine takes the environment generated by check_ie_present()
+ * and adds to it all the other structures we need to operate the adapter.
+ * This includes executing the CONFIGURE, IA-SETUP, and MC-SETUP commands,
+ * starting the receiver unit, and clearing interrupts.
+ *
+ * THIS ROUTINE MUST BE CALLED AT splimp() OR HIGHER.
+ */
+static void
+ieinit(unit)
+ int unit;
+{
+ struct ie_softc *ie = &ie_softc[unit];
+ volatile struct ie_sys_ctl_block *scb = ie->scb;
+ caddr_t ptr;
+
+ ptr = (caddr_t)Align((caddr_t)scb + sizeof *scb); /* ignore cast-qual */
+
+ /*
+ * Send the configure command first.
+ */
+ {
+ volatile struct ie_config_cmd *cmd = (void *)ptr;
+
+ ie_setup_config(cmd, ie->promisc, ie->hard_type == IE_STARLAN10);
+ cmd->com.ie_cmd_status = 0;
+ cmd->com.ie_cmd_cmd = IE_CMD_CONFIG | IE_CMD_LAST;
+ cmd->com.ie_cmd_link = 0xffff;
+
+ scb->ie_command_list = MK_16(MEM, cmd);
+
+ if(command_and_wait(unit, IE_CU_START, cmd, IE_STAT_COMPL)
+ || !(cmd->com.ie_cmd_status & IE_STAT_OK)) {
+ printf("ie%d: configure command failed\n", unit);
+ return;
+ }
+ }
+ /*
+ * Now send the Individual Address Setup command.
+ */
+ {
+ volatile struct ie_iasetup_cmd *cmd = (void *)ptr;
+
+ cmd->com.ie_cmd_status = 0;
+ cmd->com.ie_cmd_cmd = IE_CMD_IASETUP | IE_CMD_LAST;
+ cmd->com.ie_cmd_link = 0xffff;
+
+ bcopy((char *)ie_softc[unit].arpcom.ac_enaddr, (char *)&cmd->ie_address,
+ sizeof cmd->ie_address); /* ignore cast-qual */
+
+ scb->ie_command_list = MK_16(MEM, cmd);
+ if(command_and_wait(unit, IE_CU_START, cmd, IE_STAT_COMPL)
+ || !(cmd->com.ie_cmd_status & IE_STAT_OK)) {
+ printf("ie%d: individual address setup command failed\n", unit);
+ return;
+ }
+ }
+
+ /*
+ * Now run the time-domain reflectometer.
+ */
+ run_tdr(unit, (void *)ptr);
+
+ /*
+ * Acknowledge any interrupts we have generated thus far.
+ */
+ ie_ack(ie->scb, IE_ST_WHENCE, unit, ie->ie_chan_attn);
+
+ /*
+ * Set up the RFA.
+ */
+ ptr = setup_rfa(ptr, ie);
+
+ /*
+ * Finally, the transmit command and buffer are the last little bit of work.
+ */
+ ie->xmit_cmds[0] = (void *)ptr;
+ ptr += sizeof *ie->xmit_cmds[0];
+ ptr = Align(ptr);
+ ie->xmit_buffs[0] = (void *)ptr;
+ ptr += sizeof *ie->xmit_buffs[0];
+ ptr = Align(ptr);
+
+ /* Second transmit command */
+ ie->xmit_cmds[1] = (void *)ptr;
+ ptr += sizeof *ie->xmit_cmds[1];
+ ptr = Align(ptr);
+ ie->xmit_buffs[1] = (void *)ptr;
+ ptr += sizeof *ie->xmit_buffs[1];
+ ptr = Align(ptr);
+
+ /* Both transmit buffers */
+ ie->xmit_cbuffs[0] = (void *)ptr;
+ ptr += IE_BUF_LEN;
+ ptr = Align(ptr);
+ ie->xmit_cbuffs[1] = (void *)ptr;
+
+ bzero((caddr_t)ie->xmit_cmds[0], sizeof *ie->xmit_cmds[0]); /* ignore */
+ bzero((caddr_t)ie->xmit_buffs[0], sizeof *ie->xmit_buffs[0]); /* cast-qual */
+ bzero((caddr_t)ie->xmit_cmds[1], sizeof *ie->xmit_cmds[0]); /* warnings */
+ bzero((caddr_t)ie->xmit_buffs[1], sizeof *ie->xmit_buffs[0]); /* here */
+
+ /*
+ * This must be coordinated with iestart() and ietint().
+ */
+ ie->xmit_cmds[0]->ie_xmit_status = IE_STAT_COMPL;
+
+ ie->arpcom.ac_if.if_flags |= IFF_RUNNING; /* tell higher levels that we are here */
+ start_receiver(unit);
+ return;
+}
+
+static void ie_stop(unit)
+ int unit;
+{
+ command_and_wait(unit, IE_RU_DISABLE, 0, 0);
+}
+
+static int
+ieioctl(ifp, command, data)
+ struct ifnet *ifp;
+ int command;
+ caddr_t data;
+{
+ struct ifaddr *ifa = (struct ifaddr *)data;
+ struct ie_softc *ie = &ie_softc[ifp->if_unit];
+ int s, error = 0;
+
+ s = splimp();
+
+ switch(command) {
+ case SIOCSIFADDR:
+ ifp->if_flags |= IFF_UP;
+
+ switch(ifa->ifa_addr->sa_family) {
+#ifdef INET
+ case AF_INET:
+ ieinit(ifp->if_unit);
+ ((struct arpcom *)ifp)->ac_ipaddr =
+ IA_SIN(ifa)->sin_addr;
+ arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
+ break;
+#endif /* INET */
+
+#ifdef NS
+ /* This magic copied from if_is.c; I don't use XNS, so I have no
+ * way of telling if this actually works or not.
+ */
+ case AF_NS:
+ {
+ struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
+
+ if(ns_nullhost(*ina)) {
+ ina->x_host = *(union ns_host *)(ie->arpcom.ac_enaddr);
+ } else {
+ ifp->if_flags &= ~IFF_RUNNING;
+ bcopy((caddr_t)ina->x_host.c_host,
+ (caddr_t)ie->arpcom.ac_enaddr,
+ sizeof ie->arpcom.ac_enaddr);
+ }
+
+ ieinit(ifp->if_unit);
+ }
+ break;
+#endif /* NS */
+
+ default:
+ ieinit(ifp->if_unit);
+ break;
+ }
+ break;
+
+ case SIOCSIFFLAGS:
+ /*
+ * Note that this device doesn't have an "all multicast" mode, so we
+ * must turn on promiscuous mode and do the filtering manually.
+ */
+ if((ifp->if_flags & IFF_UP) == 0 &&
+ (ifp->if_flags & IFF_RUNNING)) {
+ ifp->if_flags &= ~IFF_RUNNING;
+ ie_stop(ifp->if_unit);
+ } else if((ifp->if_flags & IFF_UP) &&
+ (ifp->if_flags & IFF_RUNNING) == 0) {
+ ie_softc[ifp->if_unit].promisc =
+ ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI);
+ ieinit(ifp->if_unit);
+ } else if(ie_softc[ifp->if_unit].promisc ^
+ (ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI))) {
+ ie_softc[ifp->if_unit].promisc =
+ ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI);
+ ieinit(ifp->if_unit);
+ }
+ break;
+
+#ifdef MULTICAST
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ /*
+ * Update multicast listeners
+ */
+ error = ((command == SIOCADDMULTI)
+ ? ether_addmulti((struct ifreq *)data, &ie->arpcom)
+ : ether_delmulti((struct ifreq *)data, &ie->arpcom));
+
+ if(error == ENETRESET) {
+ /* reset multicast filtering */
+ ie_mc_reset(ifp->if_unit);
+ error = 0;
+ }
+ break;
+#endif /* MULTICAST */
+
+ default:
+ error = EINVAL;
+ }
+
+ splx(s);
+ return error;
+}
+
+#ifdef MULTICAST
+static void ie_mc_reset(int unit) {
+ struct ie_softc *ie = &ie_softc[unit];
+ struct ether_multi *enm;
+ struct ether_multistep step;
+
+ /*
+ * Step through the list of addresses.
+ */
+ ie->mcast_count = 0;
+ ETHER_FIRST_MULTI(step, &ie->arpcom, enm);
+ while(enm) {
+ if(ie->mcast_count >= MAXMCAST
+ || bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
+ ie->arpcom.ac_if.if_flags |= IFF_ALLMULTI;
+ ieioctl(&ie->arpcom.ac_if, SIOCSIFFLAGS, (void *)0);
+ goto setflag;
+ }
+
+ bcopy(enm->enm_addrlo, &(ie->mcast_addrs[ie->mcast_count]), 6);
+ ie->mcast_count++;
+ ETHER_NEXT_MULTI(step, enm);
+ }
+
+setflag:
+ ie->want_mcsetup = 1;
+}
+
+#endif
+
+#ifdef DEBUG
+void print_rbd(volatile struct ie_recv_buf_desc *rbd) {
+ printf("RBD at %08lx:\n"
+ "actual %04x, next %04x, buffer %08x\n"
+ "length %04x, mbz %04x\n",
+ (unsigned long)rbd,
+ rbd->ie_rbd_actual, rbd->ie_rbd_next, rbd->ie_rbd_buffer,
+ rbd->ie_rbd_length, rbd->mbz);
+}
+#endif /* DEBUG */
+#endif /* NIE > 0 */
+
diff --git a/sys/dev/ie/if_iereg.h b/sys/dev/ie/if_iereg.h
new file mode 100644
index 0000000..3588b84
--- /dev/null
+++ b/sys/dev/ie/if_iereg.h
@@ -0,0 +1,24 @@
+/*
+ * $Id$
+ * definitions for AT&T StarLAN 10 etc...
+ */
+
+#define IEATT_RESET 0 /* any write here resets the 586 */
+#define IEATT_ATTN 1 /* any write here sends a Chan attn */
+#define IEATT_REVISION 6 /* read here to figure out this board */
+#define IEATT_ATTRIB 7 /* more information about this board */
+
+#define SL_BOARD(x) ((x) & 0x0f)
+#define SL_REV(x) ((x) >> 4)
+
+#define SL1_BOARD 0
+#define SL10_BOARD 1
+#define EN100_BOARD 2
+#define SLFIBER_BOARD 3
+
+#define SL_ATTR_WIDTH 0x04 /* bus width: clear -> 8-bit */
+#define SL_ATTR_SPEED 0x08 /* medium speed: clear -> 10 Mbps */
+#define SL_ATTR_CODING 0x10 /* encoding: clear -> Manchester */
+#define SL_ATTR_HBW 0x20 /* host bus width: clear -> 16-bit */
+#define SL_ATTR_TYPE 0x40 /* medium type: clear -> Ethernet */
+#define SL_ATTR_BOOTROM 0x80 /* set -> boot ROM present */
diff --git a/sys/dev/kbd/kbdtables.h b/sys/dev/kbd/kbdtables.h
new file mode 100644
index 0000000..a923c45
--- /dev/null
+++ b/sys/dev/kbd/kbdtables.h
@@ -0,0 +1,859 @@
+/*
+ * Copyright (C) 1992, 1993, 1994 Søren Schmidt
+ *
+ * This program is free software; you may redistribute it and/or
+ * modify it, provided that it retain the above copyright notice
+ * and the following disclaimer.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Søren Schmidt Email: sos@login.dkuug.dk
+ * Tritonvej 36 UUCP: ...uunet!dkuug!login!sos
+ * DK9210 Aalborg SO Phone: +45 9814 8076
+ *
+ * @(#)kbdtables.h 1.3 940123
+ * $Id: kbdtables.h,v 1.11 1994/02/01 09:27:43 ache Exp $
+ */
+
+#define SET8 0x80 /* eight bit for emacs SET8-key */
+
+#ifdef DKKEYMAP
+keymap_t key_map = { 0x69, /* DK iso8859 keymap */
+/* alt
+ * scan cntrl alt alt cntrl
+ * code base shift cntrl shift alt shift cntrl shift spcl flgs
+ * ---------------------------------------------------------------------------
+ */
+/* sc=00 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=01 */ 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, DBG, 0x1B, 0x02, 0x00,
+/* sc=02 */ '1', '!', NOP, NOP, '1', '!', NOP, NOP, 0x33, 0x00,
+/* sc=03 */ '2', '"', 0x00, 0x00, '@', '"', 0x00, 0x00, 0x00, 0x00,
+/* sc=04 */ '3', '#', NOP, NOP, 0x9E, '#', NOP, NOP, 0x33, 0x00,
+/* sc=05 */ '4', 0xA4, NOP, NOP, '$', 0xA4, NOP, NOP, 0x33, 0x00,
+/* sc=06 */ '5', '%', NOP, NOP, '5', '%', NOP, NOP, 0x33, 0x00,
+/* sc=07 */ '6', '&', NOP, NOP, '6', '&', NOP, NOP, 0x33, 0x00,
+/* sc=08 */ '7', '/', NOP, NOP, '{', '/', NOP, NOP, 0x33, 0x00,
+/* sc=09 */ '8', '(', 0x1B, 0x1B, '[', '(', 0x1B, 0x1B, 0x00, 0x00,
+/* sc=0a */ '9', ')', 0x1D, 0x1D, ']', ')', 0x1D, 0x1D, 0x00, 0x00,
+/* sc=0b */ '0', '=', NOP, NOP, '}', '=', NOP, NOP, 0x33, 0x00,
+/* sc=0c */ '+', '?', NOP, NOP, '+', '?', NOP, NOP, 0x33, 0x00,
+/* sc=0d */ '\'', '`', NOP, NOP, '|', '`', NOP, NOP, 0x33, 0x00,
+/* sc=0e */ 0x7F, 0x7F, 0x08, 0x08, 0x7F, 0x7F, 0x08, 0x08, 0x00, 0x00,
+/* sc=0f */ 0x09, 0x08, NOP, NOP, 0x09, 0x08, NOP, NOP, 0x33, 0x00,
+/* sc=10 */ 'q', 'Q', 0x11, 0x11, 'q', 'Q', 0x11, 0x11, 0x00, 0x01,
+/* sc=11 */ 'w', 'W', 0x17, 0x17, 'w', 'W', 0x17, 0x17, 0x00, 0x01,
+/* sc=12 */ 'e', 'E', 0x05, 0x05, 'e', 'E', 0x05, 0x05, 0x00, 0x01,
+/* sc=13 */ 'r', 'R', 0x12, 0x12, 'r', 'R', 0x12, 0x12, 0x00, 0x01,
+/* sc=14 */ 't', 'T', 0x14, 0x14, 't', 'T', 0x14, 0x14, 0x00, 0x01,
+/* sc=15 */ 'y', 'Y', 0x19, 0x19, 'y', 'Y', 0x19, 0x19, 0x00, 0x01,
+/* sc=16 */ 'u', 'U', 0x15, 0x15, 'u', 'U', 0x15, 0x15, 0x00, 0x01,
+/* sc=17 */ 'i', 'I', 0x09, 0x09, 'i', 'I', 0x09, 0x09, 0x00, 0x01,
+/* sc=18 */ 'o', 'O', 0x0F, 0x0F, 'o', 'O', 0x0F, 0x0F, 0x00, 0x01,
+/* sc=19 */ 'p', 'P', 0x10, 0x10, 'p', 'P', 0x10, 0x10, 0x00, 0x01,
+/* sc=1a */ 0xE5, 0xC5, NOP, NOP, 0x86, 0x8F, NOP, NOP, 0x33, 0x01,
+/* sc=1b */ '"', '^', 0x1E, 0x1E, '~', '^', 0x1E, 0x1E, 0x00, 0x00,
+/* sc=1c */ 0x0D, 0x0D, 0x0A, 0x0A, 0x0D, 0x0D, 0x0A, 0x0A, 0x00, 0x00,
+/* sc=1d */ LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, 0xFF, 0x00,
+/* sc=1e */ 'a', 'A', 0x01, 0x01, 'a', 'A', 0x01, 0x01, 0x00, 0x01,
+/* sc=1f */ 's', 'S', 0x13, 0x13, 's', 'S', 0x13, 0x13, 0x00, 0x01,
+/* sc=20 */ 'd', 'D', 0x04, 0x04, 'd', 'D', 0x04, 0x04, 0x00, 0x01,
+/* sc=21 */ 'f', 'F', 0x06, 0x06, 'f', 'F', 0x06, 0x06, 0x00, 0x01,
+/* sc=22 */ 'g', 'G', 0x07, 0x07, 'g', 'G', 0x07, 0x07, 0x00, 0x01,
+/* sc=23 */ 'h', 'H', 0x08, 0x08, 'h', 'H', 0x08, 0x08, 0x00, 0x01,
+/* sc=24 */ 'j', 'J', 0x0A, 0x0A, 'j', 'J', 0x0A, 0x0A, 0x00, 0x01,
+/* sc=25 */ 'k', 'K', 0x0B, 0x0B, 'k', 'K', 0x0B, 0x0B, 0x00, 0x01,
+/* sc=26 */ 'l', 'L', 0x0C, 0x0C, 'l', 'L', 0x0C, 0x0C, 0x00, 0x01,
+/* sc=27 */ 0xE6, 0xC6, NOP, NOP, 0x91, 0x92, NOP, NOP, 0x33, 0x01,
+/* sc=28 */ 0xF8, 0xD8, NOP, NOP, 0x9B, 0x9D, NOP, NOP, 0x33, 0x01,
+/* sc=29 */ 0xBD, 0xA7, NOP, NOP, 0xBD, 0xA7, NOP, NOP, 0x33, 0x00,
+/* sc=2a */ LSH, LSH, LSH, LSH, LSH, LSH, LSH, LSH, 0xFF, 0x00,
+/* sc=2b */ '\'', '*', NOP, NOP, '\'', '*', NOP, NOP, 0x33, 0x00,
+/* sc=2c */ 'z', 'Z', 0x1A, 0x1A, 'z', 'Z', 0x1A, 0x1A, 0x00, 0x01,
+/* sc=2d */ 'x', 'X', 0x18, 0x18, 'x', 'X', 0x18, 0x18, 0x00, 0x01,
+/* sc=2e */ 'c', 'C', 0x03, 0x03, 'c', 'C', 0x03, 0x03, 0x00, 0x01,
+/* sc=2f */ 'v', 'V', 0x16, 0x16, 'v', 'V', 0x16, 0x16, 0x00, 0x01,
+/* sc=30 */ 'b', 'B', 0x02, 0x02, 'b', 'B', 0x02, 0x02, 0x00, 0x01,
+/* sc=31 */ 'n', 'N', 0x0E, 0x0E, 'n', 'N', 0x0E, 0x0E, 0x00, 0x01,
+/* sc=32 */ 'm', 'M', 0x0D, 0x0D, 'm', 'M', 0x0D, 0x0D, 0x00, 0x01,
+/* sc=33 */ ',', ';', NOP, NOP, ',', ';', NOP, NOP, 0x33, 0x00,
+/* sc=34 */ '.', ':', NOP, NOP, '.', ':', NOP, NOP, 0x33, 0x00,
+/* sc=35 */ '-', '_', 0x1F, 0x1F, '-', '_', 0x1F, 0x1F, 0x00, 0x00,
+/* sc=36 */ RSH, RSH, RSH, RSH, RSH, RSH, RSH, RSH, 0xFF, 0x00,
+/* sc=37 */ '*', '*', '*', '*', '*', '*', '*', '*', 0x00, 0x00,
+/* sc=38 */ LALT, LALT, LALT, LALT, LALT, LALT, LALT, LALT, 0xFF, 0x00,
+/* sc=39 */ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 0x00, 0x00,
+/* sc=3a */ CLK, CLK, CLK, CLK, CLK, CLK, CLK, CLK, 0xFF, 0x00,
+/* sc=3b */ F( 1), F(13), F(25), F(37), S( 1), S(11), S( 1), S(11), 0xFF, 0x00,
+/* sc=3c */ F( 2), F(14), F(26), F(38), S( 2), S(12), S( 2), S(12), 0xFF, 0x00,
+/* sc=3d */ F( 3), F(15), F(27), F(39), S( 3), S(13), S( 3), S(13), 0xFF, 0x00,
+/* sc=3e */ F( 4), F(16), F(28), F(40), S( 4), S(14), S( 4), S(14), 0xFF, 0x00,
+/* sc=3f */ F( 5), F(17), F(29), F(41), S( 5), S(15), S( 5), S(15), 0xFF, 0x00,
+/* sc=40 */ F( 6), F(18), F(30), F(42), S( 6), S(16), S( 6), S(16), 0xFF, 0x00,
+/* sc=41 */ F( 7), F(19), F(31), F(43), S( 7), S( 7), S( 7), S( 7), 0xFF, 0x00,
+/* sc=42 */ F( 8), F(20), F(32), F(44), S( 8), S( 8), S( 8), S( 8), 0xFF, 0x00,
+/* sc=43 */ F( 9), F(21), F(33), F(45), S( 9), S( 9), S( 9), S( 9), 0xFF, 0x00,
+/* sc=44 */ F(10), F(22), F(34), F(46), S(10), S(10), S(10), S(10), 0xFF, 0x00,
+/* sc=45 */ NLK, NLK, NLK, NLK, NLK, NLK, NLK, NLK, 0xFF, 0x00,
+/* sc=46 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+/* sc=47 */ F(49), '7', '7', '7', '7', '7', '7', '7', 0x80, 0x02,
+/* sc=48 */ F(50), '8', '8', '8', '8', '8', '8', '8', 0x80, 0x02,
+/* sc=49 */ F(51), '9', '9', '9', '9', '9', '9', '9', 0x80, 0x02,
+/* sc=4a */ F(52), '-', '-', '-', '-', '-', '-', '-', 0x80, 0x02,
+/* sc=4b */ F(53), '4', '4', '4', '4', '4', '4', '4', 0x80, 0x02,
+/* sc=4c */ NOP, '5', '5', '5', '5', '5', '5', '5', 0x80, 0x02,
+/* sc=4d */ F(55), '6', '6', '6', '6', '6', '6', '6', 0x80, 0x02,
+/* sc=4e */ F(56), '+', '+', '+', '+', '+', '+', '+', 0x80, 0x02,
+/* sc=4f */ F(57), '1', '1', '1', '1', '1', '1', '1', 0x80, 0x02,
+/* sc=50 */ F(58), '2', '2', '2', '2', '2', '2', '2', 0x80, 0x02,
+/* sc=51 */ F(59), '3', '3', '3', '3', '3', '3', '3', 0x80, 0x02,
+/* sc=52 */ F(60), '0', '0', '0', '0', '0', '0', '0', 0x80, 0x02,
+/* sc=53 */ 0x7F, '.', 0x7F, 0x7F, 0x7F, 0x7F, RBT, 0x7F, 0x02, 0x02,
+/* sc=54 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=55 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=56 */ '<', '>', 0x1C, 0x1C, '\\', '>', 0x1C, 0x1C, 0x00, 0x00,
+/* sc=57 */ F(11), F(23), F(35), F(47), S(11), S(11), S(11), S(11), 0xFF, 0x00,
+/* sc=58 */ F(12), F(24), F(36), F(48), S(12), S(12), S(12), S(12), 0xFF, 0x00,
+/* sc=59 */ 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x00, 0x02,
+/* sc=5a */ RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, 0xFF, 0x00,
+/* sc=5b */ '/', '/', '/', '/', '/', '/', '/', '/', 0x00, 0x00,
+/* sc=5c */ NEXT, NOP, DBG, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=5d */ RALT, RALT, RALT, RALT, RALT, RALT, RALT, RALT, 0xFF, 0x00,
+/* sc=5e */ F(49), F(49), F(49), F(49), F(49), F(49), F(49), F(49), 0xFF, 0x00,
+/* sc=5f */ F(50), F(50), F(50), F(50), F(50), F(50), F(50), F(50), 0xFF, 0x00,
+/* sc=60 */ F(51), F(51), F(51), F(51), F(51), F(51), F(51), F(51), 0xFF, 0x00,
+/* sc=61 */ F(53), F(53), F(53), F(53), F(53), F(53), F(53), F(53), 0xFF, 0x00,
+/* sc=62 */ F(55), F(55), F(55), F(55), F(55), F(55), F(55), F(55), 0xFF, 0x00,
+/* sc=63 */ F(57), F(57), F(57), F(57), F(57), F(57), F(57), F(57), 0xFF, 0x00,
+/* sc=64 */ F(58), F(58), F(58), F(58), F(58), F(58), F(58), F(58), 0xFF, 0x00,
+/* sc=65 */ F(59), F(59), F(59), F(59), F(59), F(59), F(59), F(59), 0xFF, 0x00,
+/* sc=66 */ F(60), F(60), F(60), F(60), F(60), F(60), F(60), F(60), 0xFF, 0x00,
+/* sc=67 */ F(54), F(54), F(54), F(54), F(54), F(54), RBT, F(54), 0xFF, 0x00,
+/* sc=68 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+};
+#endif
+
+#ifdef UKKEYMAP
+keymap_t key_map = { 0x69, /* uk iso8859 keymap */
+/* alt
+ * scan cntrl alt alt cntrl
+ * code base shift cntrl shift alt shift cntrl shift spcl flgs
+ * ---------------------------------------------------------------------------
+ */
+/* sc=00 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=01 */ 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, DBG, 0x1B, 0x02, 0x00,
+/* sc=02 */ '1', '!', NOP, NOP, '`', '`', NOP, NOP, 0x33, 0x00,
+/* sc=03 */ '2', '"', 0x00, 0x00, '@', '@', 0x00, 0x00, 0x00, 0x00,
+/* sc=04 */ '3', 0xA3, NOP, NOP, '#', '#', NOP, NOP, 0x33, 0x00,
+/* sc=05 */ '4', '$', NOP, NOP, '4', '$', NOP, NOP, 0x33, 0x00,
+/* sc=06 */ '5', '%', NOP, NOP, '5', '%', NOP, NOP, 0x33, 0x00,
+/* sc=07 */ '6', '^', 0x1E, 0x1E, '^', '^', 0x1E, 0x1E, 0x00, 0x00,
+/* sc=08 */ '7', '&', NOP, NOP, '[', '[', 0x1B, 0x1B, 0x30, 0x00,
+/* sc=09 */ '8', '*', NOP, NOP, '8', '*', NOP, NOP, 0x33, 0x00,
+/* sc=0a */ '9', '(', NOP, NOP, ']', ']', 0x1D, 0x1D, 0x30, 0x00,
+/* sc=0b */ '0', ')', NOP, NOP, '{', '{', NOP, NOP, 0x33, 0x00,
+/* sc=0c */ '-', '_', 0x1F, 0x1F, '|', '|', 0x1F, 0x1F, 0x00, 0x00,
+/* sc=0d */ '=', '+', NOP, NOP, '}', '}', NOP, NOP, 0x33, 0x00,
+/* sc=0e */ 0x08, 0x08, 0x7F, 0x7F, 0x08, 0x08, 0x7F, 0x7F, 0x00, 0x00,
+/* sc=0f */ 0x09, 0x08, NOP, NOP, 0x09, 0x08, NOP, NOP, 0x77, 0x00,
+/* sc=10 */ 'q', 'Q', 0x11, 0x11, 'q', 'Q', 0x11, 0x11, 0x00, 0x01,
+/* sc=11 */ 'w', 'W', 0x17, 0x17, 'w', 'W', 0x17, 0x17, 0x00, 0x01,
+/* sc=12 */ 'e', 'E', 0x05, 0x05, 'e', 'E', 0x05, 0x05, 0x00, 0x01,
+/* sc=13 */ 'r', 'R', 0x12, 0x12, 'r', 'R', 0x12, 0x12, 0x00, 0x01,
+/* sc=14 */ 't', 'T', 0x14, 0x14, 't', 'T', 0x14, 0x14, 0x00, 0x01,
+/* sc=15 */ 'y', 'Y', 0x19, 0x19, 'y', 'Y', 0x19, 0x19, 0x00, 0x01,
+/* sc=16 */ 'u', 'U', 0x15, 0x15, 'u', 'U', 0x15, 0x15, 0x00, 0x01,
+/* sc=17 */ 'i', 'I', 0x09, 0x09, 'i', 'I', 0x09, 0x09, 0x00, 0x01,
+/* sc=18 */ 'o', 'O', 0x0F, 0x0F, 'o', 'O', 0x0F, 0x0F, 0x00, 0x01,
+/* sc=19 */ 'p', 'P', 0x10, 0x10, 'p', 'P', 0x10, 0x10, 0x00, 0x01,
+/* sc=1a */ '[', '{', 0x1B, 0x1B, '[', '{', 0x1B, 0x1B, 0x00, 0x00,
+/* sc=1b */ ']', '}', 0x1D, 0x1D, ']', '}', 0x1D, 0x1D, 0x00, 0x00,
+/* sc=1c */ 0x0D, 0x0D, 0x0A, 0x0A, 0x0D, 0x0D, 0x0A, 0x0A, 0x00, 0x00,
+/* sc=1d */ LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, 0xFF, 0x00,
+/* sc=1e */ 'a', 'A', 0x01, 0x01, 'a', 'A', 0x01, 0x01, 0x00, 0x01,
+/* sc=1f */ 's', 'S', 0x13, 0x13, 's', 'S', 0x13, 0x13, 0x00, 0x01,
+/* sc=20 */ 'd', 'D', 0x04, 0x04, 'd', 'D', 0x04, 0x04, 0x00, 0x01,
+/* sc=21 */ 'f', 'F', 0x06, 0x06, 'f', 'F', 0x06, 0x06, 0x00, 0x01,
+/* sc=22 */ 'g', 'G', 0x07, 0x07, 'g', 'G', 0x07, 0x07, 0x00, 0x01,
+/* sc=23 */ 'h', 'H', 0x08, 0x08, 'h', 'H', 0x08, 0x08, 0x00, 0x01,
+/* sc=24 */ 'j', 'J', 0x0A, 0x0A, 'j', 'J', 0x0A, 0x0A, 0x00, 0x01,
+/* sc=25 */ 'k', 'K', 0x0B, 0x0B, 'k', 'K', 0x0B, 0x0B, 0x00, 0x01,
+/* sc=26 */ 'l', 'L', 0x0C, 0x0C, 'l', 'L', 0x0C, 0x0C, 0x00, 0x01,
+/* sc=27 */ ';', ':', NOP, NOP, ';', ':', NOP, NOP, 0x33, 0x00,
+/* sc=28 */ '\'', '@', 0x00, 0x00, '\'', '@', 0x00, 0x00, 0x00, 0x00,
+/* sc=29 */ '\\', '|', 0x1C, 0x1C, '\\', '\\', 0x1C, 0x1C, 0x00, 0x00,
+/* sc=2a */ LSH, LSH, LSH, LSH, LSH, LSH, LSH, LSH, 0xFF, 0x00,
+/* sc=2b */ '#', '~', NOP, NOP, '~', '~', NOP, NOP, 0x33, 0x00,
+/* sc=2c */ 'z', 'Z', 0x1A, 0x1A, 'z', 'Z', 0x1A, 0x1A, 0x00, 0x01,
+/* sc=2d */ 'x', 'X', 0x18, 0x18, 'x', 'X', 0x18, 0x18, 0x00, 0x01,
+/* sc=2e */ 'c', 'C', 0x03, 0x03, 'c', 'C', 0x03, 0x03, 0x00, 0x01,
+/* sc=2f */ 'v', 'V', 0x16, 0x16, 'v', 'V', 0x16, 0x16, 0x00, 0x01,
+/* sc=30 */ 'b', 'B', 0x02, 0x02, 'b', 'B', 0x02, 0x02, 0x00, 0x01,
+/* sc=31 */ 'n', 'N', 0x0E, 0x0E, 'n', 'N', 0x0E, 0x0E, 0x00, 0x01,
+/* sc=32 */ 'm', 'M', 0x0D, 0x0D, 'm', 'M', 0x0D, 0x0D, 0x00, 0x01,
+/* sc=33 */ ',', '<', NOP, NOP, ',', '<', NOP, NOP, 0x33, 0x00,
+/* sc=34 */ '.', '>', NOP, NOP, '.', '>', NOP, NOP, 0x33, 0x00,
+/* sc=35 */ '/', '?', NOP, NOP, '/', '?', NOP, NOP, 0x33, 0x00,
+/* sc=36 */ RSH, RSH, RSH, RSH, RSH, RSH, RSH, RSH, 0xFF, 0x00,
+/* sc=37 */ '*', '*', 0x0A, 0x0A, '*', '*', 0x0A, 0x0A, 0x33, 0x00,
+/* sc=38 */ LALT, LALT, LALT, LALT, LALT, LALT, LALT, LALT, 0xFF, 0x00,
+/* sc=39 */ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 0x00, 0x00,
+/* sc=3a */ CLK, CLK, CLK, CLK, CLK, CLK, CLK, CLK, 0xFF, 0x00,
+/* sc=3b */ F( 1), F(13), F(25), F(37), S( 1), S(11), S( 1), S(11), 0xFF, 0x00,
+/* sc=3c */ F( 2), F(14), F(26), F(38), S( 2), S(12), S( 2), S(12), 0xFF, 0x00,
+/* sc=3d */ F( 3), F(15), F(27), F(39), S( 3), S(13), S( 3), S(13), 0xFF, 0x00,
+/* sc=3e */ F( 4), F(16), F(28), F(40), S( 4), S(14), S( 4), S(14), 0xFF, 0x00,
+/* sc=3f */ F( 5), F(17), F(29), F(41), S( 5), S(15), S( 5), S(15), 0xFF, 0x00,
+/* sc=40 */ F( 6), F(18), F(30), F(42), S( 6), S(16), S( 6), S(16), 0xFF, 0x00,
+/* sc=41 */ F( 7), F(19), F(31), F(43), S( 7), S( 7), S( 7), S( 7), 0xFF, 0x00,
+/* sc=42 */ F( 8), F(20), F(32), F(44), S( 8), S( 8), S( 8), S( 8), 0xFF, 0x00,
+/* sc=43 */ F( 9), F(21), F(33), F(45), S( 9), S( 9), S( 9), S( 9), 0xFF, 0x00,
+/* sc=44 */ F(10), F(22), F(34), F(46), S(10), S(10), S(10), S(10), 0xFF, 0x00,
+/* sc=45 */ NLK, NLK, 0x13, 0x13, NLK, NLK, 0x13, 0x13, 0xCC, 0x00,
+/* sc=46 */ SLK, SLK, 0x7F, 0x7F, SLK, SLK, 0x7F, 0x7F, 0xCC, 0x00,
+/* sc=47 */ F(49), '7', '7', '7', '7', '7', '7', '7', 0x80, 0x02,
+/* sc=48 */ F(50), '8', '8', '8', '8', '8', '8', '8', 0x80, 0x02,
+/* sc=49 */ F(51), '9', '9', '9', '9', '9', '9', '9', 0x80, 0x02,
+/* sc=4a */ F(52), '-', 0x1F, 0x1F, '-', '-', '-', '-', 0x80, 0x02,
+/* sc=4b */ F(53), '4', '4', '4', '4', '4', '4', '4', 0x80, 0x02,
+/* sc=4c */ F(54), '5', '5', '5', '5', '5', '5', '5', 0x80, 0x02,
+/* sc=4d */ F(55), '6', 0x1E, 0x1E, '6', '6', '6', '6', 0x80, 0x02,
+/* sc=4e */ F(56), '+', '+', '+', '+', '+', '+', '+', 0x80, 0x02,
+/* sc=4f */ F(57), '1', '1', '1', '1', '1', '1', '1', 0x80, 0x02,
+/* sc=50 */ F(58), '2', '2', '2', '2', '2', '2', '2', 0x80, 0x02,
+/* sc=51 */ F(59), '3', '3', '3', '3', '3', '3', '3', 0x80, 0x02,
+/* sc=52 */ F(60), '0', '0', '0', '0', '0', '0', '0', 0x80, 0x02,
+/* sc=53 */ 0x7F, '.', 0x7F, 0x7F, 0x7F, 0x7F, RBT, 0x7F, 0x02, 0x02,
+/* sc=54 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=55 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=56 */ '\\', '|', 0x1C, 0x1C, '\\', '|', 0x1C, 0x1C, 0x00, 0x00,
+/* sc=57 */ F(11), F(23), F(35), F(47), S(11), S(11), S(11), S(11), 0xFF, 0x00,
+/* sc=58 */ F(12), F(24), F(36), F(48), S(12), S(12), S(12), S(12), 0xFF, 0x00,
+/* sc=59 */ 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0xFF, 0x02,
+/* sc=5a */ RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, 0xFF, 0x00,
+/* sc=5b */ '/', '/', '/', '/', '/', '/', '/', '/', 0x00, 0x02,
+/* sc=5c */ NEXT, NOP, DBG, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=5d */ RALT, RALT, RALT, RALT, RALT, RALT, RALT, RALT, 0xFF, 0x00,
+/* sc=5e */ F(49), F(49), F(49), F(49), F(49), F(49), F(49), F(49), 0xFF, 0x00,
+/* sc=5f */ F(50), F(50), F(50), F(50), F(50), F(50), F(50), F(50), 0xFF, 0x00,
+/* sc=60 */ F(51), F(51), F(51), F(51), F(51), F(51), F(51), F(51), 0xFF, 0x00,
+/* sc=61 */ F(53), F(53), F(53), F(53), F(53), F(53), F(53), F(53), 0xFF, 0x00,
+/* sc=62 */ F(55), F(55), F(55), F(55), F(55), F(55), F(55), F(55), 0xFF, 0x00,
+/* sc=63 */ F(57), F(57), F(57), F(57), F(57), F(57), F(57), F(57), 0xFF, 0x00,
+/* sc=64 */ F(58), F(58), F(58), F(58), F(58), F(58), F(58), F(58), 0xFF, 0x00,
+/* sc=65 */ F(59), F(59), F(59), F(59), F(59), F(59), F(59), F(59), 0xFF, 0x00,
+/* sc=66 */ F(60), F(60), F(60), F(60), F(60), F(60), F(60), F(60), 0xFF, 0x00,
+/* sc=67 */ F(54), F(54), F(54), F(54), F(54), F(54), RBT, F(54), 0xFF, 0x00,
+/* sc=68 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+};
+#endif
+
+#ifdef GRKEYMAP
+keymap_t key_map = { 0x69, /* german iso8859 keymap */
+/* alt
+ * scan cntrl alt alt cntrl
+ * code base shift cntrl shift alt shift cntrl shift spcl flgs
+ * ---------------------------------------------------------------------------
+ */
+/* sc=00 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=01 */ 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, DBG, 0x1B, 0x02, 0x00,
+/* sc=02 */ '1', '!', NOP, NOP, '`', '`', NOP, NOP, 0x33, 0x00,
+/* sc=03 */ '2', '"', 0x00, 0x00, '@', '@', 0x00, 0x00, 0x00, 0x00,
+/* sc=04 */ '3', 0xA7, NOP, NOP, '#', '#', NOP, NOP, 0x33, 0x00,
+/* sc=05 */ '4', '$', NOP, NOP, '4', '$', NOP, NOP, 0x33, 0x00,
+/* sc=06 */ '5', '%', NOP, NOP, '5', '%', NOP, NOP, 0x33, 0x00,
+/* sc=07 */ '6', '&', 0x1E, 0x1E, '^', '^', 0x1E, 0x1E, 0x00, 0x00,
+/* sc=08 */ '7', '/', 0x1B, 0x1B, '[', '[', 0x1B, 0x1B, 0x00, 0x00,
+/* sc=09 */ '8', '(', NOP, NOP, '8', '(', NOP, NOP, 0x33, 0x00,
+/* sc=0a */ '9', ')', 0x1D, 0x1D, ']', ']', 0x1D, 0x1D, 0x00, 0x00,
+/* sc=0b */ '0', '=', NOP, NOP, '{', '{', NOP, NOP, 0x33, 0x00,
+/* sc=0c */ 0xDF, '?', NOP, NOP, '|', '|', NOP, NOP, 0x33, 0x00,
+/* sc=0d */ 0x92, 0x93, NOP, NOP, '\'', '`', NOP, NOP, 0x33, 0x00,
+/* sc=0e */ 0x08, 0x08, 0x7F, 0x7F, 0x08, 0x08, 0x7F, 0x7F, 0x00, 0x00,
+/* sc=0f */ 0x09, 0x08, NOP, NOP, 0x09, 0x08, NOP, NOP, 0x77, 0x00,
+/* sc=10 */ 'q', 'Q', 0x11, 0x11, 'q', 'Q', 0x11, 0x11, 0x00, 0x01,
+/* sc=11 */ 'w', 'W', 0x17, 0x17, 'w', 'W', 0x17, 0x17, 0x00, 0x01,
+/* sc=12 */ 'e', 'E', 0x05, 0x05, 'e', 'E', 0x05, 0x05, 0x00, 0x01,
+/* sc=13 */ 'r', 'R', 0x12, 0x12, 'r', 'R', 0x12, 0x12, 0x00, 0x01,
+/* sc=14 */ 't', 'T', 0x14, 0x14, 't', 'T', 0x14, 0x14, 0x00, 0x01,
+/* sc=15 */ 'z', 'Z', 0x1A, 0x1A, 'z', 'Z', 0x1A, 0x1A, 0x00, 0x01,
+/* sc=16 */ 'u', 'U', 0x15, 0x15, 'u', 'U', 0x15, 0x15, 0x00, 0x01,
+/* sc=17 */ 'i', 'I', 0x09, 0x09, 'i', 'I', 0x09, 0x09, 0x00, 0x01,
+/* sc=18 */ 'o', 'O', 0x0F, 0x0F, 'o', 'O', 0x0F, 0x0F, 0x00, 0x01,
+/* sc=19 */ 'p', 'P', 0x10, 0x10, 'p', 'P', 0x10, 0x10, 0x00, 0x01,
+/* sc=1a */ 0xFC, 0xDC, 0x1B, 0x1B, '[', '{', 0x1B, 0x1B, 0x00, 0x01,
+/* sc=1b */ '+', '*', 0x1D, 0x1D, ']', '}', 0x1D, 0x1D, 0x00, 0x00,
+/* sc=1c */ 0x0D, 0x0D, 0x0A, 0x0A, 0x0D, 0x0D, 0x0A, 0x0A, 0x00, 0x00,
+/* sc=1d */ LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, 0xFF, 0x00,
+/* sc=1e */ 'a', 'A', 0x01, 0x01, 'a', 'A', 0x01, 0x01, 0x00, 0x01,
+/* sc=1f */ 's', 'S', 0x13, 0x13, 's', 'S', 0x13, 0x13, 0x00, 0x01,
+/* sc=20 */ 'd', 'D', 0x04, 0x04, 'd', 'D', 0x04, 0x04, 0x00, 0x01,
+/* sc=21 */ 'f', 'F', 0x06, 0x06, 'f', 'F', 0x06, 0x06, 0x00, 0x01,
+/* sc=22 */ 'g', 'G', 0x07, 0x07, 'g', 'G', 0x07, 0x07, 0x00, 0x01,
+/* sc=23 */ 'h', 'H', 0x08, 0x08, 'h', 'H', 0x08, 0x08, 0x00, 0x01,
+/* sc=24 */ 'j', 'J', 0x0A, 0x0A, 'j', 'J', 0x0A, 0x0A, 0x00, 0x01,
+/* sc=25 */ 'k', 'K', 0x0B, 0x0B, 'k', 'K', 0x0B, 0x0B, 0x00, 0x01,
+/* sc=26 */ 'l', 'L', 0x0C, 0x0C, 'l', 'L', 0x0C, 0x0C, 0x00, 0x01,
+/* sc=27 */ 0xF6, 0xD6, NOP, NOP, 0xF6, 0xD6, NOP, NOP, 0x33, 0x01,
+/* sc=28 */ 0xE4, 0xC4, NOP, NOP, 0xE4, 0xC4, NOP, NOP, 0x33, 0x01,
+/* sc=29 */ '<', '>', 0x1C, 0x1C, '\\', '|', 0x1C, 0x1C, 0x00, 0x00,
+/* sc=2a */ LSH, LSH, LSH, LSH, LSH, LSH, LSH, LSH, 0xFF, 0x00,
+/* sc=2b */ '#', '^', 0x1E, 0x1E, '`', '~', 0x1E, 0x1E, 0x00, 0x00,
+/* sc=2c */ 'y', 'Y', 0x19, 0x19, 'y', 'Y', 0x19, 0x19, 0x00, 0x01,
+/* sc=2d */ 'x', 'X', 0x18, 0x18, 'x', 'X', 0x18, 0x18, 0x00, 0x01,
+/* sc=2e */ 'c', 'C', 0x03, 0x03, 'c', 'C', 0x03, 0x03, 0x00, 0x01,
+/* sc=2f */ 'v', 'V', 0x16, 0x16, 'v', 'V', 0x16, 0x16, 0x00, 0x01,
+/* sc=30 */ 'b', 'B', 0x02, 0x02, 'b', 'B', 0x02, 0x02, 0x00, 0x01,
+/* sc=31 */ 'n', 'N', 0x0E, 0x0E, 'n', 'N', 0x0E, 0x0E, 0x00, 0x01,
+/* sc=32 */ 'm', 'M', 0x0D, 0x0D, 'm', 'M', 0x0D, 0x0D, 0x00, 0x01,
+/* sc=33 */ ',', ';', NOP, NOP, ',', ';', NOP, NOP, 0x33, 0x00,
+/* sc=34 */ '.', ':', NOP, NOP, '.', ':', NOP, NOP, 0x33, 0x00,
+/* sc=35 */ '-', '_', 0x1F, 0x1F, '-', '_', 0x1F, 0x1F, 0x00, 0x00,
+/* sc=36 */ RSH, RSH, RSH, RSH, RSH, RSH, RSH, RSH, 0xFF, 0x00,
+/* sc=37 */ '*', '*', 0x0A, 0x0A, '*', '*', 0x0A, 0x0A, 0x33, 0x00,
+/* sc=38 */ LALT, LALT, LALT, LALT, LALT, LALT, LALT, LALT, 0xFF, 0x00,
+/* sc=39 */ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 0x00, 0x00,
+/* sc=3a */ CLK, CLK, CLK, CLK, CLK, CLK, CLK, CLK, 0xFF, 0x00,
+/* sc=3b */ F( 1), F(13), F(25), F(37), S( 1), S(11), S( 1), S(11), 0xFF, 0x00,
+/* sc=3c */ F( 2), F(14), F(26), F(38), S( 2), S(12), S( 2), S(12), 0xFF, 0x00,
+/* sc=3d */ F( 3), F(15), F(27), F(39), S( 3), S(13), S( 3), S(13), 0xFF, 0x00,
+/* sc=3e */ F( 4), F(16), F(28), F(40), S( 4), S(14), S( 4), S(14), 0xFF, 0x00,
+/* sc=3f */ F( 5), F(17), F(29), F(41), S( 5), S(15), S( 5), S(15), 0xFF, 0x00,
+/* sc=40 */ F( 6), F(18), F(30), F(42), S( 6), S(16), S( 6), S(16), 0xFF, 0x00,
+/* sc=41 */ F( 7), F(19), F(31), F(43), S( 7), S( 7), S( 7), S( 7), 0xFF, 0x00,
+/* sc=42 */ F( 8), F(20), F(32), F(44), S( 8), S( 8), S( 8), S( 8), 0xFF, 0x00,
+/* sc=43 */ F( 9), F(21), F(33), F(45), S( 9), S( 9), S( 9), S( 9), 0xFF, 0x00,
+/* sc=44 */ F(10), F(22), F(34), F(46), S(10), S(10), S(10), S(10), 0xFF, 0x00,
+/* sc=45 */ NLK, NLK, 0x13, 0x13, NLK, NLK, 0x13, 0x13, 0xCC, 0x00,
+/* sc=46 */ SLK, SLK, 0x7F, 0x7F, SLK, SLK, 0x7F, 0x7F, 0xCC, 0x00,
+/* sc=47 */ F(49), '7', '7', '7', '7', '7', '7', '7', 0x80, 0x02,
+/* sc=48 */ F(50), '8', '8', '8', '8', '8', '8', '8', 0x80, 0x02,
+/* sc=49 */ F(51), '9', '9', '9', '9', '9', '9', '9', 0x80, 0x02,
+/* sc=4a */ F(52), '-', 0x1F, 0x1F, '-', '-', '-', '-', 0x80, 0x02,
+/* sc=4b */ F(53), '4', '4', '4', '4', '4', '4', '4', 0x80, 0x02,
+/* sc=4c */ F(54), '5', '5', '5', '5', '5', '5', '5', 0x80, 0x02,
+/* sc=4d */ F(55), '6', 0x1E, 0x1E, '6', '6', '6', '6', 0x80, 0x02,
+/* sc=4e */ F(56), '+', '+', '+', '+', '+', '+', '+', 0x80, 0x02,
+/* sc=4f */ F(57), '1', '1', '1', '1', '1', '1', '1', 0x80, 0x02,
+/* sc=50 */ F(58), '2', '2', '2', '2', '2', '2', '2', 0x80, 0x02,
+/* sc=51 */ F(59), '3', '3', '3', '3', '3', '3', '3', 0x80, 0x02,
+/* sc=52 */ F(60), '0', '0', '0', '0', '0', '0', '0', 0x80, 0x02,
+/* sc=53 */ 0x7F, '.', 0x7F, 0x7F, 0x7F, 0x7F, RBT, 0x7F, 0x02, 0x02,
+/* sc=54 */ 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x00, 0x00,
+/* sc=55 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=56 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=57 */ F(11), F(23), F(35), F(47), S(11), S(11), S(11), S(11), 0xFF, 0x00,
+/* sc=58 */ F(12), F(24), F(36), F(48), S(12), S(12), S(12), S(12), 0xFF, 0x00,
+/* sc=59 */ 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0xFF, 0x02,
+/* sc=5a */ RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, 0xFF, 0x00,
+/* sc=5b */ '/', '/', '/', '/', '/', '/', '/', '/', 0x00, 0x02,
+/* sc=5c */ NEXT, NOP, DBG, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=5d */ RALT, RALT, RALT, RALT, RALT, RALT, RALT, RALT, 0xFF, 0x00,
+/* sc=5e */ F(49), F(49), F(49), F(49), F(49), F(49), F(49), F(49), 0xFF, 0x00,
+/* sc=5f */ F(50), F(50), F(50), F(50), F(50), F(50), F(50), F(50), 0xFF, 0x00,
+/* sc=60 */ F(51), F(51), F(51), F(51), F(51), F(51), F(51), F(51), 0xFF, 0x00,
+/* sc=61 */ F(53), F(53), F(53), F(53), F(53), F(53), F(53), F(53), 0xFF, 0x00,
+/* sc=62 */ F(55), F(55), F(55), F(55), F(55), F(55), F(55), F(55), 0xFF, 0x00,
+/* sc=63 */ F(57), F(57), F(57), F(57), F(57), F(57), F(57), F(57), 0xFF, 0x00,
+/* sc=64 */ F(58), F(58), F(58), F(58), F(58), F(58), F(58), F(58), 0xFF, 0x00,
+/* sc=65 */ F(59), F(59), F(59), F(59), F(59), F(59), F(59), F(59), 0xFF, 0x00,
+/* sc=66 */ F(60), F(60), F(60), F(60), F(60), F(60), F(60), F(60), 0xFF, 0x00,
+/* sc=67 */ F(54), F(54), F(54), F(54), F(54), F(54), RBT, F(54), 0xFF, 0x00,
+/* sc=68 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+};
+#endif
+
+#ifdef SWKEYMAP
+keymap_t key_map = { 0x69, /* swedish iso8859 keymap */
+/* alt
+ * scan cntrl alt alt cntrl
+ * code base shift cntrl shift alt shift cntrl shift spcl flgs
+ * ---------------------------------------------------------------------------
+ */
+/* sc=00 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=01 */ 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, DBG, 0x1B, 0x02, 0x00,
+/* sc=02 */ '1', '!', NOP, NOP, NOP, NOP, NOP, NOP, 0x3F, 0x00,
+/* sc=03 */ '2', '"', NOP, NOP, '@', NOP, NOP, NOP, 0x37, 0x00,
+/* sc=04 */ '3', '#', NOP, NOP, 0xA3, NOP, NOP, NOP, 0x37, 0x00,
+/* sc=05 */ '4', '$', NOP, NOP, 0xA4, NOP, NOP, NOP, 0x37, 0x00,
+/* sc=06 */ '5', '%', NOP, NOP, NOP, NOP, NOP, NOP, 0x3F, 0x00,
+/* sc=07 */ '6', '&', NOP, NOP, NOP, NOP, NOP, NOP, 0x3F, 0x00,
+/* sc=08 */ '7', '/', NOP, NOP, '{', NOP, NOP, NOP, 0x37, 0x00,
+/* sc=09 */ '8', '(', NOP, NOP, '[', NOP, NOP, NOP, 0x37, 0x00,
+/* sc=0a */ '9', ')', NOP, NOP, ']', NOP, NOP, NOP, 0x37, 0x00,
+/* sc=0b */ '0', '=', NOP, NOP, '}', NOP, NOP, NOP, 0x37, 0x00,
+/* sc=0c */ '+', '?', NOP, NOP, '\\', NOP, 0x1C, NOP, 0x35, 0x00,
+/* sc=0d */ 0x180, '`', NOP, NOP, NOP, NOP, NOP, NOP, 0x3F, 0x00,
+/* sc=0e */ 0x08, 0x08, 0x7F, 0x7F, 0x08, 0x08, 0x7F, 0x7F, 0x00, 0x00,
+/* sc=0f */ 0x09, 0x08, NOP, NOP, 0x09, 0x08, NOP, NOP, 0x77, 0x00,
+/* sc=10 */ 'q', 'Q', 0x11, 0x11, 'q', 'Q', 0x11, 0x11, 0x00, 0x01,
+/* sc=11 */ 'w', 'W', 0x17, 0x17, 'w', 'W', 0x17, 0x17, 0x00, 0x01,
+/* sc=12 */ 'e', 'E', 0x05, 0x05, 'e', 'E', 0x05, 0x05, 0x00, 0x01,
+/* sc=13 */ 'r', 'R', 0x12, 0x12, 'r', 'R', 0x12, 0x12, 0x00, 0x01,
+/* sc=14 */ 't', 'T', 0x14, 0x14, 't', 'T', 0x14, 0x14, 0x00, 0x01,
+/* sc=15 */ 'y', 'Y', 0x19, 0x19, 'y', 'Y', 0x19, 0x19, 0x00, 0x01,
+/* sc=16 */ 'u', 'U', 0x15, 0x15, 'u', 'U', 0x15, 0x15, 0x00, 0x01,
+/* sc=17 */ 'i', 'I', 0x09, 0x09, 'i', 'I', 0x09, 0x09, 0x00, 0x01,
+/* sc=18 */ 'o', 'O', 0x0F, 0x0F, 'o', 'O', 0x0F, 0x0F, 0x00, 0x01,
+/* sc=19 */ 'p', 'P', 0x10, 0x10, 'p', 'P', 0x10, 0x10, 0x00, 0x01,
+/* sc=1a */ 0xE5, 0xC5, NOP, NOP, '}', ']', NOP, NOP, 0x33, 0x01,
+/* sc=1b */ 0xA8, '^', NOP, NOP, '~', NOP, NOP, NOP, 0x37, 0x00,
+/* sc=1c */ 0x0D, 0x0D, 0x0A, 0x0A, 0x0D, 0x0D, 0x0A, 0x0A, 0x00, 0x00,
+/* sc=1d */ LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, 0xFF, 0x00,
+/* sc=1e */ 'a', 'A', 0x01, 0x01, 'a', 'A', 0x01, 0x01, 0x00, 0x01,
+/* sc=1f */ 's', 'S', 0x13, 0x13, 's', 'S', 0x13, 0x13, 0x00, 0x01,
+/* sc=20 */ 'd', 'D', 0x04, 0x04, 'd', 'D', 0x04, 0x04, 0x00, 0x01,
+/* sc=21 */ 'f', 'F', 0x06, 0x06, 'f', 'F', 0x06, 0x06, 0x00, 0x01,
+/* sc=22 */ 'g', 'G', 0x07, 0x07, 'g', 'G', 0x07, 0x07, 0x00, 0x01,
+/* sc=23 */ 'h', 'H', 0x08, 0x08, 'h', 'H', 0x08, 0x08, 0x00, 0x01,
+/* sc=24 */ 'j', 'J', 0x0A, 0x0A, 'j', 'J', 0x0A, 0x0A, 0x00, 0x01,
+/* sc=25 */ 'k', 'K', 0x0B, 0x0B, 'k', 'K', 0x0B, 0x0B, 0x00, 0x01,
+/* sc=26 */ 'l', 'L', 0x0C, 0x0C, 'l', 'L', 0x0C, 0x0C, 0x00, 0x01,
+/* sc=27 */ 0xF6, 0xD6, NOP, NOP, '|', '\\', NOP, NOP, 0x33, 0x01,
+/* sc=28 */ 0xE4, 0xC4, NOP, NOP, '{', '[', NOP, NOP, 0x33, 0x01,
+/* sc=29 */ 0xA7, 0xBD, NOP, NOP, '\\', '|', NOP, NOP, 0x33, 0x00,
+/* sc=2a */ LSH, LSH, LSH, LSH, LSH, LSH, LSH, LSH, 0xFF, 0x00,
+/* sc=2b */ '\'', '*', NOP, NOP, NOP, NOP, NOP, NOP, 0x3F, 0x00,
+/* sc=2c */ 'z', 'Z', 0x1A, 0x1A, 'z', 'Z', 0x1A, 0x1A, 0x00, 0x01,
+/* sc=2d */ 'x', 'X', 0x18, 0x18, 'x', 'X', 0x18, 0x18, 0x00, 0x01,
+/* sc=2e */ 'c', 'C', 0x03, 0x03, 'c', 'C', 0x03, 0x03, 0x00, 0x01,
+/* sc=2f */ 'v', 'V', 0x16, 0x16, 'v', 'V', 0x16, 0x16, 0x00, 0x01,
+/* sc=30 */ 'b', 'B', 0x02, 0x02, 'b', 'B', 0x02, 0x02, 0x00, 0x01,
+/* sc=31 */ 'n', 'N', 0x0E, 0x0E, 'n', 'N', 0x0E, 0x0E, 0x00, 0x01,
+/* sc=32 */ 'm', 'M', 0x0D, 0x0D, 'm', 'M', 0x0D, 0x0D, 0x00, 0x01,
+/* sc=33 */ ',', ';', NOP, NOP, NOP, '<', NOP, NOP, 0x3B, 0x00,
+/* sc=34 */ '.', ':', NOP, NOP, NOP, '>', NOP, NOP, 0x3B, 0x00,
+/* sc=35 */ '-', '_', 0x1F, NOP, '/', '?', NOP, NOP, 0x13, 0x00,
+/* sc=36 */ RSH, RSH, RSH, RSH, RSH, RSH, RSH, RSH, 0xFF, 0x00,
+/* sc=37 */ '*', '*', 0x0A, 0x0A, '*', '*', 0x0A, 0x0A, 0x33, 0x00,
+/* sc=38 */ LALT, LALT, LALT, LALT, LALT, LALT, LALT, LALT, 0xFF, 0x00,
+/* sc=39 */ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 0x00, 0x00,
+/* sc=3a */ CLK, CLK, CLK, CLK, CLK, CLK, CLK, CLK, 0xFF, 0x00,
+/* sc=3b */ F( 1), F(13), F(25), F(37), S( 1), S(11), S( 1), S(11), 0xFF, 0x00,
+/* sc=3c */ F( 2), F(14), F(26), F(38), S( 2), S(12), S( 2), S(12), 0xFF, 0x00,
+/* sc=3d */ F( 3), F(15), F(27), F(39), S( 3), S(13), S( 3), S(13), 0xFF, 0x00,
+/* sc=3e */ F( 4), F(16), F(28), F(40), S( 4), S(14), S( 4), S(14), 0xFF, 0x00,
+/* sc=3f */ F( 5), F(17), F(29), F(41), S( 5), S(15), S( 5), S(15), 0xFF, 0x00,
+/* sc=40 */ F( 6), F(18), F(30), F(42), S( 6), S(16), S( 6), S(16), 0xFF, 0x00,
+/* sc=41 */ F( 7), F(19), F(31), F(43), S( 7), S( 7), S( 7), S( 7), 0xFF, 0x00,
+/* sc=42 */ F( 8), F(20), F(32), F(44), S( 8), S( 8), S( 8), S( 8), 0xFF, 0x00,
+/* sc=43 */ F( 9), F(21), F(33), F(45), S( 9), S( 9), S( 9), S( 9), 0xFF, 0x00,
+/* sc=44 */ F(10), F(22), F(34), F(46), S(10), S(10), S(10), S(10), 0xFF, 0x00,
+/* sc=45 */ NLK, NLK, 0x13, 0x13, NLK, NLK, 0x13, 0x13, 0xCC, 0x00,
+/* sc=46 */ SLK, SLK, 0x7F, 0x7F, SLK, SLK, 0x7F, 0x7F, 0xCC, 0x00,
+/* sc=47 */ F(49), '7', '7', '7', '7', '7', '7', '7', 0x80, 0x02,
+/* sc=48 */ F(50), '8', '8', '8', '8', '8', '8', '8', 0x80, 0x02,
+/* sc=49 */ F(51), '9', '9', '9', '9', '9', '9', '9', 0x80, 0x02,
+/* sc=4a */ F(52), '-', 0x1F, 0x1F, '-', '-', '-', '-', 0x80, 0x02,
+/* sc=4b */ F(53), '4', '4', '4', '4', '4', '4', '4', 0x80, 0x02,
+/* sc=4c */ F(54), '5', '5', '5', '5', '5', '5', '5', 0x80, 0x02,
+/* sc=4d */ F(55), '6', 0x1E, 0x1E, '6', '6', '6', '6', 0x80, 0x02,
+/* sc=4e */ F(56), '+', '+', '+', '+', '+', '+', '+', 0x80, 0x02,
+/* sc=4f */ F(57), '1', '1', '1', '1', '1', '1', '1', 0x80, 0x02,
+/* sc=50 */ F(58), '2', '2', '2', '2', '2', '2', '2', 0x80, 0x02,
+/* sc=51 */ F(59), '3', '3', '3', '3', '3', '3', '3', 0x80, 0x02,
+/* sc=52 */ F(60), '0', '0', '0', '0', '0', '0', '0', 0x80, 0x02,
+/* sc=53 */ 0x7F, '.', 0x7F, 0x7F, 0x7F, 0x7F, RBT, 0x7F, 0x02, 0x02,
+/* sc=54 */ 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x00, 0x00,
+/* sc=55 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=56 */ '<', '>', NOP, NOP, '|', NOP, NOP, NOP, 0x37, 0x00,
+/* sc=57 */ F(11), F(23), F(35), F(47), S(11), S(11), S(11), S(11), 0xFF, 0x00,
+/* sc=58 */ F(12), F(24), F(36), F(48), S(12), S(12), S(12), S(12), 0xFF, 0x00,
+/* sc=59 */ 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0xFF, 0x02,
+/* sc=5a */ RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, 0xFF, 0x00,
+/* sc=5b */ '/', '/', '/', '/', '/', '/', '/', '/', 0x00, 0x02,
+/* sc=5c */ NEXT, NOP, DBG, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=5d */ RALT, RALT, RALT, RALT, RALT, RALT, RALT, RALT, 0xFF, 0x00,
+/* sc=5e */ F(49), F(49), F(49), F(49), F(49), F(49), F(49), F(49), 0xFF, 0x00,
+/* sc=5f */ F(50), F(50), F(50), F(50), F(50), F(50), F(50), F(50), 0xFF, 0x00,
+/* sc=60 */ F(51), F(51), F(51), F(51), F(51), F(51), F(51), F(51), 0xFF, 0x00,
+/* sc=61 */ F(53), F(53), F(53), F(53), F(53), F(53), F(53), F(53), 0xFF, 0x00,
+/* sc=62 */ F(55), F(55), F(55), F(55), F(55), F(55), F(55), F(55), 0xFF, 0x00,
+/* sc=63 */ F(57), F(57), F(57), F(57), F(57), F(57), F(57), F(57), 0xFF, 0x00,
+/* sc=64 */ F(58), F(58), F(58), F(58), F(58), F(58), F(58), F(58), 0xFF, 0x00,
+/* sc=65 */ F(59), F(59), F(59), F(59), F(59), F(59), F(59), F(59), 0xFF, 0x00,
+/* sc=66 */ F(60), F(60), F(60), F(60), F(60), F(60), F(60), F(60), 0xFF, 0x00,
+/* sc=67 */ F(54), F(54), F(54), F(54), F(54), F(54), RBT, F(54), 0xFF, 0x00,
+/* sc=68 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+};
+#endif
+
+#ifdef RUKEYMAP
+keymap_t key_map = { 0xe9, /* keys number */
+/* alt
+ * scan cntrl alt alt cntrl
+ * code base shift cntrl shift alt shift cntrl shift spcl flgs
+ * -------------------------------------------------------------------------------------------
+ */
+/* sc=00 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=01 */ 0x1B, 0x1B, NOP, NOP, SET8|0x1B, SET8|0x1B, DBG, NOP, 0x33, 0x00,
+/* sc=02 */ '1', '!', NOP, NOP, SET8|'1', SET8|'!', NOP, NOP, 0x33, 0x00,
+/* sc=03 */ '2', '@', 0x00, 0x00, SET8|'2', SET8|'@', SET8|0x00, SET8|0x00, 0x00, 0x00,
+/* sc=04 */ '3', '#', NOP, NOP, SET8|'3', SET8|'#', NOP, NOP, 0x33, 0x00,
+/* sc=05 */ '4', '$', NOP, NOP, SET8|'4', SET8|'$', NOP, NOP, 0x33, 0x00,
+/* sc=06 */ '5', '%', NOP, NOP, SET8|'5', SET8|'%', NOP, NOP, 0x33, 0x00,
+/* sc=07 */ '6', '^', 0x1E, 0x1E, SET8|'6', SET8|'^', SET8|0x1E, SET8|0x1E, 0x00, 0x00,
+/* sc=08 */ '7', '&', NOP, NOP, SET8|'7', SET8|'&', NOP, NOP, 0x33, 0x00,
+/* sc=09 */ '8', '*', NOP, NOP, SET8|'8', SET8|'*', NOP, NOP, 0x33, 0x00,
+/* sc=0a */ '9', '(', NOP, NOP, SET8|'9', SET8|'(', NOP, NOP, 0x33, 0x00,
+/* sc=0b */ '0', ')', NOP, NOP, SET8|'0', SET8|')', NOP, NOP, 0x33, 0x00,
+/* sc=0c */ '-', '_', 0x1F, 0x1F, SET8|'-', SET8|'_', SET8|0x1F, SET8|0x1F, 0x00, 0x00,
+/* sc=0d */ '=', '+', NOP, NOP, SET8|'=', SET8|'+', NOP, NOP, 0x33, 0x00,
+/* sc=0e */ 0x08, 0x08, 0x7F, 0x7F, SET8|0x08, SET8|0x08, SET8|0x7F, SET8|0x7F, 0x00, 0x00,
+/* sc=0f */ 0x09, F(16), NOP, NOP, SET8|0x09, F(16), NOP, NOP, 0x77, 0x00,
+/* sc=10 */ 'q', 'Q', 0x11, 0x11, SET8|'q', SET8|'Q', SET8|0x11, SET8|0x11, 0x00, 0x01,
+/* sc=11 */ 'w', 'W', 0x17, 0x17, SET8|'w', SET8|'W', SET8|0x17, SET8|0x17, 0x00, 0x01,
+/* sc=12 */ 'e', 'E', 0x05, 0x05, SET8|'e', SET8|'E', SET8|0x05, SET8|0x05, 0x00, 0x01,
+/* sc=13 */ 'r', 'R', 0x12, 0x12, SET8|'r', SET8|'R', SET8|0x12, SET8|0x12, 0x00, 0x01,
+/* sc=14 */ 't', 'T', 0x14, 0x14, SET8|'t', SET8|'T', SET8|0x14, SET8|0x14, 0x00, 0x01,
+/* sc=15 */ 'y', 'Y', 0x19, 0x19, SET8|'y', SET8|'Y', SET8|0x19, SET8|0x19, 0x00, 0x01,
+/* sc=16 */ 'u', 'U', 0x15, 0x15, SET8|'u', SET8|'U', SET8|0x15, SET8|0x15, 0x00, 0x01,
+/* sc=17 */ 'i', 'I', 0x09, 0x09, SET8|'i', SET8|'I', SET8|0x09, SET8|0x09, 0x00, 0x01,
+/* sc=18 */ 'o', 'O', 0x0F, 0x0F, SET8|'o', SET8|'O', SET8|0x0F, SET8|0x0F, 0x00, 0x01,
+/* sc=19 */ 'p', 'P', 0x10, 0x10, SET8|'p', SET8|'P', SET8|0x10, SET8|0x10, 0x00, 0x01,
+/* sc=1a */ '[', '{', 0x1B, 0x1B, SET8|'[', SET8|'{', SET8|0x1B, SET8|0x1B, 0x00, 0x00,
+/* sc=1b */ ']', '}', 0x1D, 0x1D, SET8|']', SET8|'}', SET8|0x1D, SET8|0x1D, 0x00, 0x00,
+/* sc=1c */ 0x0D, 0x0D, 0x0A, 0x0A, SET8|0x0D, SET8|0x0D, SET8|0x0A, SET8|0x0A, 0x00, 0x00,
+/* sc=1d */ LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, 0xFF, 0x00,
+/* sc=1e */ 'a', 'A', 0x01, 0x01, SET8|'a', SET8|'A', SET8|0x01, SET8|0x01, 0x00, 0x01,
+/* sc=1f */ 's', 'S', 0x13, 0x13, SET8|'s', SET8|'S', SET8|0x13, SET8|0x13, 0x00, 0x01,
+/* sc=20 */ 'd', 'D', 0x04, 0x04, SET8|'d', SET8|'D', SET8|0x04, SET8|0x04, 0x00, 0x01,
+/* sc=21 */ 'f', 'F', 0x06, 0x06, SET8|'f', SET8|'F', SET8|0x06, SET8|0x06, 0x00, 0x01,
+/* sc=22 */ 'g', 'G', 0x07, 0x07, SET8|'g', SET8|'G', SET8|0x07, SET8|0x07, 0x00, 0x01,
+/* sc=23 */ 'h', 'H', 0x08, 0x08, SET8|'h', SET8|'H', SET8|0x08, SET8|0x08, 0x00, 0x01,
+/* sc=24 */ 'j', 'J', 0x0A, 0x0A, SET8|'j', SET8|'J', SET8|0x0A, SET8|0x0A, 0x00, 0x01,
+/* sc=25 */ 'k', 'K', 0x0B, 0x0B, SET8|'k', SET8|'K', SET8|0x0B, SET8|0x0B, 0x00, 0x01,
+/* sc=26 */ 'l', 'L', 0x0C, 0x0C, SET8|'l', SET8|'L', SET8|0x0C, SET8|0x0C, 0x00, 0x01,
+/* sc=27 */ ';', ':', NOP, NOP, SET8|';', SET8|':', NOP, NOP, 0x33, 0x00,
+/* sc=28 */ '\'', '"', NOP, NOP, SET8|'\'', SET8|'"', NOP, NOP, 0x33, 0x00,
+/* sc=29 */ '`', '~', NOP, NOP, SET8|'`', SET8|'~', NOP, NOP, 0x33, 0x00,
+/* sc=2a */ LSH, LSH, LSH, LSH, LSH, LSH, LSH, LSH, 0xFF, 0x00,
+/* sc=2b */ '\\', '|', 0x1C, 0x1C, SET8|'\\', SET8|'|', SET8|0x1C, SET8|0x1C, 0x00, 0x00,
+/* sc=2c */ 'z', 'Z', 0x1A, 0x1A, SET8|'z', SET8|'Z', SET8|0x1A, SET8|0x1A, 0x00, 0x01,
+/* sc=2d */ 'x', 'X', 0x18, 0x18, SET8|'x', SET8|'X', SET8|0x18, SET8|0x18, 0x00, 0x01,
+/* sc=2e */ 'c', 'C', 0x03, 0x03, SET8|'c', SET8|'C', SET8|0x03, SET8|0x03, 0x00, 0x01,
+/* sc=2f */ 'v', 'V', 0x16, 0x16, SET8|'v', SET8|'V', SET8|0x16, SET8|0x16, 0x00, 0x01,
+/* sc=30 */ 'b', 'B', 0x02, 0x02, SET8|'b', SET8|'B', SET8|0x02, SET8|0x02, 0x00, 0x01,
+/* sc=31 */ 'n', 'N', 0x0E, 0x0E, SET8|'n', SET8|'N', SET8|0x0E, SET8|0x0E, 0x00, 0x01,
+/* sc=32 */ 'm', 'M', 0x0D, 0x0D, SET8|'m', SET8|'M', SET8|0x0D, SET8|0x0D, 0x00, 0x01,
+/* sc=33 */ ',', '<', NOP, NOP, SET8|',', SET8|'<', NOP, NOP, 0x33, 0x00,
+/* sc=34 */ '.', '>', NOP, NOP, SET8|'.', SET8|'>', NOP, NOP, 0x33, 0x00,
+/* sc=35 */ '/', '?', NOP, NOP, SET8|'/', SET8|'?', NOP, NOP, 0x33, 0x00,
+/* sc=36 */ RSH, RSH, RSH, RSH, RSH, RSH, RSH, RSH, 0xFF, 0x00,
+/* sc=37 */ '*', '*', 0x0A, 0x0A, SET8|'*', SET8|'*', SET8|0x0A, SET8|0x0A, 0x00, 0x00,
+/* sc=38 */ LALT, LALT, LALT, LALT, LALT, LALT, LALT, LALT, 0xFF, 0x00,
+/* sc=39 */ ' ', ' ', ' ', ' ', SET8|' ', SET8|' ', SET8|' ', SET8|' ', 0x00, 0x00,
+/* sc=3a */ ALK, CLK, CLK, CLK, CLK, CLK, CLK, CLK, 0xFF, 0x00,
+/* sc=3b */ F( 1), F(13), F(25), F(37), S( 1), S(11), S( 1), S(11), 0xFF, 0x00,
+/* sc=3c */ F( 2), F(14), F(26), F(38), S( 2), S(12), S( 2), S(12), 0xFF, 0x00,
+/* sc=3d */ F( 3), F(15), F(27), F(39), S( 3), S(13), S( 3), S(13), 0xFF, 0x00,
+/* sc=3e */ F( 4), F(16), F(28), F(40), S( 4), S(14), S( 4), S(14), 0xFF, 0x00,
+/* sc=3f */ F( 5), F(17), F(29), F(41), S( 5), S(15), S( 5), S(15), 0xFF, 0x00,
+/* sc=40 */ F( 6), F(18), F(30), F(42), S( 6), S(16), S( 6), S(16), 0xFF, 0x00,
+/* sc=41 */ F( 7), F(19), F(31), F(43), S( 7), S( 7), S( 7), S( 7), 0xFF, 0x00,
+/* sc=42 */ F( 8), F(20), F(32), F(44), S( 8), S( 8), S( 8), S( 8), 0xFF, 0x00,
+/* sc=43 */ F( 9), F(21), F(33), F(45), S( 9), S( 9), S( 9), S( 9), 0xFF, 0x00,
+/* sc=44 */ F(10), F(22), F(34), F(46), S(10), S(10), S(10), S(10), 0xFF, 0x00,
+/* sc=45 */ NLK, NLK, NLK, NLK, NLK, NLK, NLK, NLK, 0xFF, 0x00,
+/* sc=46 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+/* sc=47 */ F(49), '7', '7', '7', SET8|'7', SET8|'7', SET8|'7', SET8|'7', 0x80, 0x02,
+/* sc=48 */ F(50), '8', '8', '8', SET8|'8', SET8|'8', SET8|'8', SET8|'8', 0x80, 0x02,
+/* sc=49 */ F(51), '9', '9', '9', SET8|'9', SET8|'9', SET8|'9', SET8|'9', 0x80, 0x02,
+/* sc=4a */ F(52), '-', '-', '-', SET8|'-', SET8|'-', SET8|'-', SET8|'-', 0x80, 0x02,
+/* sc=4b */ F(53), '4', '4', '4', SET8|'4', SET8|'4', SET8|'4', SET8|'4', 0x80, 0x02,
+/* sc=4c */ F(48), '5', '5', '5', SET8|'5', SET8|'5', SET8|'5', SET8|'5', 0x80, 0x02,
+/* sc=4d */ F(55), '6', '6', '6', SET8|'6', SET8|'6', SET8|'6', SET8|'6', 0x80, 0x02,
+/* sc=4e */ F(56), '+', '+', '+', SET8|'+', SET8|'+', SET8|'+', SET8|'+', 0x80, 0x02,
+/* sc=4f */ F(57), '1', '1', '1', SET8|'1', SET8|'1', SET8|'1', SET8|'1', 0x80, 0x02,
+/* sc=50 */ F(58), '2', '2', '2', SET8|'2', SET8|'2', SET8|'2', SET8|'2', 0x80, 0x02,
+/* sc=51 */ F(59), '3', '3', '3', SET8|'3', SET8|'3', SET8|'3', SET8|'3', 0x80, 0x02,
+/* sc=52 */ F(60), '0', '0', '0', SET8|'0', SET8|'0', SET8|'0', SET8|'0', 0x80, 0x02,
+/* sc=53 */ F(54), '.', 0x7F, 0x7F, SET8|0x7F, SET8|0x7F, RBT, SET8|0x7F, 0x82, 0x02,
+/* sc=54 */ ALK, ALK, ALK, ALK, ALK, ALK, ALK, ALK, 0xFF, 0x00,
+/* sc=55 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=56 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=57 */ F(11), F(23), F(35), F(47), S(11), S(11), S(11), S(11), 0xFF, 0x00,
+/* sc=58 */ F(12), F(24), F(36), F(48), S(12), S(12), S(12), S(12), 0xFF, 0x00,
+/* sc=59 */ 0x0D, 0x0D, 0x0A, 0x0A, SET8|0x0D, SET8|0x0D, SET8|0x0A, SET8|0x0A, 0x00, 0x00,
+/* sc=5a */ RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, 0xFF, 0x00,
+/* sc=5b */ '/', '/', NOP, NOP, SET8|'/', SET8|'/', NOP, NOP, 0x33, 0x00,
+/* sc=5c */ NEXT, NOP, DBG, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=5d */ RALT, RALT, RALT, RALT, RALT, RALT, RALT, RALT, 0xFF, 0x00,
+/* sc=5e */ F(49), F(49), F(49), F(49), F(49), F(49), F(49), F(49), 0xFF, 0x00,
+/* sc=5f */ F(50), F(50), F(50), F(50), F(50), F(50), F(50), F(50), 0xFF, 0x00,
+/* sc=60 */ F(51), F(51), F(51), F(51), F(51), F(51), F(51), F(51), 0xFF, 0x00,
+/* sc=61 */ F(53), F(53), F(53), F(53), F(53), F(53), F(53), F(53), 0xFF, 0x00,
+/* sc=62 */ F(55), F(55), F(55), F(55), F(55), F(55), F(55), F(55), 0xFF, 0x00,
+/* sc=63 */ F(57), F(57), F(57), F(57), F(57), F(57), F(57), F(57), 0xFF, 0x00,
+/* sc=64 */ F(58), F(58), F(58), F(58), F(58), F(58), F(58), F(58), 0xFF, 0x00,
+/* sc=65 */ F(59), F(59), F(59), F(59), F(59), F(59), F(59), F(59), 0xFF, 0x00,
+/* sc=66 */ F(60), F(60), F(60), F(60), F(60), F(60), F(60), F(60), 0xFF, 0x00,
+/* sc=67 */ F(54), F(54), 0x7F, 0x7F, SET8|0x7F, SET8|0x7F, RBT, SET8|0x7F, 0xC2, 0x00,
+/* sc=68 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+/* sc=69 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=6a */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=6b */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=6c */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=6d */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=6e */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=6f */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=70 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=71 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=72 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=73 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=74 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=75 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=76 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=77 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=78 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=79 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=7a */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=7b */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=7c */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=7d */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=7e */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=7f */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* extended (ALTGR LOCK keys) */
+/* sc=00 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=01 */ 0x1B, 0x1B, NOP, NOP, SET8|0x1B, SET8|0x1B, DBG, NOP, 0x33, 0x00,
+/* sc=02 */ '!', '1', NOP, NOP, SET8|'1', SET8|'!', NOP, NOP, 0x33, 0x00,
+/* sc=03 */ '"', '2', 0x00, 0x00, SET8|'2', SET8|'@', SET8|0x00, SET8|0x00, 0x00, 0x00,
+/* sc=04 */ '\'', '3', NOP, NOP, SET8|'3', SET8|'#', NOP, NOP, 0x33, 0x00,
+/* sc=05 */ ';', '4', NOP, NOP, SET8|'4', SET8|'$', NOP, NOP, 0x33, 0x00,
+/* sc=06 */ ':', '5', NOP, NOP, SET8|'5', SET8|'%', NOP, NOP, 0x33, 0x00,
+/* sc=07 */ ',', '6', 0x1E, 0x1E, SET8|'6', SET8|'^', SET8|0x1E, SET8|0x1E, 0x00, 0x00,
+/* sc=08 */ '.', '7', NOP, NOP, SET8|'7', SET8|'&', NOP, NOP, 0x33, 0x00,
+/* sc=09 */ '*', '8', NOP, NOP, SET8|'8', SET8|'*', NOP, NOP, 0x33, 0x00,
+/* sc=0a */ '(', '9', NOP, NOP, SET8|'9', SET8|'(', NOP, NOP, 0x33, 0x00,
+/* sc=0b */ ')', '0', NOP, NOP, SET8|'0', SET8|')', NOP, NOP, 0x33, 0x00,
+/* sc=0c */ '-', '_', 0x1F, 0x1F, SET8|'-', SET8|'_', SET8|0x1F, SET8|0x1F, 0x00, 0x00,
+/* sc=0d */ '=', '+', NOP, NOP, SET8|'=', SET8|'+', NOP, NOP, 0x33, 0x00,
+/* sc=0e */ 0x08, 0x08, 0x7F, 0x7F, SET8|0x08, SET8|0x08, SET8|0x7F, SET8|0x7F, 0x00, 0x00,
+/* sc=0f */ 0x09, F(16), NOP, NOP, SET8|0x09, F(16), NOP, NOP, 0x77, 0x00,
+/* sc=10 */ 0xca, 0xea, 0x11, 0x11, SET8|'q', SET8|'Q', SET8|0x11, SET8|0x11, 0x00, 0x01,
+/* sc=11 */ 0xc3, 0xe3, 0x17, 0x17, SET8|'w', SET8|'W', SET8|0x17, SET8|0x17, 0x00, 0x01,
+/* sc=12 */ 0xd5, 0xf5, 0x05, 0x05, SET8|'e', SET8|'E', SET8|0x05, SET8|0x05, 0x00, 0x01,
+/* sc=13 */ 0xcb, 0xeb, 0x12, 0x12, SET8|'r', SET8|'R', SET8|0x12, SET8|0x12, 0x00, 0x01,
+/* sc=14 */ 0xc5, 0xe5, 0x14, 0x14, SET8|'t', SET8|'T', SET8|0x14, SET8|0x14, 0x00, 0x01,
+/* sc=15 */ 0xce, 0xee, 0x19, 0x19, SET8|'y', SET8|'Y', SET8|0x19, SET8|0x19, 0x00, 0x01,
+/* sc=16 */ 0xc7, 0xe7, 0x15, 0x15, SET8|'u', SET8|'U', SET8|0x15, SET8|0x15, 0x00, 0x01,
+/* sc=17 */ 0xdb, 0xfb, 0x09, 0x09, SET8|'i', SET8|'I', SET8|0x09, SET8|0x09, 0x00, 0x01,
+/* sc=18 */ 0xdd, 0xfd, 0x0F, 0x0F, SET8|'o', SET8|'O', SET8|0x0F, SET8|0x0F, 0x00, 0x01,
+/* sc=19 */ 0xda, 0xfa, 0x10, 0x10, SET8|'p', SET8|'P', SET8|0x10, SET8|0x10, 0x00, 0x01,
+/* sc=1a */ 0xc8, 0xe8, 0x1B, 0x1B, SET8|'[', SET8|'{', SET8|0x1B, SET8|0x1B, 0x00, 0x01,
+/* sc=1b */ 0xdf, 0xff, 0x1D, 0x1D, SET8|']', SET8|'}', SET8|0x1D, SET8|0x1D, 0x00, 0x01,
+/* sc=1c */ 0x0D, 0x0D, 0x0A, 0x0A, SET8|0x0D, SET8|0x0D, SET8|0x0A, SET8|0x0A, 0x00, 0x00,
+/* sc=1d */ LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, 0xFF, 0x00,
+/* sc=1e */ 0xc6, 0xe6, 0x01, 0x01, SET8|'a', SET8|'A', SET8|0x01, SET8|0x01, 0x00, 0x01,
+/* sc=1f */ 0xd9, 0xf9, 0x13, 0x13, SET8|'s', SET8|'S', SET8|0x13, SET8|0x13, 0x00, 0x01,
+/* sc=20 */ 0xd7, 0xf7, 0x04, 0x04, SET8|'d', SET8|'D', SET8|0x04, SET8|0x04, 0x00, 0x01,
+/* sc=21 */ 0xc1, 0xe1, 0x06, 0x06, SET8|'f', SET8|'F', SET8|0x06, SET8|0x06, 0x00, 0x01,
+/* sc=22 */ 0xd0, 0xf0, 0x07, 0x07, SET8|'g', SET8|'G', SET8|0x07, SET8|0x07, 0x00, 0x01,
+/* sc=23 */ 0xd2, 0xf2, 0x08, 0x08, SET8|'h', SET8|'H', SET8|0x08, SET8|0x08, 0x00, 0x01,
+/* sc=24 */ 0xcf, 0xef, 0x0A, 0x0A, SET8|'j', SET8|'J', SET8|0x0A, SET8|0x0A, 0x00, 0x01,
+/* sc=25 */ 0xcc, 0xec, 0x0B, 0x0B, SET8|'k', SET8|'K', SET8|0x0B, SET8|0x0B, 0x00, 0x01,
+/* sc=26 */ 0xc4, 0xe4, 0x0C, 0x0C, SET8|'l', SET8|'L', SET8|0x0C, SET8|0x0C, 0x00, 0x01,
+/* sc=27 */ 0xd6, 0xf6, NOP, NOP, SET8|';', SET8|':', NOP, NOP, 0x33, 0x01,
+/* sc=28 */ 0xdc, 0xfc, NOP, NOP, SET8|'\'', SET8|'"', NOP, NOP, 0x33, 0x01,
+/* sc=29 */ 0xa3, 0xb3, NOP, NOP, SET8|'`', SET8|'~', NOP, NOP, 0x33, 0x01,
+/* sc=2a */ LSH, LSH, LSH, LSH, LSH, LSH, LSH, LSH, 0xFF, 0x00,
+/* sc=2b */ '\\', '|', 0x1C, 0x1C, SET8|'\\', SET8|'|', SET8|0x1C, SET8|0x1C, 0x00, 0x00,
+/* sc=2c */ 0xd1, 0xf1, 0x1A, 0x1A, SET8|'z', SET8|'Z', SET8|0x1A, SET8|0x1A, 0x00, 0x01,
+/* sc=2d */ 0xde, 0xfe, 0x18, 0x18, SET8|'x', SET8|'X', SET8|0x18, SET8|0x18, 0x00, 0x01,
+/* sc=2e */ 0xd3, 0xf3, 0x03, 0x03, SET8|'c', SET8|'C', SET8|0x03, SET8|0x03, 0x00, 0x01,
+/* sc=2f */ 0xcd, 0xed, 0x16, 0x16, SET8|'v', SET8|'V', SET8|0x16, SET8|0x16, 0x00, 0x01,
+/* sc=30 */ 0xc9, 0xe9, 0x02, 0x02, SET8|'b', SET8|'B', SET8|0x02, SET8|0x02, 0x00, 0x01,
+/* sc=31 */ 0xd4, 0xf4, 0x0E, 0x0E, SET8|'n', SET8|'N', SET8|0x0E, SET8|0x0E, 0x00, 0x01,
+/* sc=32 */ 0xd8, 0xf8, 0x0D, 0x0D, SET8|'m', SET8|'M', SET8|0x0D, SET8|0x0D, 0x00, 0x01,
+/* sc=33 */ 0xc2, 0xe2, NOP, NOP, SET8|',', SET8|'<', NOP, NOP, 0x33, 0x01,
+/* sc=34 */ 0xc0, 0xe0, NOP, NOP, SET8|'.', SET8|'>', NOP, NOP, 0x33, 0x01,
+/* sc=35 */ '/', '?', NOP, NOP, SET8|'/', SET8|'?', NOP, NOP, 0x33, 0x00,
+/* sc=36 */ RSH, RSH, RSH, RSH, RSH, RSH, RSH, RSH, 0xFF, 0x00,
+/* sc=37 */ '*', '*', 0x0A, 0x0A, SET8|'*', SET8|'*', SET8|0x0A, SET8|0x0A, 0x00, 0x00,
+/* sc=38 */ LALT, LALT, LALT, LALT, LALT, LALT, LALT, LALT, 0xFF, 0x00,
+/* sc=39 */ ' ', ' ', ' ', ' ', SET8|' ', SET8|' ', SET8|' ', SET8|' ', 0x00, 0x00,
+/* sc=3a */ ALK, CLK, CLK, CLK, CLK, CLK, CLK, CLK, 0xFF, 0x00,
+/* sc=3b */ F( 1), F(13), F(25), F(37), S( 1), S(11), S( 1), S(11), 0xFF, 0x00,
+/* sc=3c */ F( 2), F(14), F(26), F(38), S( 2), S(12), S( 2), S(12), 0xFF, 0x00,
+/* sc=3d */ F( 3), F(15), F(27), F(39), S( 3), S(13), S( 3), S(13), 0xFF, 0x00,
+/* sc=3e */ F( 4), F(16), F(28), F(40), S( 4), S(14), S( 4), S(14), 0xFF, 0x00,
+/* sc=3f */ F( 5), F(17), F(29), F(41), S( 5), S(15), S( 5), S(15), 0xFF, 0x00,
+/* sc=40 */ F( 6), F(18), F(30), F(42), S( 6), S(16), S( 6), S(16), 0xFF, 0x00,
+/* sc=41 */ F( 7), F(19), F(31), F(43), S( 7), S( 7), S( 7), S( 7), 0xFF, 0x00,
+/* sc=42 */ F( 8), F(20), F(32), F(44), S( 8), S( 8), S( 8), S( 8), 0xFF, 0x00,
+/* sc=43 */ F( 9), F(21), F(33), F(45), S( 9), S( 9), S( 9), S( 9), 0xFF, 0x00,
+/* sc=44 */ F(10), F(22), F(34), F(46), S(10), S(10), S(10), S(10), 0xFF, 0x00,
+/* sc=45 */ NLK, NLK, NLK, NLK, NLK, NLK, NLK, NLK, 0xFF, 0x00,
+/* sc=46 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+/* sc=47 */ F(49), '7', '7', '7', SET8|'7', SET8|'7', SET8|'7', SET8|'7', 0x80, 0x02,
+/* sc=48 */ F(50), '8', '8', '8', SET8|'8', SET8|'8', SET8|'8', SET8|'8', 0x80, 0x02,
+/* sc=49 */ F(51), '9', '9', '9', SET8|'9', SET8|'9', SET8|'9', SET8|'9', 0x80, 0x02,
+/* sc=4a */ F(52), '-', '-', '-', SET8|'-', SET8|'-', SET8|'-', SET8|'-', 0x80, 0x02,
+/* sc=4b */ F(53), '4', '4', '4', SET8|'4', SET8|'4', SET8|'4', SET8|'4', 0x80, 0x02,
+/* sc=4c */ F(48), '5', '5', '5', SET8|'5', SET8|'5', SET8|'5', SET8|'5', 0x80, 0x02,
+/* sc=4d */ F(55), '6', '6', '6', SET8|'6', SET8|'6', SET8|'6', SET8|'6', 0x80, 0x02,
+/* sc=4e */ F(56), '+', '+', '+', SET8|'+', SET8|'+', SET8|'+', SET8|'+', 0x80, 0x02,
+/* sc=4f */ F(57), '1', '1', '1', SET8|'1', SET8|'1', SET8|'1', SET8|'1', 0x80, 0x02,
+/* sc=50 */ F(58), '2', '2', '2', SET8|'2', SET8|'2', SET8|'2', SET8|'2', 0x80, 0x02,
+/* sc=51 */ F(59), '3', '3', '3', SET8|'3', SET8|'3', SET8|'3', SET8|'3', 0x80, 0x02,
+/* sc=52 */ F(60), '0', '0', '0', SET8|'0', SET8|'0', SET8|'0', SET8|'0', 0x80, 0x02,
+/* sc=53 */ F(54), '.', 0x7F, 0x7F, SET8|0x7F, SET8|0x7F, RBT, SET8|0x7F, 0x82, 0x02,
+/* sc=54 */ ALK, ALK, ALK, ALK, ALK, ALK, ALK, ALK, 0xFF, 0x00,
+/* sc=55 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=56 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=57 */ F(11), F(23), F(35), F(47), S(11), S(11), S(11), S(11), 0xFF, 0x00,
+/* sc=58 */ F(12), F(24), F(36), F(48), S(12), S(12), S(12), S(12), 0xFF, 0x00,
+/* sc=59 */ 0x0D, 0x0D, 0x0A, 0x0A, SET8|0x0D, SET8|0x0D, SET8|0x0A, SET8|0x0A, 0x00, 0x00,
+/* sc=5a */ RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, 0xFF, 0x00,
+/* sc=5b */ '/', '/', NOP, NOP, SET8|'/', SET8|'/', NOP, NOP, 0x33, 0x00,
+/* sc=5c */ NEXT, NOP, DBG, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=5d */ RALT, RALT, RALT, RALT, RALT, RALT, RALT, RALT, 0xFF, 0x00,
+/* sc=5e */ F(49), F(49), F(49), F(49), F(49), F(49), F(49), F(49), 0xFF, 0x00,
+/* sc=5f */ F(50), F(50), F(50), F(50), F(50), F(50), F(50), F(50), 0xFF, 0x00,
+/* sc=60 */ F(51), F(51), F(51), F(51), F(51), F(51), F(51), F(51), 0xFF, 0x00,
+/* sc=61 */ F(53), F(53), F(53), F(53), F(53), F(53), F(53), F(53), 0xFF, 0x00,
+/* sc=62 */ F(55), F(55), F(55), F(55), F(55), F(55), F(55), F(55), 0xFF, 0x00,
+/* sc=63 */ F(57), F(57), F(57), F(57), F(57), F(57), F(57), F(57), 0xFF, 0x00,
+/* sc=64 */ F(58), F(58), F(58), F(58), F(58), F(58), F(58), F(58), 0xFF, 0x00,
+/* sc=65 */ F(59), F(59), F(59), F(59), F(59), F(59), F(59), F(59), 0xFF, 0x00,
+/* sc=66 */ F(60), F(60), F(60), F(60), F(60), F(60), F(60), F(60), 0xFF, 0x00,
+/* sc=67 */ F(54), F(54), 0x7F, 0x7F, SET8|0x7F, SET8|0x7F, RBT, SET8|0x7F, 0xC2, 0x00,
+/* sc=68 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+};
+
+#endif
+
+#if !defined(DKKEYMAP) && !defined(UKKEYMAP) && !defined(GRKEYMAP) && !defined(SWKEYMAP) && !defined(RUKEYMAP)
+keymap_t key_map = { 0x69, /* US iso8859 keymap */
+/* alt
+ * scan cntrl alt alt cntrl
+ * code base shift cntrl shift alt shift cntrl shift spcl flgs
+ * ---------------------------------------------------------------------------
+ */
+/* sc=00 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=01 */ 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, DBG, 0x1B, 0x02, 0x00,
+/* sc=02 */ '1', '!', NOP, NOP, '1', '!', NOP, NOP, 0x33, 0x00,
+/* sc=03 */ '2', '@', 0x00, 0x00, '2', '@', 0x00, 0x00, 0x00, 0x00,
+/* sc=04 */ '3', '#', NOP, NOP, '3', '#', NOP, NOP, 0x33, 0x00,
+/* sc=05 */ '4', '$', NOP, NOP, '4', '$', NOP, NOP, 0x33, 0x00,
+/* sc=06 */ '5', '%', NOP, NOP, '5', '%', NOP, NOP, 0x33, 0x00,
+/* sc=07 */ '6', '^', 0x1E, 0x1E, '6', '^', 0x1E, 0x1E, 0x00, 0x00,
+/* sc=08 */ '7', '&', NOP, NOP, '7', '&', NOP, NOP, 0x33, 0x00,
+/* sc=09 */ '8', '*', NOP, NOP, '8', '*', NOP, NOP, 0x33, 0x00,
+/* sc=0a */ '9', '(', NOP, NOP, '9', '(', NOP, NOP, 0x33, 0x00,
+/* sc=0b */ '0', ')', NOP, NOP, '0', ')', NOP, NOP, 0x33, 0x00,
+/* sc=0c */ '-', '_', 0x1F, 0x1F, '-', '_', 0x1F, 0x1F, 0x00, 0x00,
+/* sc=0d */ '=', '+', NOP, NOP, '=', '+', NOP, NOP, 0x33, 0x00,
+/* sc=0e */ 0x08, 0x08, 0x7F, 0x7F, 0x08, 0x08, 0x7F, 0x7F, 0x00, 0x00,
+/* sc=0f */ 0x09, 0x08, NOP, NOP, 0x09, 0x08, NOP, NOP, 0x33, 0x00,
+/* sc=10 */ 'q', 'Q', 0x11, 0x11, 'q', 'Q', 0x11, 0x11, 0x00, 0x01,
+/* sc=11 */ 'w', 'W', 0x17, 0x17, 'w', 'W', 0x17, 0x17, 0x00, 0x01,
+/* sc=12 */ 'e', 'E', 0x05, 0x05, 'e', 'E', 0x05, 0x05, 0x00, 0x01,
+/* sc=13 */ 'r', 'R', 0x12, 0x12, 'r', 'R', 0x12, 0x12, 0x00, 0x01,
+/* sc=14 */ 't', 'T', 0x14, 0x14, 't', 'T', 0x14, 0x14, 0x00, 0x01,
+/* sc=15 */ 'y', 'Y', 0x19, 0x19, 'y', 'Y', 0x19, 0x19, 0x00, 0x01,
+/* sc=16 */ 'u', 'U', 0x15, 0x15, 'u', 'U', 0x15, 0x15, 0x00, 0x01,
+/* sc=17 */ 'i', 'I', 0x09, 0x09, 'i', 'I', 0x09, 0x09, 0x00, 0x01,
+/* sc=18 */ 'o', 'O', 0x0F, 0x0F, 'o', 'O', 0x0F, 0x0F, 0x00, 0x01,
+/* sc=19 */ 'p', 'P', 0x10, 0x10, 'p', 'P', 0x10, 0x10, 0x00, 0x01,
+/* sc=1a */ '[', '{', 0x1B, 0x1B, '[', '{', 0x1B, 0x1B, 0x00, 0x00,
+/* sc=1b */ ']', '}', 0x1D, 0x1D, ']', '}', 0x1D, 0x1D, 0x00, 0x00,
+/* sc=1c */ 0x0D, 0x0D, 0x0A, 0x0A, 0x0D, 0x0D, 0x0A, 0x0A, 0x00, 0x00,
+/* sc=1d */ LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, 0xFF, 0x00,
+/* sc=1e */ 'a', 'A', 0x01, 0x01, 'a', 'A', 0x01, 0x01, 0x00, 0x01,
+/* sc=1f */ 's', 'S', 0x13, 0x13, 's', 'S', 0x13, 0x13, 0x00, 0x01,
+/* sc=20 */ 'd', 'D', 0x04, 0x04, 'd', 'D', 0x04, 0x04, 0x00, 0x01,
+/* sc=21 */ 'f', 'F', 0x06, 0x06, 'f', 'F', 0x06, 0x06, 0x00, 0x01,
+/* sc=22 */ 'g', 'G', 0x07, 0x07, 'g', 'G', 0x07, 0x07, 0x00, 0x01,
+/* sc=23 */ 'h', 'H', 0x08, 0x08, 'h', 'H', 0x08, 0x08, 0x00, 0x01,
+/* sc=24 */ 'j', 'J', 0x0A, 0x0A, 'j', 'J', 0x0A, 0x0A, 0x00, 0x01,
+/* sc=25 */ 'k', 'K', 0x0B, 0x0B, 'k', 'K', 0x0B, 0x0B, 0x00, 0x01,
+/* sc=26 */ 'l', 'L', 0x0C, 0x0C, 'l', 'L', 0x0C, 0x0C, 0x00, 0x01,
+/* sc=27 */ ';', ':', NOP, NOP, ';', ':', NOP, NOP, 0x33, 0x00,
+/* sc=28 */ '\'', '"', NOP, NOP, '\'', '"', NOP, NOP, 0x33, 0x00,
+/* sc=29 */ '`', '~', NOP, NOP, '`', '~', NOP, NOP, 0x33, 0x00,
+/* sc=2a */ LSH, LSH, LSH, LSH, LSH, LSH, LSH, LSH, 0xFF, 0x00,
+/* sc=2b */ '\\', '|', 0x1C, 0x1C, '\\', '|', 0x1C, 0x1C, 0x00, 0x00,
+/* sc=2c */ 'z', 'Z', 0x1A, 0x1A, 'z', 'Z', 0x1A, 0x1A, 0x00, 0x01,
+/* sc=2d */ 'x', 'X', 0x18, 0x18, 'x', 'X', 0x18, 0x18, 0x00, 0x01,
+/* sc=2e */ 'c', 'C', 0x03, 0x03, 'c', 'C', 0x03, 0x03, 0x00, 0x01,
+/* sc=2f */ 'v', 'V', 0x16, 0x16, 'v', 'V', 0x16, 0x16, 0x00, 0x01,
+/* sc=30 */ 'b', 'B', 0x02, 0x02, 'b', 'B', 0x02, 0x02, 0x00, 0x01,
+/* sc=31 */ 'n', 'N', 0x0E, 0x0E, 'n', 'N', 0x0E, 0x0E, 0x00, 0x01,
+/* sc=32 */ 'm', 'M', 0x0D, 0x0D, 'm', 'M', 0x0D, 0x0D, 0x00, 0x01,
+/* sc=33 */ ',', '<', NOP, NOP, ',', '<', NOP, NOP, 0x33, 0x00,
+/* sc=34 */ '.', '>', NOP, NOP, '.', '>', NOP, NOP, 0x33, 0x00,
+/* sc=35 */ '/', '?', NOP, NOP, '/', '?', NOP, NOP, 0x33, 0x00,
+/* sc=36 */ RSH, RSH, RSH, RSH, RSH, RSH, RSH, RSH, 0xFF, 0x00,
+/* sc=37 */ '*', '*', 0x0A, 0x0A, '*', '*', 0x0A, 0x0A, 0x33, 0x00,
+/* sc=38 */ LALT, LALT, LALT, LALT, LALT, LALT, LALT, LALT, 0xFF, 0x00,
+/* sc=39 */ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 0x00, 0x00,
+/* sc=3a */ CLK, CLK, CLK, CLK, CLK, CLK, CLK, CLK, 0xFF, 0x00,
+/* sc=3b */ F( 1), F(13), F(25), F(37), S( 1), S(11), S( 1), S(11), 0xFF, 0x00,
+/* sc=3c */ F( 2), F(14), F(26), F(38), S( 2), S(12), S( 2), S(12), 0xFF, 0x00,
+/* sc=3d */ F( 3), F(15), F(27), F(39), S( 3), S(13), S( 3), S(13), 0xFF, 0x00,
+/* sc=3e */ F( 4), F(16), F(28), F(40), S( 4), S(14), S( 4), S(14), 0xFF, 0x00,
+/* sc=3f */ F( 5), F(17), F(29), F(41), S( 5), S(15), S( 5), S(15), 0xFF, 0x00,
+/* sc=40 */ F( 6), F(18), F(30), F(42), S( 6), S(16), S( 6), S(16), 0xFF, 0x00,
+/* sc=41 */ F( 7), F(19), F(31), F(43), S( 7), S( 7), S( 7), S( 7), 0xFF, 0x00,
+/* sc=42 */ F( 8), F(20), F(32), F(44), S( 8), S( 8), S( 8), S( 8), 0xFF, 0x00,
+/* sc=43 */ F( 9), F(21), F(33), F(45), S( 9), S( 9), S( 9), S( 9), 0xFF, 0x00,
+/* sc=44 */ F(10), F(22), F(34), F(46), S(10), S(10), S(10), S(10), 0xFF, 0x00,
+/* sc=45 */ NLK, NLK, NLK, NLK, NLK, NLK, NLK, NLK, 0xFF, 0x00,
+/* sc=46 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+/* sc=47 */ F(49), '7', '7', '7', '7', '7', '7', '7', 0x80, 0x02,
+/* sc=48 */ F(50), '8', '8', '8', '8', '8', '8', '8', 0x80, 0x02,
+/* sc=49 */ F(51), '9', '9', '9', '9', '9', '9', '9', 0x80, 0x02,
+/* sc=4a */ F(52), '-', '-', '-', '-', '-', '-', '-', 0x80, 0x02,
+/* sc=4b */ F(53), '4', '4', '4', '4', '4', '4', '4', 0x80, 0x02,
+/* sc=4c */ NOP, '5', '5', '5', '5', '5', '5', '5', 0x80, 0x02,
+/* sc=4d */ F(55), '6', '6', '6', '6', '6', '6', '6', 0x80, 0x02,
+/* sc=4e */ F(56), '+', '+', '+', '+', '+', '+', '+', 0x80, 0x02,
+/* sc=4f */ F(57), '1', '1', '1', '1', '1', '1', '1', 0x80, 0x02,
+/* sc=50 */ F(58), '2', '2', '2', '2', '2', '2', '2', 0x80, 0x02,
+/* sc=51 */ F(59), '3', '3', '3', '3', '3', '3', '3', 0x80, 0x02,
+/* sc=52 */ F(60), '0', '0', '0', '0', '0', '0', '0', 0x80, 0x02,
+/* sc=53 */ 0x7F, '.', 0x7F, 0x7F, 0x7F, 0x7F, RBT, 0x7F, 0x02, 0x02,
+/* sc=54 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=55 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=56 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=57 */ F(11), F(23), F(35), F(47), S(11), S(11), S(11), S(11), 0xFF, 0x00,
+/* sc=58 */ F(12), F(24), F(36), F(48), S(12), S(12), S(12), S(12), 0xFF, 0x00,
+/* sc=59 */ 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x00, 0x00,
+/* sc=5a */ RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, 0xFF, 0x00,
+/* sc=5b */ '/', '/', '/', '/', '/', '/', '/', '/', 0x00, 0x00,
+/* sc=5c */ NEXT, NOP, DBG, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=5d */ RALT, RALT, RALT, RALT, RALT, RALT, RALT, RALT, 0xFF, 0x00,
+/* sc=5e */ F(49), F(49), F(49), F(49), F(49), F(49), F(49), F(49), 0xFF, 0x00,
+/* sc=5f */ F(50), F(50), F(50), F(50), F(50), F(50), F(50), F(50), 0xFF, 0x00,
+/* sc=60 */ F(51), F(51), F(51), F(51), F(51), F(51), F(51), F(51), 0xFF, 0x00,
+/* sc=61 */ F(53), F(53), F(53), F(53), F(53), F(53), F(53), F(53), 0xFF, 0x00,
+/* sc=62 */ F(55), F(55), F(55), F(55), F(55), F(55), F(55), F(55), 0xFF, 0x00,
+/* sc=63 */ F(57), F(57), F(57), F(57), F(57), F(57), F(57), F(57), 0xFF, 0x00,
+/* sc=64 */ F(58), F(58), F(58), F(58), F(58), F(58), F(58), F(58), 0xFF, 0x00,
+/* sc=65 */ F(59), F(59), F(59), F(59), F(59), F(59), F(59), F(59), 0xFF, 0x00,
+/* sc=66 */ F(60), F(60), F(60), F(60), F(60), F(60), F(60), F(60), 0xFF, 0x00,
+/* sc=67 */ F(54), F(54), F(54), F(54), F(54), F(54), RBT, F(54), 0xFF, 0x00,
+/* sc=68 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+};
+
+#endif
+
+fkeytab_t fkey_tab[60] = {
+/* 00-03 */ {"\033[M", 3}, {"\033[N", 3}, {"\033[O", 3}, {"\033[P", 3},
+/* 04-07 */ {"\033[Q", 3}, {"\033[R", 3}, {"\033[S", 3}, {"\033[T", 3},
+/* 08-0B */ {"\033[U", 3}, {"\033[V", 3}, {"\033[W", 3}, {"\033[X", 3},
+/* 0C-0F */ {"\033[W", 3}, {"\033[X", 3}, {"\033[Y", 3}, {"\033[Z", 3},
+/* 10-13 */ {"\033[a", 3}, {"\033[b", 3}, {"\033[c", 3}, {"\033[d", 3},
+/* 14-17 */ {"\033[e", 3}, {"\033[f", 3}, {"\033[g", 3}, {"\033[h", 3},
+/* 18-1B */ {"\033[g", 3}, {"\033[h", 3}, {"\033[i", 3}, {"\033[j", 3},
+/* 1C-1F */ {"\033[k", 3}, {"\033[l", 3}, {"\033[m", 3}, {"\033[n", 3},
+/* 20-23 */ {"\033[o", 3}, {"\033[p", 3}, {"\033[q", 3}, {"\033[r", 3},
+/* 24-27 */ {"\033[g", 3}, {"\033[h", 3}, {"\033[i", 3}, {"\033[j", 3},
+/* 28-2B */ {"\033[k", 3}, {"\033[l", 3}, {"\033[m", 3}, {"\033[n", 3},
+/* 2C-2F */ {"\033[o", 3}, {"\033[p", 3}, {"\033[q", 3}, {"\033[r", 3},
+/* 30-33 */ {"\033[H", 3}, {"\033[A", 3}, {"\033[I", 3}, {"-" , 1},
+/* 34-37 */ {"\033[D", 3}, {"\177" , 1}, {"\033[C", 3}, {"+" , 1},
+/* 38-3B */ {"\033[F", 3}, {"\033[B", 3}, {"\033[G", 3}, {"\033[L", 3}
+};
diff --git a/sys/dev/mcd/mcd.c b/sys/dev/mcd/mcd.c
new file mode 100644
index 0000000..683b0e1
--- /dev/null
+++ b/sys/dev/mcd/mcd.c
@@ -0,0 +1,1335 @@
+/*
+ * Copyright 1993 by Holger Veit (data part)
+ * Copyright 1993 by Brian Moore (audio part)
+ * Changes Copyright 1993 by Gary Clark II
+ *
+ * Rewrote probe routine to work on newer Mitsumi drives.
+ * Additional changes (C) 1994 by Jordan K. Hubbard
+ *
+ * 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: mcd.c,v 1.15 1994/04/20 07:06:41 davidg Exp $
+ */
+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 0
+
+/* 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 */
+
+/* These are apparently the different states a mitsumi can get up to */
+#define MCDCDABSENT 0x0030
+#define MCDCDPRESENT 0x0020
+#define MCDSCLOSED 0x0080
+#define MCDSOPEN 0x00a0
+
+/* 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);
+void 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; i<MAXPARTITIONS; i++) cd->partflags[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<<part);
+ if (part == RAW_PART && phys != 0)
+ cd->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<<part);
+ MCD_TRACE("close: partition=%d\n",part,0,0,0);
+
+ return 0;
+}
+
+void
+mcdstrategy(struct buf *bp)
+{
+ struct mcd_data *cd;
+ struct buf *qp;
+ int s;
+
+ int unit = mcd_unit(bp->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;
+ }
+ } else {
+ bp->b_pblkno = bp->b_blkno;
+ bp->b_resid = 0;
+ }
+
+ /* 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->b_actf;
+ 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);
+}
+
+/* Wait for non-busy - return 0 on timeout */
+static int
+twiddle_thumbs(int port, int unit, int count, char *whine)
+{
+ int i;
+
+ for (i = 0; i < count; i++) {
+ if (!(inb(port+MCD_FLAGS) & MCD_ST_BUSY)) {
+ return 1;
+ }
+ }
+#ifdef MCD_TO_WARNING_ON
+ printf("mcd%d: timeout %s\n", unit, whine);
+#endif
+ return 0;
+}
+
+/* check to see if a Mitsumi CD-ROM is attached to the ISA bus */
+
+int
+mcd_probe(struct isa_device *dev)
+{
+ int port = dev->id_iobase;
+ int unit = dev->id_unit;
+ int i, j;
+ int status;
+ unsigned char stbytes[3];
+
+ 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, M_RESET);
+
+ /*
+ * delay awhile by getting any pending garbage (old data) and
+ * throwing it away.
+ */
+ for (i = 1000000; i != 0; i--) {
+ inb(port+MCD_FLAGS);
+ }
+
+ /* Get status */
+ outb(port+MCD_DATA, MCD_CMDGETSTAT);
+ if (!twiddle_thumbs(port, unit, 1000000, "getting status")) {
+ return 0; /* Timeout */
+ }
+ status = inb(port+MCD_DATA);
+ if (status != MCDCDABSENT && status != MCDCDPRESENT &&
+ status != MCDSOPEN && status != MCDSCLOSED)
+ return 0; /* Not actually a Mitsumi drive here */
+ /* Get version information */
+ outb(port+MCD_DATA, MCD_CMDCONTINFO);
+ for (j = 0; j < 3; j++) {
+ if (!twiddle_thumbs(port, unit, 3000, "getting version info")) {
+ return 0;
+ }
+ stbytes[j] = (inb(port+MCD_DATA) & 0xFF);
+ }
+ printf("mcd%d: version information is %x %c %x\n", unit,
+ stbytes[0], stbytes[1], stbytes[2]);
+ if (stbytes[1] >= 4) {
+ outb(port+MCD_CTRL, M_PICKLE);
+ printf("mcd%d: Adjusted for newer drive model\n", unit);
+ }
+ return 4;
+}
+
+
+static int
+mcd_waitrdy(int port,int dly)
+{
+ int i;
+
+ /* wait until xfer port senses data ready */
+ for (i=0; i<dly; i++) {
+ if ((inb(port+mcd_xfer) & MCD_ST_BUSY)==0)
+ return 0;
+ mcd_delay(1);
+ }
+ return -1;
+}
+
+static int
+mcd_getreply(int unit,int dly)
+{
+ int i;
+ struct mcd_data *cd = mcd_data + unit;
+ int port = cd->iobase;
+
+ /* 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<nmax; i++) {
+ /* wait for data */
+ if ((k = mcd_getreply(unit,DELAY_GETREPLY)) < 0) {
+#ifdef MCD_TO_WARNING_ON
+ printf("mcd%d: timeout mcd_get\n",unit);
+#endif
+ return -1;
+ }
+ buf[i] = k;
+ }
+ return i;
+}
+
+static int
+mcd_send(int unit, int cmd,int nretrys)
+{
+ int i,k;
+ int port = mcd_data[unit].iobase;
+
+/*MCD_TRACE("mcd_send: command = 0x%x\n",cmd,0,0,0);*/
+ for (i=0; i<nretrys; i++) {
+ outb(port+mcd_command, cmd);
+ if ((k=mcd_getstat(unit,0)) != -1) {
+ break;
+ }
+ }
+ if (i == nretrys) {
+ printf("mcd%d: mcd_send retry cnt exceeded\n",unit);
+ return -1;
+ }
+/*MCD_TRACE("mcd_send: status = 0x%x\n",k,0,0,0);*/
+ return 0;
+}
+
+static int
+bcd2bin(bcd_t b)
+{
+ return (b >> 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;
+}
+
+void
+mcdintr(unit)
+ int 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((timeout_func_t)mcd_doread,
+ (caddr_t)MCD_S_WAITSTAT,hz/100); /* XXX */
+ return;
+ case MCD_S_WAITSTAT:
+ untimeout((timeout_func_t)mcd_doread,(caddr_t)MCD_S_WAITSTAT);
+ if (mbx->count-- >= 0) {
+ if (inb(port+mcd_xfer) & MCD_ST_BUSY) {
+ timeout((timeout_func_t)mcd_doread,
+ (caddr_t)MCD_S_WAITSTAT,hz/100); /* XXX */
+ 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((timeout_func_t)mcd_doread,
+ (caddr_t)MCD_S_WAITMODE,hz/100); /* XXX */
+ return;
+ } else {
+#ifdef MCD_TO_WARNING_ON
+ printf("mcd%d: timeout getstatus\n",unit);
+#endif
+ goto readerr;
+ }
+
+ case MCD_S_WAITMODE:
+ untimeout((timeout_func_t)mcd_doread,(caddr_t)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((timeout_func_t)mcd_doread,(caddr_t)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((timeout_func_t)mcd_doread,
+ (caddr_t)MCD_S_WAITREAD,hz/100); /* XXX */
+ return;
+ case MCD_S_WAITREAD:
+ untimeout((timeout_func_t)mcd_doread,(caddr_t)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; i<mbx->sz; 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((timeout_func_t)mcd_doread,
+ (caddr_t)MCD_S_WAITREAD,hz/100); /* XXX */
+ 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; retry<MCD_RETRYS; retry++)
+ {
+ outb(port+mcd_command, MCD_CMDSETMODE);
+ outb(port+mcd_command, mode);
+ if (mcd_getstat(unit, 0) != -1) return 0;
+ }
+
+ return -1;
+}
+
+static int
+mcd_toc_header(int unit, struct ioc_toc_header *th)
+{
+ struct mcd_data *cd = mcd_data + unit;
+
+ if (mcd_volinfo(unit) < 0) {
+ return ENXIO;
+ }
+
+ th->len = 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.addr[1] = cd->toc[i].hd_pos_msf[0];
+ ret_toc.rt.addr.addr[2] = cd->toc[i].hd_pos_msf[1];
+ ret_toc.rt.addr.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; retry<MCD_RETRYS; retry++) {
+ outb(port+mcd_command, MCD_CMDREAD2);
+ outb(port+mcd_command, pb->start_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 */
diff --git a/sys/dev/mcd/mcdreg.h b/sys/dev/mcd/mcdreg.h
new file mode 100644
index 0000000..0ce5de7
--- /dev/null
+++ b/sys/dev/mcd/mcdreg.h
@@ -0,0 +1,159 @@
+/*
+ * Copyright 1993 by Holger Veit (data part)
+ * Copyright 1993 by Brian Moore (audio part)
+ * Changes Copyright 1993 by Gary Clark II
+ * 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.
+ *
+ * This file contains definitions for some cdrom control commands
+ * and status codes. This info was "inherited" from the DOS MTMCDE.SYS
+ * driver, and is thus not complete (and may even be wrong). Some day
+ * the manufacturer or anyone else might provide better documentation,
+ * so this file (and the driver) will then have a better quality.
+ *
+ * $Id: mcdreg.h,v 1.2 1994/01/16 23:34:17 jkh Exp $
+ */
+
+#ifndef MCD_H
+#define MCD_H
+
+#ifdef __GNUC__
+#if __GNUC__ >= 2
+#pragma pack(1)
+#endif
+#endif
+
+typedef unsigned char bcd_t;
+#define M_msf(msf) msf[0]
+#define S_msf(msf) msf[1]
+#define F_msf(msf) msf[2]
+
+/* io lines used */
+#define MCD_IO_BASE 0x300
+
+#define mcd_command 0
+#define mcd_status 0
+#define mcd_rdata 0
+
+#define mcd_reset 1
+#define mcd_xfer 1
+#define mcd_ctl2 2 /* XXX Is this right? */
+#define mcd_config 3
+
+#define MCD_MASK_DMA 0x07 /* bits 2-0 = DMA channel */
+#define MCD_MASK_IRQ 0x70 /* bits 6-4 = INT number */
+ /* 001 = int 2,9 */
+ /* 010 = int 3 */
+ /* 011 = int 5 */
+ /* 100 = int 10 */
+ /* 101 = int 11 */
+/* flags */
+#define STATUS_AVAIL 0xB
+#define DATA_AVAIL 0xF
+
+/* New Flags */
+#define M_STATUS_AVAIL 0xFB
+#define M_DATA_AVAIL 0xFD
+
+/* New Commands */
+#define M_RESET 0x00
+#define M_PICKLE 0x04
+
+/* ports */
+#define MCD_DATA 0
+#define MCD_FLAGS 1
+#define MCD_CTRL 2
+#define CHANNEL 3 /* XXX ??? */
+
+/* Status bits */
+#define MCD_ST_DOOROPEN 0x80
+#define MCD_ST_DSKIN 0x40
+#define MCD_ST_DSKCHNG 0x20
+#define MCD_ST_BUSY 0x04
+#define MCD_ST_AUDIOBSY 0x02
+
+/* commands known by the controller */
+#define MCD_CMDRESET 0x00
+#define MCD_CMDGETVOLINFO 0x10 /* gets mcd_volinfo */
+#define MCD_CMDGETQCHN 0x20 /* gets mcd_qchninfo */
+#define MCD_CMDGETSTAT 0x40 /* gets a byte of status */
+#define MCD_CMDSETMODE 0x50 /* set transmission mode, needs byte */
+#define MCD_MD_RAW 0x60
+#define MCD_MD_COOKED 0x01
+#define MCD_MD_TOC 0x05
+#define MCD_CMDSTOPAUDIO 0x70
+#define MCD_CMDGETVOLUME 0x8E /* gets mcd_volume */
+#define MCD_CMDSETVOLUME 0xAE /* sets mcd_volume */
+#define MCD_CMDREAD1 0xB0 /* read n sectors */
+#define MCD_CMDREAD2 0xC0 /* read from-to */
+#define MCD_CMDCONTINFO 0xDC /* Get controller info */
+#define MCD_CMDEJECTDISK 0xF6
+#define MCD_CMDCLOSETRAY 0xF8
+#define MCD_CMDLOCKDRV 0xFE /* needs byte */
+#define MCD_LK_UNLOCK 0x00
+#define MCD_LK_LOCK 0x01
+#define MCD_LK_TEST 0x02
+
+struct mcd_volinfo {
+ bcd_t trk_low;
+ bcd_t trk_high;
+ bcd_t vol_msf[3];
+ bcd_t trk1_msf[3];
+};
+
+struct mcd_qchninfo {
+ u_char ctrl_adr;
+ u_char trk_no;
+ u_char idx_no;
+ bcd_t trk_size_msf[3];
+ u_char :8;
+ bcd_t hd_pos_msf[3];
+};
+
+struct mcd_volume {
+ u_char v0l;
+ u_char v0rs;
+ u_char v0r;
+ u_char v0ls;
+};
+
+struct mcd_read1 {
+ bcd_t start_msf[3];
+ u_char nsec[3];
+};
+
+struct mcd_read2 {
+ bcd_t start_msf[3];
+ bcd_t end_msf[3];
+};
+#endif /* MCD_H */
diff --git a/sys/dev/mse/mse.c b/sys/dev/mse/mse.c
new file mode 100644
index 0000000..466e936
--- /dev/null
+++ b/sys/dev/mse/mse.c
@@ -0,0 +1,499 @@
+/*
+ * Copyright 1992 by the University of Guelph
+ *
+ * Permission to use, copy and modify this
+ * software and its documentation for any purpose and without
+ * fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting
+ * documentation.
+ * University of Guelph makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ */
+/*
+ * Driver for the Logitech and ATI Inport Bus mice for use with 386bsd and
+ * the X386 port, courtesy of
+ * Rick Macklem, rick@snowhite.cis.uoguelph.ca
+ * Caveats: The driver currently uses spltty(), but doesn't use any
+ * generic tty code. It could use splmse() (that only masks off the
+ * bus mouse interrupt, but that would require hacking in i386/isa/icu.s.
+ * (This may be worth the effort, since the Logitech generates 30/60
+ * interrupts/sec continuously while it is open.)
+ * NB: The ATI has NOT been tested yet!
+ */
+
+/*
+ * Modification history:
+ *
+ * Oct 19, 1992 -- E. Stark (stark@cs.sunysb.edu)
+ * fixes to make it work with Microsoft InPort busmouse
+ *
+ * Jan, 1993 -- E. Stark (stark@cs.sunysb.edu)
+ * added patches for new "select" interface
+ *
+ * May 4, 1993 -- E. Stark (stark@cs.sunysb.edu)
+ * changed position of some spl()'s in mseread
+ *
+ * October 8, 1993 -- E. Stark (stark@cs.sunysb.edu)
+ * limit maximum negative x/y value to -127 to work around XFree problem
+ * that causes spurious button pushes.
+ */
+
+#include "mse.h"
+#if NMSE > 0
+#include "param.h"
+#include "proc.h"
+#include "user.h"
+#include "buf.h"
+#include "systm.h"
+#include "kernel.h"
+#include "ioctl.h"
+#include "tty.h"
+#include "uio.h"
+
+#include "i386/isa/isa_device.h"
+#include "i386/isa/icu.h"
+
+static int mseprobe(struct isa_device *);
+static int mseattach(struct isa_device *);
+void mseintr(int);
+
+struct isa_driver msedriver = {
+ mseprobe, mseattach, "mse"
+};
+
+/*
+ * Software control structure for mouse. The sc_enablemouse(),
+ * sc_disablemouse() and sc_getmouse() routines must be called spl'd().
+ */
+#define PROTOBYTES 5
+struct mse_softc {
+ int sc_flags;
+ int sc_mousetype;
+ struct selinfo sc_selp;
+ u_int sc_port;
+ void (*sc_enablemouse)();
+ void (*sc_disablemouse)();
+ void (*sc_getmouse)();
+ int sc_deltax;
+ int sc_deltay;
+ int sc_obuttons;
+ int sc_buttons;
+ int sc_bytesread;
+ u_char sc_bytes[PROTOBYTES];
+} mse_sc[NMSE];
+
+/* Flags */
+#define MSESC_OPEN 0x1
+#define MSESC_WANT 0x2
+
+/* and Mouse Types */
+#define MSE_LOGITECH 0x1
+#define MSE_ATIINPORT 0x2
+
+#define MSE_PORTA 0
+#define MSE_PORTB 1
+#define MSE_PORTC 2
+#define MSE_PORTD 3
+
+#define MSE_UNIT(dev) (minor(dev) >> 1)
+#define MSE_NBLOCKIO(dev) (minor(dev) & 0x1)
+
+/*
+ * Logitech bus mouse definitions
+ */
+#define MSE_SETUP 0x91 /* What does this mean? */
+#define MSE_HOLD 0x80
+#define MSE_RXLOW 0x00
+#define MSE_RXHIGH 0x20
+#define MSE_RYLOW 0x40
+#define MSE_RYHIGH 0x60
+#define MSE_DISINTR 0x10
+#define MSE_INTREN 0x00
+
+static int mse_probelogi();
+static void mse_enablelogi(), mse_disablelogi(), mse_getlogi();
+
+/*
+ * ATI Inport mouse definitions
+ */
+#define MSE_INPORT_RESET 0x80
+#define MSE_INPORT_STATUS 0x00
+#define MSE_INPORT_DX 0x01
+#define MSE_INPORT_DY 0x02
+#define MSE_INPORT_MODE 0x07
+#define MSE_INPORT_HOLD 0x20
+#define MSE_INPORT_INTREN 0x09
+
+static int mse_probeati();
+static void mse_enableati(), mse_disableati(), mse_getati();
+
+#define MSEPRI (PZERO + 3)
+
+/*
+ * Table of mouse types.
+ * Keep the Logitech last, since I haven't figured out how to probe it
+ * properly yet. (Someday I'll have the documentation.)
+ */
+struct mse_types {
+ int m_type; /* Type of bus mouse */
+ int (*m_probe)(); /* Probe routine to test for it */
+ void (*m_enable)(); /* Start routine */
+ void (*m_disable)(); /* Disable interrupts routine */
+ void (*m_get)(); /* and get mouse status */
+} mse_types[] = {
+ { MSE_ATIINPORT, mse_probeati, mse_enableati, mse_disableati, mse_getati },
+ { MSE_LOGITECH, mse_probelogi, mse_enablelogi, mse_disablelogi, mse_getlogi },
+ { 0, },
+};
+
+int
+mseprobe(idp)
+ register struct isa_device *idp;
+{
+ register struct mse_softc *sc = &mse_sc[idp->id_unit];
+ register int i;
+
+ /*
+ * Check for each mouse type in the table.
+ */
+ i = 0;
+ while (mse_types[i].m_type) {
+ if ((*mse_types[i].m_probe)(idp)) {
+ sc->sc_mousetype = mse_types[i].m_type;
+ sc->sc_enablemouse = mse_types[i].m_enable;
+ sc->sc_disablemouse = mse_types[i].m_disable;
+ sc->sc_getmouse = mse_types[i].m_get;
+ return (1);
+ }
+ i++;
+ }
+ return (0);
+}
+
+int
+mseattach(idp)
+ struct isa_device *idp;
+{
+ struct mse_softc *sc = &mse_sc[idp->id_unit];
+
+ sc->sc_port = idp->id_iobase;
+ return (1);
+}
+
+/*
+ * Exclusive open the mouse, initialize it and enable interrupts.
+ */
+int
+mseopen(dev, flag)
+ dev_t dev;
+ int flag;
+{
+ register struct mse_softc *sc;
+ int s;
+
+ if (MSE_UNIT(dev) >= NMSE)
+ return (ENXIO);
+ sc = &mse_sc[MSE_UNIT(dev)];
+ if (sc->sc_flags & MSESC_OPEN)
+ return (EBUSY);
+ sc->sc_flags |= MSESC_OPEN;
+ sc->sc_obuttons = sc->sc_buttons = 0x7;
+ sc->sc_deltax = sc->sc_deltay = 0;
+ sc->sc_bytesread = PROTOBYTES;
+
+ /*
+ * Initialize mouse interface and enable interrupts.
+ */
+ s = spltty();
+ (*sc->sc_enablemouse)(sc->sc_port);
+ splx(s);
+ return (0);
+}
+
+/*
+ * mseclose: just turn off mouse innterrupts.
+ */
+int
+mseclose(dev, flag)
+ dev_t dev;
+ int flag;
+{
+ struct mse_softc *sc = &mse_sc[MSE_UNIT(dev)];
+ int s;
+
+ s = spltty();
+ (*sc->sc_disablemouse)(sc->sc_port);
+ sc->sc_flags &= ~MSESC_OPEN;
+ splx(s);
+ return(0);
+}
+
+/*
+ * mseread: return mouse info using the MSC serial protocol, but without
+ * using bytes 4 and 5.
+ * (Yes this is cheesy, but it makes the X386 server happy, so...)
+ */
+int
+mseread(dev, uio)
+ dev_t dev;
+ struct uio *uio;
+{
+ register struct mse_softc *sc = &mse_sc[MSE_UNIT(dev)];
+ int xfer, s, error;
+
+ /*
+ * If there are no protocol bytes to be read, set up a new protocol
+ * packet.
+ */
+ s = spltty(); /* XXX Should be its own spl, but where is imlXX() */
+ if (sc->sc_bytesread >= PROTOBYTES) {
+ while (sc->sc_deltax == 0 && sc->sc_deltay == 0 &&
+ (sc->sc_obuttons ^ sc->sc_buttons) == 0) {
+ if (MSE_NBLOCKIO(dev)) {
+ splx(s);
+ return (0);
+ }
+ sc->sc_flags |= MSESC_WANT;
+ if (error = tsleep((caddr_t)sc, MSEPRI | PCATCH,
+ "mseread", 0)) {
+ splx(s);
+ return (error);
+ }
+ }
+
+ /*
+ * Generate protocol bytes.
+ * For some reason X386 expects 5 bytes but never uses
+ * the fourth or fifth?
+ */
+ sc->sc_bytes[0] = 0x80 | (sc->sc_buttons & ~0xf8);
+ if (sc->sc_deltax > 127)
+ sc->sc_deltax = 127;
+ if (sc->sc_deltax < -127)
+ sc->sc_deltax = -127;
+ sc->sc_deltay = -sc->sc_deltay; /* Otherwise mousey goes wrong way */
+ if (sc->sc_deltay > 127)
+ sc->sc_deltay = 127;
+ if (sc->sc_deltay < -127)
+ sc->sc_deltay = -127;
+ sc->sc_bytes[1] = sc->sc_deltax;
+ sc->sc_bytes[2] = sc->sc_deltay;
+ sc->sc_bytes[3] = sc->sc_bytes[4] = 0;
+ sc->sc_obuttons = sc->sc_buttons;
+ sc->sc_deltax = sc->sc_deltay = 0;
+ sc->sc_bytesread = 0;
+ }
+ splx(s);
+ xfer = min(uio->uio_resid, PROTOBYTES - sc->sc_bytesread);
+ if (error = uiomove(&sc->sc_bytes[sc->sc_bytesread], xfer, uio))
+ return (error);
+ sc->sc_bytesread += xfer;
+ return(0);
+}
+
+/*
+ * mseselect: check for mouse input to be processed.
+ */
+int
+mseselect(dev, rw, p)
+ dev_t dev;
+ int rw;
+ struct proc *p;
+{
+ register struct mse_softc *sc = &mse_sc[MSE_UNIT(dev)];
+ int s;
+
+ s = spltty();
+ if (sc->sc_bytesread != PROTOBYTES || sc->sc_deltax != 0 ||
+ sc->sc_deltay != 0 || (sc->sc_obuttons ^ sc->sc_buttons) != 0) {
+ splx(s);
+ return (1);
+ }
+
+ /*
+ * Since this is an exclusive open device, any previous proc.
+ * pointer is trash now, so we can just assign it.
+ */
+ selrecord(p, &sc->sc_selp);
+ splx(s);
+ return (0);
+}
+
+/*
+ * mseintr: update mouse status. sc_deltax and sc_deltay are accumulative.
+ */
+void
+mseintr(unit)
+ int unit;
+{
+ register struct mse_softc *sc = &mse_sc[unit];
+ pid_t p;
+
+#ifdef DEBUG
+ static int mse_intrcnt = 0;
+ if((mse_intrcnt++ % 10000) == 0)
+ printf("mseintr\n");
+#endif /* DEBUG */
+ if ((sc->sc_flags & MSESC_OPEN) == 0)
+ return;
+
+ (*sc->sc_getmouse)(sc->sc_port, &sc->sc_deltax, &sc->sc_deltay, &sc->sc_buttons);
+
+ /*
+ * If mouse state has changed, wake up anyone wanting to know.
+ */
+ if (sc->sc_deltax != 0 || sc->sc_deltay != 0 ||
+ (sc->sc_obuttons ^ sc->sc_buttons) != 0) {
+ if (sc->sc_flags & MSESC_WANT) {
+ sc->sc_flags &= ~MSESC_WANT;
+ wakeup((caddr_t)sc);
+ }
+ selwakeup(&sc->sc_selp);
+ }
+}
+
+/*
+ * Routines for the Logitech mouse.
+ */
+/*
+ * Test for a Logitech bus mouse and return 1 if it is.
+ * (until I know how to use the signature port properly, just disable
+ * interrupts and return 1)
+ */
+static int
+mse_probelogi(idp)
+ register struct isa_device *idp;
+{
+
+ outb(idp->id_iobase + MSE_PORTB, 0x55);
+ if (inb(idp->id_iobase + MSE_PORTB) == 0x55) {
+ outb(idp->id_iobase + MSE_PORTB, 0xaa);
+ if (inb(idp->id_iobase + MSE_PORTB) == 0xaa)
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * Initialize Logitech mouse and enable interrupts.
+ */
+static void
+mse_enablelogi(port)
+ register u_int port;
+{
+ int dx, dy, but;
+
+ outb(port + MSE_PORTD, MSE_SETUP);
+ mse_getlogi(port, &dx, &dy, &but);
+}
+
+/*
+ * Disable interrupts for Logitech mouse.
+ */
+static void
+mse_disablelogi(port)
+ register u_int port;
+{
+
+ outb(port + MSE_PORTC, MSE_DISINTR);
+}
+
+/*
+ * Get the current dx, dy and button up/down state.
+ */
+static void
+mse_getlogi(port, dx, dy, but)
+ register u_int port;
+ int *dx;
+ int *dy;
+ int *but;
+{
+ register char x, y;
+
+ outb(port + MSE_PORTC, MSE_HOLD | MSE_RXLOW);
+ x = inb(port + MSE_PORTA);
+ *but = (x >> 5) & 0x7;
+ x &= 0xf;
+ outb(port + MSE_PORTC, MSE_HOLD | MSE_RXHIGH);
+ x |= (inb(port + MSE_PORTA) << 4);
+ outb(port + MSE_PORTC, MSE_HOLD | MSE_RYLOW);
+ y = (inb(port + MSE_PORTA) & 0xf);
+ outb(port + MSE_PORTC, MSE_HOLD | MSE_RYHIGH);
+ y |= (inb(port + MSE_PORTA) << 4);
+ *dx += x;
+ *dy += y;
+ outb(port + MSE_PORTC, MSE_INTREN);
+}
+
+/*
+ * Routines for the ATI Inport bus mouse.
+ */
+/*
+ * Test for a ATI Inport bus mouse and return 1 if it is.
+ * (do not enable interrupts)
+ */
+static int
+mse_probeati(idp)
+ register struct isa_device *idp;
+{
+ int i;
+
+ for (i = 0; i < 2; i++)
+ if (inb(idp->id_iobase + MSE_PORTC) == 0xde)
+ return (1);
+ return (0);
+}
+
+/*
+ * Initialize ATI Inport mouse and enable interrupts.
+ */
+static void
+mse_enableati(port)
+ register u_int port;
+{
+
+ outb(port + MSE_PORTA, MSE_INPORT_RESET);
+ outb(port + MSE_PORTA, MSE_INPORT_MODE);
+ outb(port + MSE_PORTB, MSE_INPORT_INTREN);
+}
+
+/*
+ * Disable interrupts for ATI Inport mouse.
+ */
+static void
+mse_disableati(port)
+ register u_int port;
+{
+
+ outb(port + MSE_PORTA, MSE_INPORT_MODE);
+ outb(port + MSE_PORTB, 0);
+}
+
+/*
+ * Get current dx, dy and up/down button state.
+ */
+static void
+mse_getati(port, dx, dy, but)
+ register u_int port;
+ int *dx;
+ int *dy;
+ int *but;
+{
+ register char byte;
+
+ outb(port + MSE_PORTA, MSE_INPORT_MODE);
+ outb(port + MSE_PORTB, MSE_INPORT_HOLD);
+ outb(port + MSE_PORTA, MSE_INPORT_STATUS);
+ *but = ~(inb(port + MSE_PORTB) & 0x7);
+ outb(port + MSE_PORTA, MSE_INPORT_DX);
+ byte = inb(port + MSE_PORTB);
+ *dx += byte;
+ outb(port + MSE_PORTA, MSE_INPORT_DY);
+ byte = inb(port + MSE_PORTB);
+ *dy += byte;
+ outb(port + MSE_PORTA, MSE_INPORT_MODE);
+ outb(port + MSE_PORTB, MSE_INPORT_INTREN);
+}
+#endif /* NMSE */
diff --git a/sys/dev/ppbus/lptio.h b/sys/dev/ppbus/lptio.h
new file mode 100644
index 0000000..87af5bc
--- /dev/null
+++ b/sys/dev/ppbus/lptio.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 1994 Geoffrey M. Rehmet
+ *
+ * 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.
+ *
+ * Geoff Rehmet, Rhodes University, South Africa <csgr@cs.ru.ac.za>
+ *
+ */
+
+#ifndef _LPT_PRINTER_H_
+#define _LPT_PRINTER_H_
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+
+#define LPT_IRQ _IOW('p', 1, long) /* set interrupt status */
+
+#endif
diff --git a/sys/dev/sio/sio.c b/sys/dev/sio/sio.c
new file mode 100644
index 0000000..dd4ee55
--- /dev/null
+++ b/sys/dev/sio/sio.c
@@ -0,0 +1,1920 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)com.c 7.5 (Berkeley) 5/16/91
+ * $Id: sio.c,v 1.44 1994/04/03 12:25:57 ache Exp $
+ */
+
+#include "sio.h"
+#if NSIO > 0
+#define DONT_MALLOC_TTYS
+/*
+ * Serial driver, based on 386BSD-0.1 com driver.
+ * Mostly rewritten to use pseudo-DMA.
+ * Works for National Semiconductor NS8250-NS16550AF UARTs.
+ * COM driver, based on HP dca driver.
+ */
+#include "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/sioreg.h"
+#include "i386/isa/ic/ns16550.h"
+
+#define FAKE_DCD(unit) ((unit) == comconsole)
+#define LOTS_OF_EVENTS 64 /* helps separate urgent events from input */
+#define RBSZ 1024
+#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 RS_OBUFSIZE 256
+#define TTY_BI TTY_FE /* XXX */
+#define TTY_OE TTY_PE /* XXX */
+
+#ifdef COM_BIDIR
+#define CALLOUT(x) (minor(x) & COM_CALLOUT_MASK)
+#define COM_CALLOUT_MASK 0x80
+#define COM_MINOR_MAGIC_MASK 0x80
+#else /* COM_BIDIR */
+#define COM_MINOR_MAGIC_MASK 0
+#endif /* COM_BIDIR */
+
+#define UNIT(x) (minor(x) & ~COM_MINOR_MAGIC_MASK)
+
+#ifdef COM_MULTIPORT
+/* checks in flags for multiport and which is multiport "master chip"
+ * for a given card
+ */
+#define COM_ISMULTIPORT(dev) ((dev)->id_flags & 0x01)
+#define COM_MPMASTER(dev) (((dev)->id_flags >> 8) & 0x0ff)
+#define COM_NOMASTER(dev) ((dev)->id_flags & 0x04)
+#endif /* COM_MULTIPORT */
+
+#define COM_NOFIFO(dev) ((dev)->id_flags & 0x02)
+
+#ifndef FIFO_TRIGGER
+/*
+ * This driver is fast enough to work with any value and for high values
+ * to be only slightly more efficient. Low values may be better because
+ * they give lower latency.
+ * TODO: always use low values for low speeds. Mouse movements are jerky
+ * if more than one packet arrives at once. The low speeds used for
+ * serial mice help avoid this, but not if (large) fifos are enabled.
+ */
+#define FIFO_TRIGGER FIFO_TRIGGER_14
+#endif
+
+#define com_scr 7 /* scratch register for 16450-16550 (R/W) */
+
+#ifndef setsofttty
+#define OLD_INTERRUPT_HANDLING /* XXX FreeBSD-1.1 and earlier */
+#define setsofttty() (ipending |= 1 << 4) /* XXX requires owning IRQ4 */
+extern u_int ipending; /* XXX */
+void softsio1 __P((void));
+#endif
+
+/*
+ * 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 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 */
+#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 */
+ int dtr_wait; /* time to hold DTR down on close (* 1/HZ) */
+ u_int tx_fifo_size;
+
+ /*
+ * 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 */
+
+#ifdef TIOCTIMESTAMP
+ bool_t do_timestamp;
+ struct timeval timestamp;
+#endif
+
+ u_long bytes_in; /* statistics */
+ u_long bytes_out;
+ u_int delta_error_counts[CE_NTYPES];
+ u_int error_counts[CE_NTYPES];
+
+ /*
+ * Ping-pong input buffers. The extra factor of 2 in the sizes is
+ * to allow for an error byte for each input byte.
+ */
+#define CE_INPUT_OFFSET RS_IBUFSIZE
+ u_char ibuf1[2 * RS_IBUFSIZE];
+ u_char ibuf2[2 * RS_IBUFSIZE];
+ u_char obuf[RS_OBUFSIZE];
+};
+
+/*
+ * The public functions in the com module ought to be declared in a com-driver
+ * system header.
+ */
+
+/* Interrupt handling entry points. */
+void siointr __P((int unit));
+void siopoll __P((void));
+
+/* Device switch entry points. */
+int sioopen __P((dev_t dev, int oflags, int devtype,
+ struct proc *p));
+int sioclose __P((dev_t dev, int fflag, int devtype,
+ struct proc *p));
+int sioread __P((dev_t dev, struct uio *uio, int ioflag));
+int siowrite __P((dev_t dev, struct uio *uio, int ioflag));
+int sioioctl __P((dev_t dev, int cmd, caddr_t data,
+ int fflag, struct proc *p));
+void siostop __P((struct tty *tp, int rw));
+#define sioreset noreset
+int sioselect __P((dev_t dev, int rw, struct proc *p));
+#define siommap nommap
+#define siostrategy nostrategy
+
+/* Console device entry points. */
+int siocngetc __P((dev_t dev));
+struct consdev;
+void siocninit __P((struct consdev *cp));
+void siocnprobe __P((struct consdev *cp));
+void siocnputc __P((dev_t dev, int c));
+
+static int sioattach __P((struct isa_device *dev));
+static void comflush __P((struct com_s *com));
+static void comhardclose __P((struct com_s *com));
+static void siointr1 __P((struct com_s *com));
+static void commctl __P((struct com_s *com, int bits, int how));
+static int comparam __P((struct tty *tp, struct termios *t));
+static int sioprobe __P((struct isa_device *dev));
+static void comstart __P((struct tty *tp));
+static void comwakeup __P((caddr_t chan, int ticks));
+static int tiocm_xxx2mcr __P((int tiocm_xxx));
+
+/* table and macro for fast conversion from a unit number to its com struct */
+static struct com_s *p_com_addr[NSIO];
+#define com_addr(unit) (p_com_addr[unit])
+
+static struct com_s com_structs[NSIO];
+
+#ifdef TIOCTIMESTAMP
+static struct timeval intr_timestamp;
+#endif
+
+struct isa_driver siodriver = {
+ sioprobe, sioattach, "sio"
+};
+
+#ifdef COMCONSOLE
+static int comconsole = COMCONSOLE;
+#else
+static int comconsole = -1;
+#endif
+static speed_t comdefaultrate = TTYDEF_SPEED;
+static u_int com_events; /* input chars + weighted output completions */
+static int commajor;
+#define TB_OUT(tp) (&(tp)->t_outq)
+#define TB_RAW(tp) (&(tp)->t_rawq)
+struct tty sio_tty[NSIO];
+extern struct tty *constty;
+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();
+
+ /*
+ * Initialize the speed so that any junk in the THR or output fifo will
+ * be transmitted in a known time. (There may be lots of junk after a
+ * soft reboot, and output interrupts don't work right after a master
+ * reset, at least for 16550s. (The speed is undefined after MR, but
+ * MR empties the THR and the TSR so it's not clear why this matters)).
+ * 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_DLAB);
+ outb(iobase + com_dlbl, COMBRD(9600) & 0xff);
+ outb(iobase + com_dlbh, (u_int) COMBRD(9600) >> 8);
+ 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 */
+ DELAY((16 + 1) * 9600 / 10); /* enough to drain 16 bytes */
+ if ( inb(iobase + com_cfcr) != CFCR_8BITS
+ || inb(iobase + com_ier) != IER_ETXRDY
+ || inb(iobase + com_mcr) != MCR_IENABLE
+#ifndef COM_MULTIPORT /* XXX - need to do more to enable interrupts */
+ || !isa_irq_pending(dev)
+#endif
+ || (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;
+ if (result == 0)
+ outb(iobase + com_mcr, 0);
+
+ enable_intr();
+ return (result);
+}
+
+static int
+sioattach(isdp)
+ struct isa_device *isdp;
+{
+ struct com_s *com;
+ static bool_t comwakeup_started = FALSE;
+ Port_t iobase;
+ int s;
+ int unit;
+
+ iobase = isdp->id_iobase;
+ unit = isdp->id_unit;
+ 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]; /* XXX malloc it */
+ com->cfcr_image = CFCR_8BITS;
+ com->mcr_image = MCR_IENABLE;
+ com->dtr_wait = 3 * hz;
+ com->tx_fifo_size = 1;
+ com->iptr = com->ibuf = com->ibuf1;
+ com->ibufend = com->ibuf1 + RS_IBUFSIZE;
+ com->ihighwater = com->ibuf1 + RS_IHIGHWATER;
+ com->iobase = iobase;
+ com->data_port = iobase + com_data;
+ com->int_id_port = iobase + com_iir;
+ com->modem_ctl_port = iobase + com_mcr;
+ com->line_status_port = iobase + com_lsr;
+ com->modem_status_port = iobase + com_msr;
+#ifdef DONT_MALLOC_TTYS
+ com->tp = &sio_tty[unit];
+#endif
+
+ /* attempt to determine UART type */
+ printf("sio%d: type", unit);
+#ifdef COM_MULTIPORT
+ if (!COM_ISMULTIPORT(isdp))
+#endif
+ {
+ u_char scr;
+ u_char scr1;
+ u_char scr2;
+
+ scr = inb(iobase + com_scr);
+ outb(iobase + com_scr, 0xa5);
+ scr1 = inb(iobase + com_scr);
+ outb(iobase + com_scr, 0x5a);
+ scr2 = inb(iobase + com_scr);
+ outb(iobase + com_scr, scr);
+ if (scr1 != 0xa5 || scr2 != 0x5a) {
+ printf(" 8250");
+ goto determined_type;
+ }
+ }
+ outb(iobase + com_fifo, FIFO_ENABLE | FIFO_TRIGGER_14);
+ DELAY(100);
+ switch (inb(com->int_id_port) & IIR_FIFO_MASK) {
+ case FIFO_TRIGGER_1:
+ printf(" 16450");
+ break;
+ case FIFO_TRIGGER_4:
+ printf(" 16450?");
+ break;
+ case FIFO_TRIGGER_8:
+ printf(" 16550?");
+ break;
+ case FIFO_TRIGGER_14:
+ printf(" 16550A");
+ if (COM_NOFIFO(isdp))
+ printf(" fifo disabled");
+ else {
+ com->hasfifo = TRUE;
+ com->tx_fifo_size = 16;
+ }
+ break;
+ }
+ outb(iobase + com_fifo, 0);
+determined_type: ;
+
+#ifdef COM_MULTIPORT
+ if (COM_ISMULTIPORT(isdp)) {
+ com->multiport = TRUE;
+ printf(" (multiport)");
+
+ /* Note: some cards have no master port (e.g., BocaBoards) */
+ if (!COM_NOMASTER(isdp)) {
+ struct isa_device *masterdev;
+
+ /* set the master's common-interrupt-enable reg.,
+ * as appropriate. YYY See your manual
+ */
+ /* enable only common interrupt for port */
+ outb(com->modem_ctl_port, com->mcr_image = 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 {
+ int divisor;
+
+ /*
+ * XXX now unfinished and broken. Need to do
+ * something more like a full open(). There's no
+ * suitable interrupt handler so don't enable device
+ * interrupts. Watch out for null tp's.
+ */
+ outb(iobase + com_cfcr, CFCR_DLAB);
+ divisor = ttspeedtab(kgdb_rate, comspeedtab);
+ outb(iobase + com_dlbl, divisor & 0xFF);
+ outb(iobase + com_dlbh, (u_int) divisor >> 8);
+ outb(iobase + com_cfcr, CFCR_8BITS);
+ outb(com->modem_status_port,
+ com->mcr_image |= MCR_DTR | MCR_RTS);
+
+ if (kgdb_debug_init) {
+ /*
+ * Print prefix of device name,
+ * let kgdb_connect print the rest.
+ */
+ printf("sio%d: ", unit);
+ kgdb_connect(1);
+ } else
+ printf("sio%d: kgdb enabled\n", unit);
+ }
+ }
+#endif
+
+ com_addr(unit) = com;
+ splx(s);
+ if (!comwakeup_started) {
+ comwakeup((caddr_t) NULL, 0);
+ comwakeup_started = TRUE;
+ }
+ return (1);
+}
+
+/* ARGSUSED */
+int
+sioopen(dev, flag, mode, p)
+ dev_t dev;
+ int flag;
+ int mode;
+ struct proc *p;
+{
+#ifdef COM_BIDIR
+ bool_t callout;
+#endif /* COM_BIDIR */
+ struct com_s *com;
+ int error = 0;
+ bool_t got_status = FALSE;
+ Port_t iobase;
+ int s;
+ struct tty *tp;
+ int unit;
+
+ unit = UNIT(dev);
+ 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 */
+ callout = CALLOUT(dev);
+ if (callout && !(com->bidir))
+ return (ENXIO);
+#endif /* COM_BIDIR */
+
+#ifdef DONT_MALLOC_TTYS
+ tp = com->tp;
+#else
+ sio_tty[unit] = ttymalloc(sio_tty[unit]);
+ tp = com->tp = sio_tty[unit];
+#endif
+ s = spltty();
+
+#ifdef COM_BIDIR
+
+bidir_open_top:
+ got_status = FALSE;
+ /* 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;
+ }
+ } 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((caddr_t)&com->active_out,
+ TTIPRI|PCATCH,
+ "siooth",
+ 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;
+ }
+ }
+ disable_intr();
+ com->prev_modem_status =
+ com->last_modem_status = inb(com->modem_status_port);
+ enable_intr();
+ got_status = TRUE;
+ if (com->prev_modem_status & MSR_DCD
+ || FAKE_DCD(unit)) {
+ /* there's a carrier on the line; we win */
+ com->active_in = TRUE;
+ } else {
+ /* there is no carrier on the line */
+ if (flag & O_NONBLOCK) {
+ /* can't wait; let it open */
+ com->active_in = TRUE;
+ } else {
+ /* put DTR & RTS up */
+ /* XXX - bring up RTS earlier? */
+ commctl(com, MCR_DTR | MCR_RTS, DMSET);
+ outb(com->iobase + com_ier, IER_EMSC);
+
+ /* wait for it... */
+ error = tsleep((caddr_t)&com->active_in,
+ TTIPRI|PCATCH,
+ "siodcd",
+ 0);
+
+ /* if not active, turn intrs and DTR off */
+ if (!com->active) {
+ outb(com->iobase + com_ier, 0);
+ 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 don't use all the flags from <sys/ttydefaults.h>
+ * 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;
+#ifdef COM_BIDIR
+ if (com->bidir && !callout)
+ tp->t_cflag |= HUPCL;
+#endif
+ tp->t_lflag = 0;
+ tp->t_ispeed = tp->t_ospeed = comdefaultrate;
+ if (unit == comconsole) {
+ tp->t_iflag = TTYDEF_IFLAG;
+ tp->t_oflag = TTYDEF_OFLAG;
+ tp->t_cflag = TTYDEF_CFLAG;
+ tp->t_lflag = TTYDEF_LFLAG;
+ }
+ }
+
+ /*
+ * XXX the full state after a first open() needs to be
+ * programmable and separate for callin and callout.
+ */
+#ifdef COM_BIDIR
+ if (com->bidir) {
+ if (callout)
+ tp->t_cflag |= CLOCAL;
+ else
+ tp->t_cflag &= ~CLOCAL;
+ }
+#endif
+
+ commctl(com, MCR_DTR | MCR_RTS, DMSET);
+ error = comparam(tp, &tp->t_termios);
+ if (error != 0)
+ goto out;
+ ttsetwater(tp);
+ iobase = com->iobase;
+ if (com->hasfifo) {
+ /* (re)enable and drain FIFO */
+ outb(iobase + com_fifo, FIFO_ENABLE | FIFO_TRIGGER
+ | FIFO_RCV_RST | FIFO_XMT_RST);
+ DELAY(100);
+ }
+ disable_intr();
+ (void) inb(com->line_status_port);
+ (void) inb(com->data_port);
+ if (!got_status)
+ com->prev_modem_status =
+ com->last_modem_status = inb(com->modem_status_port);
+ outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS
+ | IER_EMSC);
+ enable_intr();
+ if (com->prev_modem_status & MSR_DCD || FAKE_DCD(unit))
+ 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)TB_RAW(tp), TTIPRI | PCATCH,
+ ttopen, 0);
+ if (error != 0)
+ break;
+ }
+out:
+ if (error == 0)
+ error = (*linesw[tp->t_line].l_open)(dev, tp);
+ splx(s);
+
+#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
+ * remained 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;
+ int s;
+ struct tty *tp;
+
+ com = com_addr(UNIT(dev));
+ tp = com->tp;
+ s = spltty();
+ (*linesw[tp->t_line].l_close)(tp, flag);
+ siostop(tp, FREAD | FWRITE);
+ comhardclose(com);
+ ttyclose(tp);
+ splx(s);
+ return (0);
+}
+
+static void
+comhardclose(com)
+ struct com_s *com;
+{
+ Port_t iobase;
+ int s;
+ struct tty *tp;
+ int unit;
+
+ unit = com - &com_structs[0];
+ iobase = com->iobase;
+ s = spltty();
+#ifdef TIOCTIMESTAMP
+ com->do_timestamp = 0;
+#endif
+ outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
+#ifdef KGDB
+ /* do not disable interrupts or hang up if debugging */
+ if (kgdb_dev != makedev(commajor, unit))
+#endif
+ {
+ outb(iobase + com_ier, 0);
+ tp = com->tp;
+ if (tp->t_cflag & HUPCL || tp->t_state & TS_WOPEN
+#ifdef COM_BIDIR
+ /*
+ * XXX we will miss any carrier drop between here and the
+ * next open. Perhaps we should watch DCD even when the
+ * port is closed; it is not sufficient to check it at
+ * the next open because it might go up and down while
+ * we're not watching. And we shouldn't look at DCD if
+ * CLOCAL is set (here or for the dialin device ...).
+ * When the termios state is reinitialized for initial
+ * opens, the correct CLOCAL bit will be
+ * ((the bit now) & (the initial bit)).
+ */
+ || com->active_in
+ && !(com->prev_modem_status & MSR_DCD) && !FAKE_DCD(unit)
+#endif
+ || !(tp->t_state & TS_ISOPEN)) {
+ commctl(com, MCR_RTS, DMSET);
+ if (com->dtr_wait != 0)
+ /*
+ * Uninterruptible sleep since we want to
+ * wait a fixed time.
+ * XXX - delay in open() (if necessary),
+ * not here (always).
+ */
+ tsleep((caddr_t)&com->dtr_wait, TTIPRI,
+ "sioclose", com->dtr_wait);
+ }
+ }
+
+#ifdef COM_BIDIR
+ com->active = com->active_in = com->active_out = 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));
+}
+
+#ifdef TIOCTIMESTAMP
+/* Interrupt routine for timekeeping purposes */
+void
+siointrts(unit)
+ int unit;
+{
+ microtime(&intr_timestamp);
+ siointr(unit);
+}
+#endif
+
+void
+siointr(unit)
+ int unit;
+{
+#ifndef COM_MULTIPORT
+ siointr1(com_addr(unit));
+#else /* COM_MULTIPORT */
+ bool_t possibly_more_intrs;
+ struct com_s *com;
+
+ /*
+ * Loop until there is no activity on any port. This is necessary
+ * to get an interrupt edge more than to avoid another interrupt.
+ * If the IRQ signal is just an OR of the IRQ signals from several
+ * devices, then the edge from one may be lost because another is
+ * on.
+ */
+ do {
+ possibly_more_intrs = FALSE;
+ for (unit = 0; unit < NSIO; ++unit) {
+ com = com_addr(unit);
+ if (com != NULL
+ && (inb(com->int_id_port) & IIR_IMASK)
+ != IIR_NOPEND) {
+ siointr1(com);
+ possibly_more_intrs = TRUE;
+ }
+ }
+ } while (possibly_more_intrs);
+#endif /* COM_MULTIPORT */
+}
+
+static void
+siointr1(com)
+ struct com_s *com;
+{
+ u_char line_status;
+ u_char modem_status;
+ u_char *ioptr;
+ u_char recv_data;
+
+#ifdef TIOCTIMESTAMP
+ if (com->do_timestamp)
+ /* XXX a little bloat here... */
+ com->timestamp = intr_timestamp;
+#endif
+ while (TRUE) {
+ line_status = inb(com->line_status_port);
+
+ /* input event? (check first to help avoid overruns) */
+ while (line_status & LSR_RCV_MASK) {
+ /* break/unnattached error bits or real input? */
+ if (!(line_status & LSR_RXRDY))
+ recv_data = 0;
+ else
+ recv_data = inb(com->data_port);
+ ++com->bytes_in;
+ /* XXX reduce SLIP input latency */
+#define FRAME_END 0xc0
+ if (recv_data == FRAME_END)
+ setsofttty();
+#ifdef KGDB
+ /* trap into kgdb? (XXX - needs testing and optim) */
+ if (recv_data == FRAME_END
+ && !(com->tp->t_state & TS_ISOPEN)
+ && kgdb_dev == makedev(commajor, unit)) {
+ kgdb_connect(0);
+ continue;
+ }
+#endif /* KGDB */
+ ioptr = com->iptr;
+ if (ioptr >= com->ibufend)
+ CE_RECORD(com, CE_INTERRUPT_BUF_OVERFLOW);
+ else {
+ ++com_events;
+#if 0 /* for testing input latency vs efficiency */
+if (com->iptr - com->ibuf == 8)
+ setsofttty();
+#endif
+ ioptr[0] = recv_data;
+ ioptr[CE_INPUT_OFFSET] = line_status;
+ com->iptr = ++ioptr;
+ if (ioptr == com->ihighwater
+ && com->state & CS_RTS_IFLOW)
+ outb(com->modem_ctl_port,
+ com->mcr_image &= ~MCR_RTS);
+ /* XXX - move this out of isr */
+ if (line_status & LSR_OE)
+ CE_RECORD(com, CE_OVERRUN);
+ }
+
+ /*
+ * "& 0x7F" is to avoid the gcc-1.40 generating a slow
+ * jump from the top of the loop to here
+ */
+ line_status = inb(com->line_status_port) & 0x7F;
+ }
+
+ /* modem status change? (always check before doing output) */
+ modem_status = inb(com->modem_status_port);
+ if (modem_status != com->last_modem_status) {
+ /*
+ * Schedule high level to handle DCD changes. Note
+ * that we don't use the delta bits anywhere. Some
+ * UARTs mess them up, and it's easy to remember the
+ * previous bits and calculate the delta.
+ */
+ com->last_modem_status = modem_status;
+ if (!(com->state & CS_CHECKMSR)) {
+ com_events += LOTS_OF_EVENTS;
+ com->state |= CS_CHECKMSR;
+ setsofttty();
+ }
+
+ /* handle CTS change immediately for crisp flow ctl */
+ if (com->state & CS_CTS_OFLOW) {
+ if (modem_status & MSR_CTS)
+ com->state |= CS_ODEVREADY;
+ else
+ com->state &= ~CS_ODEVREADY;
+ }
+ }
+
+ /* output queued and everything ready? */
+ if (line_status & LSR_TXRDY
+ && com->state >= (CS_ODEVREADY | CS_BUSY | CS_TTGO)) {
+ ioptr = com->optr;
+ if (com->tx_fifo_size > 1) {
+ u_int ocount;
+
+ ocount = com->obufend - ioptr;
+ if (ocount > com->tx_fifo_size)
+ ocount = com->tx_fifo_size;
+ com->bytes_out += ocount;
+ do
+ outb(com->data_port, *ioptr++);
+ while (--ocount != 0);
+ } else {
+ outb(com->data_port, *ioptr++);
+ ++com->bytes_out;
+ }
+ com->optr = ioptr;
+ if (ioptr >= com->obufend) {
+ /* output just completed */
+ com_events += LOTS_OF_EVENTS;
+ com->state ^= (CS_ODONE | CS_BUSY);
+ setsofttty(); /* handle at high level ASAP */
+ }
+ }
+
+ /* finished? */
+#ifndef COM_MULTIPORT
+ if ((inb(com->int_id_port) & IIR_IMASK) == IIR_NOPEND)
+#endif /* COM_MULTIPORT */
+ return;
+ }
+}
+
+static int
+tiocm_xxx2mcr(tiocm_xxx)
+ int tiocm_xxx;
+{
+ int mcr;
+
+ mcr = 0;
+ if (tiocm_xxx & TIOCM_DTR)
+ mcr |= MCR_DTR;
+ if (tiocm_xxx & TIOCM_RTS)
+ mcr |= MCR_RTS;
+ return (mcr);
+}
+
+int
+sioioctl(dev, cmd, data, flag, p)
+ dev_t dev;
+ int cmd;
+ caddr_t data;
+ int flag;
+ struct proc *p;
+{
+ struct com_s *com;
+ int error;
+ Port_t iobase;
+ int mcr;
+ int msr;
+ int s;
+ int tiocm_xxx;
+ struct tty *tp;
+
+ com = com_addr(UNIT(dev));
+ tp = com->tp;
+ error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
+ if (error >= 0)
+ return (error);
+ error = ttioctl(tp, cmd, data, flag);
+
+#ifdef COM_BIDIR
+ /* XXX: plug security hole while sticky bits not yet implemented */
+ if (com->bidir && com->active_in && p->p_ucred->cr_uid != 0)
+ tp->t_cflag &= ~CLOCAL;
+#endif
+
+ if (error >= 0)
+ return (error);
+
+ iobase = com->iobase;
+ s = spltty();
+ switch (cmd) {
+ case TIOCSBRK:
+ outb(iobase + com_cfcr, com->cfcr_image |= CFCR_SBREAK);
+ break;
+ case TIOCCBRK:
+ outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
+ break;
+ case TIOCSDTR:
+ commctl(com, MCR_DTR, DMBIS);
+ break;
+ case TIOCCDTR:
+ commctl(com, MCR_DTR, DMBIC);
+ break;
+ case TIOCMSET:
+ commctl(com, tiocm_xxx2mcr(*(int *)data), DMSET);
+ break;
+ case TIOCMBIS:
+ commctl(com, tiocm_xxx2mcr(*(int *)data), DMBIS);
+ break;
+ case TIOCMBIC:
+ commctl(com, tiocm_xxx2mcr(*(int *)data), DMBIC);
+ break;
+ case TIOCMGET:
+ tiocm_xxx = TIOCM_LE; /* XXX - always enabled while open */
+ mcr = com->mcr_image;
+ if (mcr & MCR_DTR)
+ tiocm_xxx |= TIOCM_DTR;
+ if (mcr & MCR_RTS)
+ tiocm_xxx |= TIOCM_RTS;
+ msr = com->prev_modem_status;
+ if (msr & MSR_CTS)
+ tiocm_xxx |= TIOCM_CTS;
+ if (msr & MSR_DCD)
+ tiocm_xxx |= TIOCM_CD;
+ if (msr & MSR_DSR)
+ tiocm_xxx |= TIOCM_DSR;
+ /*
+ * XXX - MSR_RI is naturally volatile, and we make MSR_TERI
+ * more volatile by reading the modem status a lot. Perhaps
+ * we should latch both bits until the status is read here.
+ */
+ if (msr & (MSR_RI | MSR_TERI))
+ tiocm_xxx |= TIOCM_RI;
+ *(int *)data = tiocm_xxx;
+ break;
+#ifdef COM_BIDIR
+ case TIOCMSBIDIR:
+ /* must be root to set bidir. capability */
+ error = suser(p->p_ucred, &p->p_acflag);
+ if (error != 0) {
+ splx(s);
+ return(EPERM);
+ }
+
+ /* if it's the console, can't do it (XXX why?) */
+ if (UNIT(dev) == comconsole) {
+ splx(s);
+ return(ENOTTY);
+ }
+
+#if 0
+ /* XXX - 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) {
+ splx(s);
+ return(EBUSY);
+ }
+#endif
+
+ com->bidir = *(int *)data;
+ break;
+ case TIOCMGBIDIR:
+ *(int *)data = com->bidir;
+ break;
+#endif /* COM_BIDIR */
+#if 0
+ case TIOCMSDTRWAIT:
+ /* must be root since the wait applies to following logins */
+ error = suser(p->p_ucred, &p->p_acflag);
+ if (error != 0) {
+ splx(s);
+ return(EPERM);
+ }
+
+ /* if it's the console, can't do it (XXX why?) */
+ if (UNIT(dev) == comconsole) {
+ splx(s);
+ return(ENOTTY);
+ }
+ com->dtr_wait = *(int *)data;
+ break;
+ case TIOCMGDTRWAIT:
+ *(int *)data = com->dtr_wait;
+ break;
+#endif
+#ifdef TIOCTIMESTAMP
+ case TIOCTIMESTAMP:
+ com->do_timestamp = TRUE;
+ *(struct timeval *)data = com->timestamp;
+ break;
+#endif
+ default:
+ splx(s);
+ return (ENOTTY);
+ }
+ splx(s);
+ return (0);
+}
+
+/* cancel pending output */
+static void
+comflush(com)
+ struct com_s *com;
+{
+ struct clist *rbp;
+
+ disable_intr();
+ if (com->state & CS_ODONE)
+ com_events -= LOTS_OF_EVENTS;
+ com->state &= ~(CS_ODONE | CS_BUSY);
+ enable_intr();
+ while( getc( TB_OUT(com->tp)) != -1);
+ com->ocount = 0;
+ com->tp->t_state &= ~TS_BUSY;
+}
+
+void
+siopoll()
+{
+#ifdef OLD_INTERRUPT_HANDLING
+ static bool_t awake = FALSE;
+ int s;
+#endif
+ int unit;
+
+ if (com_events == 0)
+ return;
+
+#ifdef OLD_INTERRUPT_HANDLING
+ disable_intr();
+ if (awake) {
+ enable_intr();
+ return;
+ }
+ awake = TRUE;
+ enable_intr();
+ s = spltty();
+#endif
+
+repeat:
+ for (unit = 0; unit < NSIO; ++unit) {
+ u_char *buf;
+ struct com_s *com;
+ u_char *ibuf;
+ int incc;
+ struct tty *tp;
+
+ com = com_addr(unit);
+ if (com == NULL)
+ continue;
+ tp = com->tp;
+#ifdef DONT_MALLOC_TTYS
+ if (tp == NULL)
+ continue;
+#endif
+
+ /* switch the role of the low-level input buffers */
+ if (com->iptr == (ibuf = com->ibuf)) {
+ buf = NULL; /* not used, but compiler can't tell */
+ incc = 0;
+ } else {
+ buf = ibuf;
+ disable_intr();
+ incc = com->iptr - buf;
+ com_events -= incc;
+ if (ibuf == com->ibuf1)
+ ibuf = com->ibuf2;
+ else
+ ibuf = com->ibuf1;
+ com->ibufend = ibuf + RS_IBUFSIZE;
+ com->ihighwater = ibuf + RS_IHIGHWATER;
+ com->iptr = ibuf;
+
+ /*
+ * There is now room for another low-level buffer full
+ * of input, so enable RTS if it is now disabled and
+ * there is room in the high-level buffer.
+ */
+ /*
+ * XXX this used not to look at CS_RTS_IFLOW. The
+ * change is to allow full control of MCR_RTS via
+ * ioctls after turning CS_RTS_IFLOW off. Check
+ * for races. We shouldn't allow the ioctls while
+ * CS_RTS_IFLOW is on.
+ */
+ if ((com->state & CS_RTS_IFLOW)
+ && !(com->mcr_image & MCR_RTS) /*
+ && !(tp->t_state & TS_RTS_IFLOW) */)
+ outb(com->modem_ctl_port,
+ com->mcr_image |= MCR_RTS);
+ enable_intr();
+ com->ibuf = ibuf;
+ }
+
+ if (com->state & CS_CHECKMSR) {
+ u_char delta_modem_status;
+
+ disable_intr();
+ delta_modem_status = com->last_modem_status
+ ^ com->prev_modem_status;
+ com->prev_modem_status = com->last_modem_status;
+ com_events -= LOTS_OF_EVENTS;
+ com->state &= ~CS_CHECKMSR;
+ enable_intr();
+ if (delta_modem_status & MSR_DCD && !FAKE_DCD(unit)) {
+ if (com->prev_modem_status & MSR_DCD) {
+ (*linesw[tp->t_line].l_modem)(tp, 1);
+#ifdef COM_BIDIR
+ wakeup((caddr_t) &com->active_in);
+#endif /* COM_BIDIR */
+ } else
+ (*linesw[tp->t_line].l_modem)(tp, 0);
+ }
+ }
+
+ /* XXX */
+ if (TRUE) {
+ u_int delta;
+ int errnum;
+ u_long total;
+
+ for (errnum = 0; errnum < CE_NTYPES; ++errnum) {
+ disable_intr();
+ delta = com->delta_error_counts[errnum];
+ com->delta_error_counts[errnum] = 0;
+ enable_intr();
+ if (delta != 0) {
+ total =
+ com->error_counts[errnum] += delta;
+ log(LOG_WARNING,
+ "sio%d: %u more %s%s (total %lu)\n",
+ unit, delta, error_desc[errnum],
+ delta == 1 ? "" : "s", total);
+ }
+ }
+ }
+ if (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
+ && TB_RAW(tp)->c_cc + incc >= RB_I_HIGH_WATER /*
+ && !(tp->t_state & TS_RTS_IFLOW) */
+ /*
+ * XXX - need RTS flow control for all line disciplines.
+ * Only have it in standard one now.
+ */
+ && linesw[tp->t_line].l_rint == ttyinput) {
+/* tp->t_state |= TS_RTS_IFLOW; */
+ ttstart(tp);
+ }
+#if 0
+ /*
+ * 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(TB_RAW(tp), (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 {
+#endif
+ 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 0
+ }
+#endif
+ if (com_events == 0)
+ break;
+ }
+ if (com_events >= LOTS_OF_EVENTS)
+ goto repeat;
+
+#ifdef OLD_INTERRUPT_HANDLING
+ splx(s);
+ awake = FALSE;
+#endif
+}
+
+static int
+comparam(tp, t)
+ struct tty *tp;
+ struct termios *t;
+{
+ u_int cfcr;
+ int cflag;
+ struct com_s *com;
+ int divisor;
+ int error;
+ Port_t iobase;
+ int s;
+ int unit;
+
+ /* check requested parameters */
+ divisor = ttspeedtab(t->c_ospeed, comspeedtab);
+ if (t->c_ispeed == 0)
+ t->c_ispeed = t->c_ospeed;
+ if (divisor < 0 || 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)
+ commctl(com, MCR_DTR, DMBIC); /* hang up line */
+ else
+ commctl(com, MCR_DTR, DMBIS);
+ cflag = t->c_cflag;
+ switch (cflag & CSIZE) {
+ case CS5:
+ cfcr = CFCR_5BITS;
+ break;
+ case CS6:
+ cfcr = CFCR_6BITS;
+ break;
+ case CS7:
+ cfcr = CFCR_7BITS;
+ break;
+ default:
+ cfcr = CFCR_8BITS;
+ break;
+ }
+ if (cflag & PARENB) {
+ cfcr |= CFCR_PENAB;
+ if (!(cflag & PARODD))
+ cfcr |= CFCR_PEVEN;
+ }
+ if (cflag & CSTOPB)
+ cfcr |= CFCR_STOPB;
+
+ /*
+ * Some UARTs lock up if the divisor latch registers are selected
+ * while the UART is doing output (they refuse to transmit anything
+ * more until given a hard reset). Fix this by stopping filling
+ * the device buffers and waiting for them to drain. Reading the
+ * line status port outside of siointr1() might lose some receiver
+ * error bits, but that is acceptable here.
+ */
+ disable_intr();
+retry:
+ com->state &= ~CS_TTGO;
+ enable_intr();
+ while ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY))
+ != (LSR_TSRE | LSR_TXRDY)) {
+ error = ttysleep(tp, (caddr_t)TB_RAW(tp), TTIPRI | PCATCH,
+ "sioparam", 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 */
+
+ /*
+ * XXX - clearing CS_TTGO is not sufficient to stop further output,
+ * because siopoll() calls comstart() which usually sets it again
+ * because TS_TTSTOP is clear. Setting TS_TTSTOP would not be
+ * sufficient, for similar reasons.
+ */
+ if ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY))
+ != (LSR_TSRE | LSR_TXRDY))
+ goto retry;
+
+ if (divisor != 0) {
+ outb(iobase + com_cfcr, cfcr | CFCR_DLAB);
+ outb(iobase + com_dlbl, divisor & 0xFF);
+ outb(iobase + com_dlbh, (u_int) divisor >> 8);
+ }
+ outb(iobase + com_cfcr, com->cfcr_image = cfcr);
+ if (!(tp->t_state & TS_TTSTOP))
+ com->state |= CS_TTGO;
+ if (cflag & CRTS_IFLOW)
+ com->state |= CS_RTS_IFLOW; /* XXX - secondary changes? */
+ else
+ com->state &= ~CS_RTS_IFLOW;
+
+ /*
+ * Set up state to handle output flow control.
+ * XXX - worth handling MDMBUF (DCD) flow control at the lowest level?
+ * Now has 16+ msec latency, while CTS flow has 50- usec latency.
+ */
+ com->state &= ~CS_CTS_OFLOW;
+ com->state |= CS_ODEVREADY;
+ if (cflag & CCTS_OFLOW) {
+ com->state |= CS_CTS_OFLOW;
+ if (!(com->last_modem_status & MSR_CTS))
+ com->state &= ~CS_ODEVREADY;
+ }
+
+ /*
+ * Recover from fiddling with CS_TTGO. We used to call siointr1()
+ * unconditionally, but that defeated the careful discarding of
+ * stale input in sioopen().
+ *
+ * XXX sioopen() is not careful waiting for carrier for the callout
+ * case.
+ */
+ if (com->state >= (CS_BUSY | CS_TTGO))
+ siointr1(com);
+
+ enable_intr();
+ splx(s);
+ return (0);
+}
+
+static void
+comstart(tp)
+ struct tty *tp;
+{
+ struct com_s *com;
+ int s;
+ int unit;
+
+ unit = 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 0
+ if (tp->t_state & TS_RTS_IFLOW) {
+ if (com->mcr_image & MCR_RTS && com->state & CS_RTS_IFLOW)
+ outb(com->modem_ctl_port, com->mcr_image &= ~MCR_RTS);
+ } else {
+#endif
+ /*
+ * XXX don't raise MCR_RTS if CTS_RTS_IFLOW is off. Set it
+ * appropriately in comparam() if RTS-flow is being changed.
+ * Check for races.
+ */
+ if (!(com->mcr_image & MCR_RTS) && com->iptr < com->ihighwater)
+ outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
+#if 0
+ }
+#endif
+ enable_intr();
+ if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))
+ goto out;
+ if (TB_OUT(tp)->c_cc <= tp->t_lowat) {
+ if (tp->t_state & TS_ASLEEP) {
+ tp->t_state &= ~TS_ASLEEP;
+ wakeup((caddr_t)TB_OUT(tp));
+ }
+ selwakeup(&tp->t_wsel);
+ }
+ if (com->ocount != 0) {
+ disable_intr();
+ siointr1(com);
+ enable_intr();
+ } else if (TB_OUT(tp)->c_cc != 0) {
+ tp->t_state |= TS_BUSY;
+ disable_intr();
+ com->ocount = q_to_b(TB_OUT(tp), com->obuf, sizeof com->obuf);
+ com->optr = com->obuf;
+ com->obufend = com->obuf + com->ocount;
+ com->state |= CS_BUSY;
+ siointr1(com); /* fake interrupt to start output */
+ enable_intr();
+ }
+out:
+ splx(s);
+}
+
+void
+siostop(tp, rw)
+ struct tty *tp;
+ int rw;
+{
+ struct com_s *com;
+
+ com = com_addr(UNIT(tp->t_dev));
+ if (rw & FWRITE)
+ comflush(com);
+ disable_intr();
+ if (rw & FREAD) {
+ com_events -= (com->iptr - com->ibuf);
+ com->iptr = com->ibuf;
+ }
+ if (tp->t_state & TS_TTSTOP)
+ com->state &= ~CS_TTGO;
+ else
+ com->state |= CS_TTGO;
+ enable_intr();
+}
+
+int
+sioselect(dev, rw, p)
+ dev_t dev;
+ int rw;
+ struct proc *p;
+{
+ return (ttselect(dev & ~COM_MINOR_MAGIC_MASK, rw, p));
+}
+
+static void
+commctl(com, bits, how)
+ struct com_s *com;
+ int bits;
+ int how;
+{
+ disable_intr();
+ switch (how) {
+ case DMSET:
+ outb(com->modem_ctl_port,
+ com->mcr_image = bits | (com->mcr_image & MCR_IENABLE));
+ break;
+ case DMBIS:
+ outb(com->modem_ctl_port, com->mcr_image |= bits);
+ break;
+ case DMBIC:
+ outb(com->modem_ctl_port, com->mcr_image &= ~bits);
+ break;
+ }
+ enable_intr();
+}
+
+static void
+comwakeup(chan, ticks)
+ caddr_t chan;
+ int ticks;
+{
+ int unit;
+
+ timeout((timeout_func_t)comwakeup, (caddr_t) NULL, hz / 100);
+
+ if (com_events != 0) {
+#ifndef OLD_INTERRUPT_HANDLING
+ int s = spltty();
+#endif
+ siopoll();
+#ifndef OLD_INTERRUPT_HANDLING
+ splx(s);
+#endif
+ }
+
+ /* recover from lost output interrupts */
+ for (unit = 0; unit < NSIO; ++unit) {
+ struct com_s *com;
+
+ com = com_addr(unit);
+ if (com != NULL && com->state >= (CS_BUSY | CS_TTGO)) {
+ disable_intr();
+ siointr1(com);
+ enable_intr();
+ }
+ }
+}
+
+#ifdef OLD_INTERRUPT_HANDLING
+void
+softsio1()
+{
+ siopoll();
+}
+#endif
+
+/*
+ * Following are all routines needed for SIO to act as console
+ */
+#include "i386/i386/cons.h"
+
+struct siocnstate {
+ u_char dlbl;
+ u_char dlbh;
+ u_char ier;
+ u_char cfcr;
+ u_char mcr;
+};
+
+static Port_t siocniobase;
+
+static void
+siocntxwait()
+{
+ int timo;
+
+ /*
+ * Wait for any pending transmission to finish. Required to avoid
+ * the UART lockup bug when the speed is changed, and for normal
+ * transmits.
+ */
+ timo = 100000;
+ while ((inb(siocniobase + com_lsr) & (LSR_TSRE | LSR_TXRDY))
+ != (LSR_TSRE | LSR_TXRDY) && --timo != 0)
+ ;
+}
+
+static void
+siocnopen(sp)
+ struct siocnstate *sp;
+{
+ int divisor;
+ Port_t iobase;
+
+ /*
+ * Save all the device control registers except the fifo register
+ * and set our default ones (cs8 -parenb speed=comdefaultrate).
+ * We can't save the fifo register since it is read-only.
+ */
+ iobase = siocniobase;
+ sp->ier = inb(iobase + com_ier);
+ outb(iobase + com_ier, 0); /* spltty() doesn't stop siointr() */
+ siocntxwait();
+ sp->cfcr = inb(iobase + com_cfcr);
+ outb(iobase + com_cfcr, CFCR_DLAB);
+ sp->dlbl = inb(iobase + com_dlbl);
+ sp->dlbh = inb(iobase + com_dlbh);
+ divisor = ttspeedtab(comdefaultrate, comspeedtab);
+ outb(iobase + com_dlbl, divisor & 0xFF);
+ outb(iobase + com_dlbh, (u_int) divisor >> 8);
+ outb(iobase + com_cfcr, CFCR_8BITS);
+ sp->mcr = inb(iobase + com_mcr);
+ outb(iobase + com_mcr, MCR_DTR | MCR_RTS);
+}
+
+static void
+siocnclose(sp)
+ struct siocnstate *sp;
+{
+ Port_t iobase;
+
+ /*
+ * Restore the device control registers.
+ */
+ siocntxwait();
+ iobase = siocniobase;
+ outb(iobase + com_cfcr, CFCR_DLAB);
+ outb(iobase + com_dlbl, sp->dlbl);
+ outb(iobase + com_dlbh, sp->dlbh);
+ outb(iobase + com_cfcr, sp->cfcr);
+ /*
+ * XXX damp osicllations of MCR_DTR or MCR_RTS by not restoring them.
+ */
+ outb(iobase + com_mcr, sp->mcr | MCR_DTR | MCR_RTS);
+ outb(iobase + com_ier, sp->ier);
+}
+
+void
+siocnprobe(cp)
+ struct consdev *cp;
+{
+ int unit;
+
+ /* locate the major number */
+ /* XXX - should be elsewhere since KGDB uses it */
+ for (commajor = 0; commajor < nchrdev; commajor++)
+ if (cdevsw[commajor].d_open == sioopen)
+ break;
+
+ /* XXX: ick */
+ unit = UNIT(CONUNIT);
+ siocniobase = CONADDR;
+
+ /* make sure hardware exists? XXX */
+
+ /* initialize required fields */
+ cp->cn_dev = makedev(commajor, unit);
+#ifdef COMCONSOLE
+ cp->cn_pri = CN_REMOTE; /* Force a serial port console */
+#else
+ cp->cn_pri = CN_NORMAL;
+#endif
+}
+
+void
+siocninit(cp)
+ struct consdev *cp;
+{
+ /*
+ * XXX can delete more comconsole stuff now that i/o routines are
+ * fairly reentrant.
+ */
+ comconsole = UNIT(cp->cn_dev);
+}
+
+int
+siocngetc(dev)
+ dev_t dev;
+{
+ int c;
+ Port_t iobase;
+ int s;
+ struct siocnstate sp;
+
+ iobase = siocniobase;
+ s = spltty();
+ siocnopen(&sp);
+ while (!(inb(iobase + com_lsr) & LSR_RXRDY))
+ ;
+ c = inb(iobase + com_data);
+ siocnclose(&sp);
+ splx(s);
+ return (c);
+}
+
+void
+siocnputc(dev, c)
+ dev_t dev;
+ int c;
+{
+ int s;
+ struct siocnstate sp;
+
+ s = spltty();
+ siocnopen(&sp);
+ siocntxwait();
+ outb(siocniobase + com_data, c);
+ siocnclose(&sp);
+ splx(s);
+}
+
+#endif /* NSIO > 0 */
diff --git a/sys/dev/sio/sioreg.h b/sys/dev/sio/sioreg.h
new file mode 100644
index 0000000..4b0f1b6
--- /dev/null
+++ b/sys/dev/sio/sioreg.h
@@ -0,0 +1,114 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)comreg.h 7.2 (Berkeley) 5/9/91
+ * $Id$
+ */
+
+
+/* 16 bit baud rate divisor (lower byte in dca_data, upper in dca_ier) */
+#define COMBRD(x) (1843200 / (16*(x)))
+
+/* interrupt enable register */
+#define IER_ERXRDY 0x1
+#define IER_ETXRDY 0x2
+#define IER_ERLS 0x4
+#define IER_EMSC 0x8
+
+/* interrupt identification register */
+#define IIR_IMASK 0xf
+#define IIR_RXTOUT 0xc
+#define IIR_RLS 0x6
+#define IIR_RXRDY 0x4
+#define IIR_TXRDY 0x2
+#define IIR_NOPEND 0x1
+#define IIR_MLSC 0x0
+#define IIR_FIFO_MASK 0xc0 /* set if FIFOs are enabled */
+
+/* fifo control register */
+#define FIFO_ENABLE 0x01
+#define FIFO_RCV_RST 0x02
+#define FIFO_XMT_RST 0x04
+#define FIFO_DMA_MODE 0x08
+#define FIFO_TRIGGER_1 0x00
+#define FIFO_TRIGGER_4 0x40
+#define FIFO_TRIGGER_8 0x80
+#define FIFO_TRIGGER_14 0xc0
+
+/* character format control register */
+#define CFCR_DLAB 0x80
+#define CFCR_SBREAK 0x40
+#define CFCR_PZERO 0x30
+#define CFCR_PONE 0x20
+#define CFCR_PEVEN 0x10
+#define CFCR_PODD 0x00
+#define CFCR_PENAB 0x08
+#define CFCR_STOPB 0x04
+#define CFCR_8BITS 0x03
+#define CFCR_7BITS 0x02
+#define CFCR_6BITS 0x01
+#define CFCR_5BITS 0x00
+
+/* modem control register */
+#define MCR_LOOPBACK 0x10
+#define MCR_IENABLE 0x08
+#define MCR_DRS 0x04
+#define MCR_RTS 0x02
+#define MCR_DTR 0x01
+
+/* line status register */
+#define LSR_RCV_FIFO 0x80
+#define LSR_TSRE 0x40
+#define LSR_TXRDY 0x20
+#define LSR_BI 0x10
+#define LSR_FE 0x08
+#define LSR_PE 0x04
+#define LSR_OE 0x02
+#define LSR_RXRDY 0x01
+#define LSR_RCV_MASK 0x1f
+
+/* modem status register */
+#define MSR_DCD 0x80
+#define MSR_RI 0x40
+#define MSR_DSR 0x20
+#define MSR_CTS 0x10
+#define MSR_DDCD 0x08
+#define MSR_TERI 0x04
+#define MSR_DDSR 0x02
+#define MSR_DCTS 0x01
+
+/*
+ * WARNING: Serial console is assumed to be at COM1 address
+ * and CONUNIT must be 0.
+ */
+#define CONADDR (0x3f8)
+#define CONUNIT (0)
diff --git a/sys/dev/speaker/speaker.h b/sys/dev/speaker/speaker.h
new file mode 100644
index 0000000..af80a28
--- /dev/null
+++ b/sys/dev/speaker/speaker.h
@@ -0,0 +1,30 @@
+/*
+ * speaker.h -- interface definitions for speaker ioctl()
+ *
+ * v1.4 by Eric S. Raymond (esr@snark.thyrsus.com) Aug 1993
+ * modified for FreeBSD by Andrew A. Chernov <ache@astral.msk.su>
+ */
+
+#ifndef _SPEAKER_H_
+#define _SPEAKER_H_
+
+#include <sys/ioctl.h>
+
+#define SPKRTONE _IOW('S', 1, tone_t) /* emit tone */
+#define SPKRTUNE _IO('S', 2) /* emit tone sequence*/
+
+typedef struct
+{
+ int frequency; /* in hertz */
+ int duration; /* in 1/100ths of a second */
+}
+tone_t;
+
+/*
+ * Strings written to the speaker device are interpreted as tunes and played;
+ * see the spkr(4) man page for details.
+ */
+
+#endif /* _SPEAKER_H_ */
+
+/* speaker.h ends here */
diff --git a/sys/dev/speaker/spkr.c b/sys/dev/speaker/spkr.c
new file mode 100644
index 0000000..d273f31
--- /dev/null
+++ b/sys/dev/speaker/spkr.c
@@ -0,0 +1,541 @@
+/*
+ * spkr.c -- device driver for console speaker
+ *
+ * v1.4 by Eric S. Raymond (esr@snark.thyrsus.com) Aug 1993
+ * modified for FreeBSD by Andrew A. Chernov <ache@astral.msk.su>
+ *
+ * $Id: spkr.c,v 1.7 1994/01/25 23:04:27 ache Exp $
+ */
+
+#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 "i386/isa/isa.h"
+#include "i386/isa/timerreg.h"
+#include "machine/speaker.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_SPKR 0x03 /* turn these PPI bits on to pass sound */
+#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 */
+
+#define SPKRPRI PSOCK
+static char endtone, endrest;
+
+static void tone(thz, ticks)
+/* emit tone of frequency thz for given number of ticks */
+unsigned int thz, ticks;
+{
+ unsigned int divisor = TIMER_CLK / thz;
+ int sps;
+
+#ifdef DEBUG
+ (void) printf("tone: thz=%d ticks=%d\n", thz, ticks);
+#endif /* DEBUG */
+
+ /* set timer to generate clicks at given frequency in Hertz */
+ sps = spltty();
+
+ if (acquire_timer2(PIT_MODE)) {
+ /* enter list of waiting procs ??? */
+ return;
+ }
+ outb(TIMER_CNTR2, (divisor & 0xff)); /* send lo byte */
+ outb(TIMER_CNTR2, (divisor >> 8)); /* send hi byte */
+ splx(sps);
+
+ /* turn the speaker on */
+ outb(IO_PPI, inb(IO_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.
+ */
+ (void) tsleep((caddr_t)&endtone, SPKRPRI | PCATCH, "spkrtn", ticks);
+ outb(IO_PPI, inb(IO_PPI) & ~PPI_SPKR);
+ release_timer2();
+}
+
+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
+ (void) printf("rest: %d\n", ticks);
+#endif /* DEBUG */
+ (void) tsleep((caddr_t)&endrest, SPKRPRI | PCATCH, "spkrrs", ticks);
+}
+
+/**************** PLAY STRING INTERPRETER BEGINS HERE **********************
+ *
+ * Play string interpretation is modelled on IBM BASIC 2.0's PLAY statement;
+ * M[LNS] are missing; the ~ synonym and the _ slur mark and the octave-
+ * tracking facility are 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--)
+ {
+ /* See the BUGS section in the man page for discussion */
+ 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
+ (void) 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, oldfill, 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
+ (void) 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++;
+ }
+
+ /* ...and/or a slur mark */
+ oldfill = fill;
+ if (cp[1] == '_')
+ {
+ fill = LEGATO;
+ ++cp;
+ slen--;
+ }
+
+ /* time to emit the actual tone */
+ playtone(pitch, timeval, sustain);
+
+ fill = oldfill;
+ 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++;
+ }
+ oldfill = fill;
+ if (cp[1] == '_')
+ {
+ fill = LEGATO;
+ ++cp;
+ slen--;
+ }
+ playtone(pitch - 1, value, sustain);
+ fill = oldfill;
+ 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 = FALSE; /* exclusion flag */
+static struct buf *spkr_inbuf; /* incoming buf */
+
+int spkropen(dev)
+dev_t dev;
+{
+#ifdef DEBUG
+ (void) printf("spkropen: entering with dev = %x\n", dev);
+#endif /* DEBUG */
+
+ if (minor(dev) != 0)
+ return(ENXIO);
+ else if (spkr_active)
+ return(EBUSY);
+ else
+ {
+#ifdef DEBUG
+ (void) printf("spkropen: about to perform play initialization\n");
+#endif /* DEBUG */
+ playinit();
+ spkr_inbuf = geteblk(DEV_BSIZE);
+ spkr_active = TRUE;
+ return(0);
+ }
+}
+
+int spkrwrite(dev, uio)
+dev_t dev;
+struct uio *uio;
+{
+#ifdef DEBUG
+ printf("spkrwrite: entering with dev = %x, count = %d\n",
+ dev, uio->uio_resid);
+#endif /* DEBUG */
+
+ if (minor(dev) != 0)
+ return(ENXIO);
+ else if (uio->uio_resid > DEV_BSIZE) /* prevent system crashes */
+ return(E2BIG);
+ else
+ {
+ unsigned n;
+ char *cp;
+ int error;
+
+ n = uio->uio_resid;
+ cp = spkr_inbuf->b_un.b_addr;
+ if (!(error = uiomove(cp, n, uio)))
+ playstring(cp, n);
+ return(error);
+ }
+}
+
+int spkrclose(dev)
+dev_t dev;
+{
+#ifdef DEBUG
+ (void) printf("spkrclose: entering with dev = %x\n", dev);
+#endif /* DEBUG */
+
+ if (minor(dev) != 0)
+ return(ENXIO);
+ else
+ {
+ wakeup((caddr_t)&endtone);
+ wakeup((caddr_t)&endrest);
+ brelse(spkr_inbuf);
+ spkr_active = FALSE;
+ return(0);
+ }
+}
+
+int spkrioctl(dev, cmd, cmdarg)
+dev_t dev;
+int cmd;
+caddr_t cmdarg;
+{
+#ifdef DEBUG
+ (void) printf("spkrioctl: entering with dev = %x, cmd = %x\n");
+#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);
+ return 0;
+ }
+ 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);
+ }
+ return(0);
+ }
+ return(EINVAL);
+}
+
+#endif /* NSPEAKER > 0 */
+/* spkr.c ends here */
diff --git a/sys/dev/syscons/syscons.c b/sys/dev/syscons/syscons.c
new file mode 100644
index 0000000..a2a931c
--- /dev/null
+++ b/sys/dev/syscons/syscons.c
@@ -0,0 +1,2660 @@
+/*-
+ * Copyright (c) 1992-1994 Søren Schmidt
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz and Don Ahn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from:@(#)syscons.c 1.3 940129
+ * $Id: syscons.c,v 1.46 1994/05/25 08:59:56 rgrimes Exp $
+ *
+ */
+
+#if !defined(__FreeBSD__)
+#define FAT_CURSOR
+#endif
+
+#include "param.h"
+#include <sys/systm.h>
+#include "conf.h"
+#include "ioctl.h"
+#include "proc.h"
+#include "user.h"
+#include "tty.h"
+#include "uio.h"
+#include "callout.h"
+#include "kernel.h"
+#include "syslog.h"
+#include "errno.h"
+#include "malloc.h"
+#include "i386/isa/isa.h"
+#include "i386/isa/isa_device.h"
+#include "i386/isa/timerreg.h"
+#include "i386/i386/cons.h"
+#include "machine/console.h"
+#include "machine/psl.h"
+#include "machine/frame.h"
+#include "machine/pc/display.h"
+#include "iso8859.font"
+#include "kbdtables.h"
+#include "sc.h"
+
+#if NSC > 0
+
+#if !defined(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
+
+/* video hardware memory addresses */
+#define VIDEOMEM 0x000A0000
+
+/* misc defines */
+#define MAX_ESC_PAR 3
+#define TEXT80x25 1
+#define TEXT80x50 2
+#define COL 80
+#define ROW 25
+#define BELL_DURATION 5
+#define BELL_PITCH 800
+#define TIMER_FREQ 1193182 /* should be in isa.h */
+#define PCBURST 256
+
+/* defines related to hardware addresses */
+#define MONO_BASE 0x3B4 /* crt controller base mono */
+#define COLOR_BASE 0x3D4 /* crt controller base color */
+#define ATC IO_VGA+0x00 /* attribute controller */
+#define TSIDX IO_VGA+0x04 /* timing sequencer idx */
+#define TSREG IO_VGA+0x05 /* timing sequencer data */
+#define PIXMASK IO_VGA+0x06 /* pixel write mask */
+#define PALRADR IO_VGA+0x07 /* palette read address */
+#define PALWADR IO_VGA+0x08 /* palette write address */
+#define PALDATA IO_VGA+0x09 /* palette data register */
+#define GDCIDX IO_VGA+0x0E /* graph data controller idx */
+#define GDCREG IO_VGA+0x0F /* graph data controller data */
+
+/* special characters */
+#define cntlc 0x03
+#define cntld 0x04
+#define bs 0x08
+#define lf 0x0a
+#define cr 0x0d
+#define del 0x7f
+
+typedef struct term_stat {
+ int esc; /* processing escape sequence */
+ int num_param; /* # of parameters to ESC */
+ int last_param; /* last parameter # */
+ int param[MAX_ESC_PAR]; /* contains ESC parameters */
+ int cur_attr; /* current attributes */
+ int std_attr; /* normal attributes */
+ int rev_attr; /* reverse attributes */
+} term_stat;
+
+typedef struct scr_stat {
+ u_short *crt_base; /* address of screen memory */
+ u_short *scr_buf; /* buffer when off screen */
+ u_short *crtat; /* cursor address */
+ int xpos; /* current X position */
+ int ypos; /* current Y position */
+ int xsize; /* X size */
+ int ysize; /* Y size */
+ term_stat term; /* terminal emulation stuff */
+ char cursor_start; /* cursor start line # */
+ char cursor_end; /* cursor end line # */
+ u_char border; /* border color */
+ u_short bell_duration;
+ u_short bell_pitch;
+ u_short status; /* status (bitfield) */
+ u_short mode; /* mode */
+ pid_t pid; /* pid of controlling proc */
+ struct proc *proc; /* proc* of controlling proc */
+ struct vt_mode smode; /* switch mode */
+} scr_stat;
+
+typedef struct default_attr {
+ int std_attr; /* normal attributes */
+ int rev_attr; /* reverse attributes */
+} default_attr;
+
+static default_attr user_default = {
+ (FG_LIGHTGREY | BG_BLACK) << 8,
+ (FG_BLACK | BG_LIGHTGREY) << 8
+};
+
+static default_attr kernel_default = {
+ (FG_WHITE | BG_BLACK) << 8,
+ (FG_BLACK | BG_LIGHTGREY) << 8
+};
+
+#define CONSOLE_BUFFER_SIZE 1024
+int console_buffer_count;
+char console_buffer[CONSOLE_BUFFER_SIZE];
+
+static scr_stat console[NCONS];
+static scr_stat *cur_console = &console[0];
+static scr_stat *new_scp, *old_scp;
+static term_stat kernel_console;
+static default_attr *current_default;
+static int switch_in_progress = 0;
+static u_short *crtat = 0;
+static u_int crtc_addr = MONO_BASE;
+static char crtc_vga = 0;
+static u_char shfts = 0, ctls = 0, alts = 0, agrs = 0, metas = 0;
+static u_char nlkcnt = 0, clkcnt = 0, slkcnt = 0, alkcnt = 0;
+static char palette[3*256];
+static const u_int n_fkey_tab = sizeof(fkey_tab) / sizeof(*fkey_tab);
+static int cur_cursor_pos = -1;
+static char in_putc = 0;
+static char polling = 0;
+static int delayed_next_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 int scrn_saver = 0; /* screen saver routine */
+static long scrn_time_stamp;
+static u_char scr_map[256];
+extern int hz;
+extern struct timeval time;
+
+/* function prototypes */
+int pcprobe(struct isa_device *dev);
+int pcattach(struct isa_device *dev);
+int pcopen(dev_t dev, int flag, int mode, struct proc *p);
+int pcclose(dev_t dev, int flag, int mode, struct proc *p);
+int pcread(dev_t dev, struct uio *uio, int flag);
+int pcwrite(dev_t dev, struct uio *uio, int flag);
+int pcparam(struct tty *tp, struct termios *t);
+int pcioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p);
+void pcxint(dev_t dev);
+void pcstart(struct tty *tp);
+void pccnprobe(struct consdev *cp);
+void pccninit(struct consdev *cp);
+void pccnputc(dev_t dev, char c);
+int pccngetc(dev_t dev);
+void scintr(int unit);
+int pcmmap(dev_t dev, int offset, int nprot);
+u_int sgetc(int noblock);
+int getchar(void);
+static void scinit(void);
+static void scput(u_char c);
+static u_int scgetc(int noblock);
+static struct tty *get_tty_ptr(dev_t dev);
+static scr_stat *get_scr_stat(dev_t dev);
+static int get_scr_num();
+static void cursor_shape(int start, int end);
+static void get_cursor_shape(int *start, int *end);
+static void cursor_pos(int force);
+static void clear_screen(scr_stat *scp);
+static int switch_scr(u_int next_scr);
+static void exchange_scr(void);
+static void move_crsr(scr_stat *scp, int x, int y);
+static void move_up(u_short *s, u_short *d, u_int len);
+static void move_down(u_short *s, u_short *d, u_int len);
+static void scan_esc(scr_stat *scp, u_char c);
+static void ansi_put(scr_stat *scp, u_char c);
+static u_char *get_fstr(u_int c, u_int *len);
+static void update_leds(int which);
+static void kbd_wait(void);
+static void kbd_cmd(u_char command);
+static void kbd_cmd2(u_char command, u_char arg);
+static int kbd_reply(void);
+static void set_mode(scr_stat *scp);
+static void set_border(int color);
+static void load_font(int segment, int size, char* font);
+static void save_palette(void);
+static void load_palette(void);
+static void change_winsize(struct tty *tp, int x, int y);
+
+
+/* available screen savers */
+
+static void none_saver(int test);
+static void blank_saver(int test);
+static void fade_saver(int test);
+static void star_saver(int test);
+static void snake_saver(int test);
+
+static const struct {
+ char *name;
+ void (*routine)();
+} screen_savers[] = {
+ { "none", none_saver }, /* 0 */
+ { "blank", blank_saver }, /* 1 */
+ { "fade", fade_saver }, /* 2 */
+ { "star", star_saver }, /* 3 */
+ { "snake", snake_saver }, /* 4 */
+};
+#define SCRN_SAVER(arg) (*screen_savers[scrn_saver].routine)(arg)
+#define NUM_SCRN_SAVERS (sizeof(screen_savers) / sizeof(screen_savers[0]))
+
+/* OS specific stuff */
+
+#if defined(NetBSD)
+#define VIRTUAL_TTY(x) pc_tty[x] ? (pc_tty[x]) : (pc_tty[x] = ttymalloc())
+#define CONSOLE_TTY pc_tty[NCONS] ? (pc_tty[NCONS]) : (pc_tty[NCONS] = ttymalloc())
+#define frametype struct trapframe
+#define eflags tf_eflags
+extern u_short *Crtat;
+struct tty *pc_tty[NCONS+1];
+int ttrstrt();
+#endif
+
+#if defined(__FreeBSD__)
+#if 0
+#define VIRTUAL_TTY(x) (pccons[x] = ttymalloc(pccons[x]))
+#define CONSOLE_TTY (pccons[NCONS] = ttymalloc(pccons[NCONS]))
+struct tty *pccons[NCONS+1];
+#else
+#define VIRTUAL_TTY(x) &pccons[x]
+#define CONSOLE_TTY &pccons[NCONS]
+struct tty pccons[NCONS+1];
+#endif
+#define timeout_t timeout_func_t
+#define frametype struct trapframe
+#define eflags tf_eflags
+#define MONO_BUF (KERNBASE+0xB0000)
+#define CGA_BUF (KERNBASE+0xB8000)
+#endif
+
+#if defined(__386BSD__) && !defined(__FreeBSD__)
+#define VIRTUAL_TTY(x) &pccons[x]
+#define CONSOLE_TTY &pccons[NCONS]
+#define frametype struct syscframe
+#define eflags sf_eflags
+#define timeout_t caddr_t
+#define MONO_BUF (0xFE0B0000)
+#define CGA_BUF (0xFE0B8000)
+struct tty pccons[NCONS+1];
+#endif
+
+#if defined(__386BSD__) || defined(__FreeBSD__)
+u_short *Crtat = (u_short *)MONO_BUF;
+void consinit(void) {scinit();}
+#include "ddb.h"
+#if NDDB > 0
+#define DDB 1
+#endif
+#endif
+
+struct isa_driver scdriver = {
+ pcprobe, pcattach, "sc",
+};
+
+
+int pcprobe(struct isa_device *dev)
+{
+ /* Enable interrupts and keyboard controller */
+ kbd_wait();
+ outb(KB_STAT, KB_WRITE);
+ kbd_cmd(0x4D);
+
+ /* Start keyboard stuff RESET */
+ for (;;) {
+ kbd_cmd(KB_RESET);
+ if (kbd_reply() == KB_ACK && /* command accepted */
+ kbd_reply() == 0xaa) /* self test passed */
+ break;
+ printf("Keyboard reset failed\n");
+ }
+ return (IO_KBDSIZE);
+}
+
+
+int pcattach(struct isa_device *dev)
+{
+ scr_stat *scp;
+ int start = -1, end = -1, i;
+
+ printf("sc%d: ", dev->id_unit);
+ if (crtc_vga)
+ if (crtc_addr == MONO_BASE)
+ printf("VGA mono");
+ else
+ printf("VGA color");
+ else
+ if (crtc_addr == MONO_BASE)
+ printf("MDA/hercules");
+ else
+ printf("CGA/EGA");
+
+ if (NCONS > 1)
+ printf(" <%d virtual consoles>\n", NCONS);
+ else
+ printf("\n");
+#if defined(FAT_CURSOR)
+ start = 0;
+ end = 18;
+ if (crtc_vga) {
+#else
+ if (crtc_vga) {
+ get_cursor_shape(&start, &end);
+#endif
+ 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 = &console[i];
+ scp->scr_buf = (u_short *)malloc(COL * ROW * 2, M_DEVBUF, M_NOWAIT);
+ scp->mode = TEXT80x25;
+ scp->term.esc = 0;
+ scp->term.std_attr = current_default->std_attr;
+ scp->term.rev_attr = current_default->rev_attr;
+ scp->term.cur_attr = scp->term.std_attr;
+ scp->border = BG_BLACK;
+ scp->cursor_start = start;
+ scp->cursor_end = end;
+ scp->xsize = COL;
+ scp->ysize = ROW;
+ scp->bell_pitch = BELL_PITCH;
+ scp->bell_duration = BELL_DURATION;
+ scp->status = 0;
+ scp->pid = 0;
+ scp->proc = NULL;
+ scp->smode.mode = VT_AUTO;
+ if (i > 0) {
+ scp->crt_base = scp->crtat = scp->scr_buf;
+ fillw(scp->term.cur_attr|scr_map[0x20], scp->scr_buf, COL*ROW);
+ }
+ }
+ /* get cursor going */
+#if defined(FAT_CURSOR)
+ cursor_shape(console[0].cursor_start,
+ console[0].cursor_end);
+#endif
+ cursor_pos(1);
+ return 0;
+}
+
+
+static struct tty *get_tty_ptr(dev_t dev)
+{
+ int unit = minor(dev);
+
+ if (unit > NCONS)
+ return(NULL);
+ if (unit == NCONS)
+ return(CONSOLE_TTY);
+ return(VIRTUAL_TTY(unit));
+}
+
+
+static scr_stat *get_scr_stat(dev_t dev)
+{
+ int unit = minor(dev);
+
+ if (unit > NCONS)
+ return(NULL);
+ if (unit == NCONS)
+ return(&console[0]);
+ return(&console[unit]);
+}
+
+
+static int get_scr_num()
+{
+ int i = 0;
+
+ while ((i < NCONS) && (cur_console != &console[i])) i++;
+ return i < NCONS ? i : 0;
+}
+
+int pcopen(dev_t dev, int flag, int mode, struct proc *p)
+{
+ struct tty *tp = get_tty_ptr(dev);
+
+ if (!tp)
+ return(ENXIO);
+
+ tp->t_oproc = pcstart;
+ tp->t_param = pcparam;
+ tp->t_dev = dev;
+ if (!(tp->t_state & TS_ISOPEN)) {
+ 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;
+ tp->t_cflag |= CLOCAL;
+ return((*linesw[tp->t_line].l_open)(dev, tp));
+}
+
+
+int pcclose(dev_t dev, int flag, int mode, struct proc *p)
+{
+ struct tty *tp = get_tty_ptr(dev);
+ struct scr_stat *scp;
+
+ if (!tp)
+ return(ENXIO);
+ if (minor(dev) < NCONS) {
+ scp = get_scr_stat(tp->t_dev);
+ if (scp->status & SWITCH_WAIT_ACQ)
+ wakeup((caddr_t)&scp->smode);
+ scp->pid = 0;
+ scp->proc = NULL;
+ scp->smode.mode = VT_AUTO;
+ }
+ (*linesw[tp->t_line].l_close)(tp, flag);
+ ttyclose(tp);
+ return(0);
+}
+
+
+int pcread(dev_t dev, struct uio *uio, int flag)
+{
+ struct tty *tp = get_tty_ptr(dev);
+
+ if (!tp)
+ return(ENXIO);
+ return((*linesw[tp->t_line].l_read)(tp, uio, flag));
+}
+
+
+int pcwrite(dev_t dev, struct uio *uio, int flag)
+{
+ struct tty *tp = get_tty_ptr(dev);
+
+ if (!tp)
+ return(ENXIO);
+ return((*linesw[tp->t_line].l_write)(tp, uio, flag));
+}
+
+
+/*
+ * Got a console interrupt, keyboard action !
+ * Catch the character, and see who it goes to.
+ */
+void scintr(int unit)
+{
+ static struct tty *cur_tty;
+ int c, len;
+ u_char *cp;
+
+ /* make screensaver happy */
+ scrn_time_stamp = time.tv_sec;
+ if (scrn_blanked)
+ SCRN_SAVER(0);
+
+ c = scgetc(1);
+
+ cur_tty = VIRTUAL_TTY(get_scr_num());
+ if (!(cur_tty->t_state & TS_ISOPEN))
+ cur_tty = CONSOLE_TTY;
+
+ if (!(cur_tty->t_state & TS_ISOPEN) || polling)
+ return;
+
+ switch (c & 0xff00) {
+ case 0x0000: /* normal key */
+ (*linesw[cur_tty->t_line].l_rint)(c & 0xFF, cur_tty);
+ break;
+ case NOKEY: /* nothing there */
+ break;
+ case FKEY: /* function key, return string */
+ if (cp = get_fstr((u_int)c, (u_int *)&len)) {
+ while (len-- > 0)
+ (*linesw[cur_tty->t_line].l_rint)
+ (*cp++ & 0xFF, cur_tty);
+ }
+ break;
+ case MKEY: /* meta is active, prepend ESC */
+ (*linesw[cur_tty->t_line].l_rint)(0x1b, cur_tty);
+ (*linesw[cur_tty->t_line].l_rint)(c & 0xFF, cur_tty);
+ break;
+ }
+}
+
+
+/*
+ * Set line parameters
+ */
+int pcparam(struct tty *tp, struct termios *t)
+{
+ int cflag = t->c_cflag;
+
+ /* and copy to tty */
+ tp->t_ispeed = t->c_ispeed;
+ tp->t_ospeed = t->c_ospeed;
+ tp->t_cflag = cflag;
+ return 0;
+}
+
+
+int pcioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
+{
+ int i, error;
+ struct tty *tp;
+ frametype *fp;
+ scr_stat *scp;
+
+ tp = get_tty_ptr(dev);
+ if (!tp)
+ return ENXIO;
+ scp = get_scr_stat(tp->t_dev);
+
+ switch (cmd) { /* process console hardware related ioctl's */
+
+ case CONS_BLANKTIME: /* set screen saver timeout (0 = no saver) */
+ scrn_blank_time = *(int*)data;
+ return 0;
+ case CONS_SSAVER: /* set screen saver */
+ {
+ register ssaver_t *sav = (ssaver_t *)data;
+ if (sav->num < 0 || sav->num >= NUM_SCRN_SAVERS)
+ return EIO;
+ SCRN_SAVER(0);
+ scrn_saver = sav->num;
+ scrn_blank_time = sav->time;
+ return 0;
+ }
+ case CONS_GSAVER: /* get screen saver info */
+ {
+ register ssaver_t *sav = (ssaver_t *)data;
+ if (sav->num < 0)
+ sav->num = scrn_saver;
+ else if (sav->num >= NUM_SCRN_SAVERS)
+ return EIO;
+ sav->time = scrn_blank_time;
+ strcpy(sav->name, screen_savers[sav->num].name);
+ return 0;
+ }
+ case CONS_80x25TEXT: /* set 80x25 text mode */
+ if (!crtc_vga)
+ return ENXIO;
+ scp->mode = TEXT80x25;
+ scp->ysize = 25;
+ free(scp->scr_buf, M_DEVBUF);
+ scp->scr_buf = (u_short *)malloc(scp->xsize*scp->ysize*2,
+ M_DEVBUF, M_NOWAIT);
+ if (scp != cur_console)
+ scp->crt_base = scp->scr_buf;
+ set_mode(scp);
+ clear_screen(scp);
+ change_winsize(tp, scp->xsize, scp->ysize);
+ return 0;
+
+ case CONS_80x50TEXT: /* set 80x50 text mode */
+ if (!crtc_vga)
+ return ENXIO;
+ scp->mode = TEXT80x50;
+ scp->ysize = 50;
+ free(scp->scr_buf, M_DEVBUF);
+ scp->scr_buf = (u_short *)malloc(scp->xsize*scp->ysize*2,
+ M_DEVBUF, M_NOWAIT);
+ if (scp != cur_console)
+ scp->crt_base = scp->scr_buf;
+ set_mode(scp);
+ clear_screen(scp);
+ change_winsize(tp, scp->xsize, scp->ysize);
+ return 0;
+
+ case CONS_GETVERS: /* get version number */
+ *(int*)data = 0x103; /* version 1.3 */
+ return 0;
+
+ case CONS_GETINFO: /* get current (virtual) console info */
+ {
+ vid_info_t *ptr = (vid_info_t*)data;
+ if (ptr->size == sizeof(struct vid_info)) {
+ ptr->m_num = get_scr_num();
+ ptr->mv_col = scp->xpos;
+ ptr->mv_row = scp->ypos;
+ ptr->mv_csz = scp->xsize;
+ ptr->mv_rsz = scp->ysize;
+ ptr->mv_norm.fore = (scp->term.std_attr & 0x0f00)>>8;
+ ptr->mv_norm.back = (scp->term.std_attr & 0xf000)>>12;
+ ptr->mv_rev.fore = (scp->term.rev_attr & 0x0f00)>>8;
+ ptr->mv_rev.back = (scp->term.rev_attr & 0xf000)>>12;
+ ptr->mv_grfc.fore = 0; /* not supported */
+ ptr->mv_grfc.back = 0; /* not supported */
+ ptr->mv_ovscan = scp->border;
+ ptr->mk_keylock = scp->status & LOCK_KEY_MASK;
+ return 0;
+ }
+ return EINVAL;
+ }
+
+ case VT_SETMODE: /* set screen switcher mode */
+ bcopy(data, &scp->smode, sizeof(struct vt_mode));
+ if (scp->smode.mode == VT_PROCESS) {
+ scp->proc = p;
+ scp->pid = scp->proc->p_pid;
+ }
+ return 0;
+
+ case VT_GETMODE: /* get screen switcher mode */
+ bcopy(&scp->smode, data, sizeof(struct vt_mode));
+ return 0;
+
+ case VT_RELDISP: /* screen switcher ioctl */
+ switch(*data) {
+ case VT_FALSE: /* user refuses to release screen, abort */
+ if (scp == old_scp && (scp->status & SWITCH_WAIT_REL)) {
+ old_scp->status &= ~SWITCH_WAIT_REL;
+ switch_in_progress = 0;
+ return 0;
+ }
+ return EINVAL;
+
+ case VT_TRUE: /* user has released screen, go on */
+ if (scp == old_scp && (scp->status & SWITCH_WAIT_REL)) {
+ scp->status &= ~SWITCH_WAIT_REL;
+ exchange_scr();
+ if (new_scp->smode.mode == VT_PROCESS) {
+ new_scp->status |= SWITCH_WAIT_ACQ;
+ psignal(new_scp->proc,
+ new_scp->smode.acqsig);
+ }
+ else
+ switch_in_progress = 0;
+ return 0;
+ }
+ return EINVAL;
+
+ case VT_ACKACQ: /* acquire acknowledged, switch completed */
+ if (scp == new_scp && (scp->status & SWITCH_WAIT_ACQ)) {
+ scp->status &= ~SWITCH_WAIT_ACQ;
+ switch_in_progress = 0;
+ return 0;
+ }
+ return EINVAL;
+
+ default:
+ return EINVAL;
+ }
+ /* NOT REACHED */
+
+ case VT_OPENQRY: /* return free virtual console */
+ for (i = 0; i < NCONS; i++) {
+ tp = VIRTUAL_TTY(i);
+ if (!(tp->t_state & TS_ISOPEN)) {
+ *data = i + 1;
+ return 0;
+ }
+ }
+ return EINVAL;
+
+ case VT_ACTIVATE: /* switch to screen *data */
+ return switch_scr((*data) - 1);
+
+ case VT_WAITACTIVE: /* wait for switch to occur */
+ if (*data > NCONS)
+ return EINVAL;
+ if (minor(dev) == (*data) - 1)
+ return 0;
+ if (*data == 0) {
+ if (scp == cur_console)
+ return 0;
+ while ((error=tsleep((caddr_t)&scp->smode,
+ PZERO|PCATCH, "waitvt", 0)) == ERESTART) ;
+ }
+ else
+ while ((error=tsleep(
+ (caddr_t)&console[*(data-1)].smode,
+ PZERO|PCATCH, "waitvt", 0)) == ERESTART) ;
+ return error;
+
+ case VT_GETACTIVE:
+ *data = get_scr_num()+1;
+ return 0;
+
+ case KDENABIO: /* allow io operations */
+ fp = (frametype *)p->p_md.md_regs;
+ fp->eflags |= PSL_IOPL;
+ return 0;
+
+ case KDDISABIO: /* disallow io operations (default) */
+ fp = (frametype *)p->p_md.md_regs;
+ fp->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_console)
+ set_border(scp->border);
+ return 0;
+
+ case KDSKBSTATE: /* set keyboard state (locks) */
+ if (*data >= 0 && *data <= LOCK_KEY_MASK) {
+ scp->status &= ~LOCK_KEY_MASK;
+ scp->status |= *data;
+ if (scp == cur_console)
+ update_leds(scp->status);
+ return 0;
+ }
+ return EINVAL;
+
+ case KDGKBSTATE: /* get keyboard state (locks) */
+ *data = scp->status & LOCK_KEY_MASK;
+ return 0;
+
+ case KDSETRAD: /* set keyboard repeat & delay rates */
+ if (*data & 0x80)
+ return EINVAL;
+ kbd_cmd2(KB_SETRAD, *data);
+ return 0;
+
+ case KDSKBMODE: /* set keyboard mode */
+ switch (*data) {
+ case K_RAW: /* switch to RAW scancode mode */
+ scp->status |= KBD_RAW_MODE;
+ return 0;
+
+ case K_XLATE: /* switch to XLT ascii mode */
+ if (scp == cur_console && scp->status == KBD_RAW_MODE)
+ shfts = ctls = alts = agrs = metas = 0;
+ scp->status &= ~KBD_RAW_MODE;
+ return 0;
+ default:
+ return EINVAL;
+ }
+ /* NOT REACHED */
+
+ case KDGKBMODE: /* get keyboard mode */
+ *data = (scp->status & KBD_RAW_MODE) ? K_RAW : K_XLATE;
+ return 0;
+
+ case KDMKTONE: /* sound the bell */
+ if (scp == cur_console)
+ sysbeep(scp->bell_pitch, scp->bell_duration);
+ return 0;
+
+ case KIOCSOUND: /* make tone (*data) hz */
+ if (scp == cur_console) {
+ if (*(int*)data) {
+ int pitch = TIMER_FREQ/(*(int*)data);
+ /* set command for counter 2, 2 byte write */
+ if (acquire_timer2(TIMER_16BIT|TIMER_SQWAVE)) {
+ return EBUSY;
+ }
+ /* set pitch */
+ outb(TIMER_CNTR2, pitch);
+ outb(TIMER_CNTR2, (pitch>>8));
+ /* enable counter 2 output to speaker */
+ outb(IO_PPI, inb(IO_PPI) | 3);
+ }
+ else {
+ /* disable counter 2 output to speaker */
+ outb(IO_PPI, inb(IO_PPI) & 0xFC);
+ release_timer2();
+ }
+ }
+ return 0;
+
+ case KDGKBTYPE: /* get keyboard type */
+ *data = 0; /* type not known (yet) */
+ return 0;
+
+ case KDSETLED: /* set keyboard LED status */
+ if (*data >= 0 && *data <= LED_MASK) {
+ scp->status &= ~LED_MASK;
+ scp->status |= *data;
+ if (scp == cur_console)
+ update_leds(scp->status);
+ return 0;
+ }
+ return EINVAL;
+
+ case KDGETLED: /* get keyboard LED status */
+ *data = scp->status & LED_MASK;
+ return 0;
+
+ case GETFKEY: /* get functionkey string */
+ if (*(u_short*)data < n_fkey_tab) {
+ fkeyarg_t *ptr = (fkeyarg_t*)data;
+ bcopy(&fkey_tab[ptr->keynum].str,
+ ptr->keydef,
+ fkey_tab[ptr->keynum].len);
+ ptr->flen = fkey_tab[ptr->keynum].len;
+ return 0;
+ }
+ else
+ return EINVAL;
+
+ case SETFKEY: /* set functionkey string */
+ if (*(u_short*)data < n_fkey_tab) {
+ fkeyarg_t *ptr = (fkeyarg_t*)data;
+ bcopy(ptr->keydef,
+ &fkey_tab[ptr->keynum].str,
+ min(ptr->flen, MAXFK));
+ fkey_tab[ptr->keynum].len = min(ptr->flen, MAXFK);
+ return 0;
+ }
+ else
+ return EINVAL;
+
+ case GIO_SCRNMAP: /* get output translation table */
+ bcopy(&scr_map, data, sizeof(scr_map));
+ return 0;
+
+ case PIO_SCRNMAP: /* set output translation table */
+ bcopy(data, &scr_map, sizeof(scr_map));
+ return 0;
+
+ case GIO_KEYMAP: /* get keyboard translation table */
+ bcopy(&key_map, data, sizeof(key_map));
+ return 0;
+
+ case PIO_KEYMAP: /* set keyboard translation table */
+ bcopy(data, &key_map, sizeof(key_map));
+ return 0;
+
+ case PIO_FONT8x8: /* set 8x8 dot font */
+ if (!crtc_vga)
+ return ENXIO;
+ bcopy(data, &font_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();
+ switch_scr(minor(dev));
+ fp = (frametype *)p->p_md.md_regs;
+ fp->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 = (frametype *)p->p_md.md_regs;
+ fp->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(TIMER_FREQ/((int*)data)[0],
+ ((int*)data)[1]*hz/3000);
+ else
+ sysbeep(scp->bell_pitch, scp->bell_duration);
+ return 0;
+
+ default:
+ break;
+ }
+
+ error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
+ if (error >= 0)
+ return(error);
+ error = ttioctl(tp, cmd, data, flag);
+ if (error >= 0)
+ return(error);
+ return(ENOTTY);
+}
+
+
+void pcxint(dev_t dev)
+{
+ struct tty *tp = get_tty_ptr(dev);
+
+ if (!tp)
+ return;
+ tp->t_state &= ~TS_BUSY;
+ if (tp->t_line)
+ (*linesw[tp->t_line].l_start)(tp);
+ else
+ pcstart(tp);
+}
+
+
+void pcstart(struct tty *tp)
+{
+#if defined(NetBSD) || defined(__FreeBSD__)
+ struct clist *rbp;
+ int i, s, len;
+ u_char buf[PCBURST];
+ scr_stat *scp = get_scr_stat(tp->t_dev);
+
+ if (scp->status & SLKED)
+ return;
+ s = spltty(); /* Isn't start always called at spltty? */
+ if (!(tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))) {
+ tp->t_state |= TS_BUSY;
+ splx(s);
+ rbp = &tp->t_outq;
+ while (rbp->c_cc) {
+ len = q_to_b(rbp, buf, PCBURST);
+ for (i=0; i<len; i++)
+ if (buf[i]) ansi_put(scp, buf[i]);
+ }
+ s = spltty();
+ tp->t_state &= ~TS_BUSY;
+#if 0
+ if (rbp->c_cc) {
+ tp->t_state |= TS_TIMEOUT;
+ timeout((timeout_t)ttrstrt, (caddr_t)tp, 1);
+ }
+#endif
+ if (rbp->c_cc <= tp->t_lowat) {
+ if (tp->t_state & TS_ASLEEP) {
+ tp->t_state &= ~TS_ASLEEP;
+ wakeup((caddr_t)rbp);
+ }
+ selwakeup(&tp->t_wsel);
+ }
+ }
+ splx(s);
+
+#else /* __386BSD__ */
+
+ int c, s, len, i;
+ scr_stat *scp = get_scr_stat(tp->t_dev);
+ u_char buf[PCBURST];
+
+ if (scp->status & SLKED)
+ return;
+ 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);
+ }
+ selwakeup(&tp->t_wsel);
+ }
+ if (RB_LEN(tp->t_out) == 0)
+ break;
+ if (scp->status & SLKED)
+ break;
+ len = 0;
+ while( len < PCBURST) {
+ buf[len++] = getc(tp->t_out);
+ if( RB_LEN(tp->t_out) == 0)
+ break;
+ }
+ tp->t_state |= TS_BUSY;
+ splx(s);
+ for(i=0;i<len;i++)
+ ansi_put(scp, buf[i]);
+ s = spltty();
+ tp->t_state &= ~TS_BUSY;
+ }
+ tp->t_state |= TS_BUSY;
+ if( in_putc == 0) {
+ int i;
+ for(i=0;i<console_buffer_count;i++) {
+ scput(console_buffer[i]);
+ }
+ console_buffer_count = 0;
+ }
+ tp->t_state &= ~TS_BUSY;
+ }
+ splx(s);
+#endif
+}
+
+
+void pccnprobe(struct consdev *cp)
+{
+ int maj;
+
+ /* locate the major number */
+ for (maj = 0; maj < nchrdev; maj++)
+ if ((void*)cdevsw[maj].d_open == (void*)pcopen)
+ break;
+
+ /* initialize required fields */
+ cp->cn_dev = makedev(maj, NCONS);
+ cp->cn_pri = CN_INTERNAL;
+#if defined(__386BSD__) && !defined(__FreeBSD__)
+ cp->cn_tp = CONSOLE_TTY;
+#endif
+}
+
+
+void pccninit(struct consdev *cp)
+{
+ scinit();
+}
+
+
+void pccnputc(dev_t dev, char c)
+{
+ if (c == '\n')
+ scput('\r');
+ scput(c);
+ if (cur_console == &console[0]) {
+ int pos = cur_console->crtat - cur_console->crt_base;
+ if (pos != cur_cursor_pos) {
+ cur_cursor_pos = pos;
+ outb(crtc_addr,14);
+ outb(crtc_addr+1,pos >> 8);
+ outb(crtc_addr,15);
+ outb(crtc_addr+1,pos&0xff);
+ }
+ }
+}
+
+
+int pccngetc(dev_t dev)
+{
+ int s = spltty(); /* block scintr while we poll */
+ int c = scgetc(0);
+ splx(s);
+ if (c == '\r') c = '\n';
+ return(c);
+}
+
+static void none_saver(int test)
+{
+}
+
+static void fade_saver(int test)
+{
+ static int count = 0;
+ int i;
+
+ if (test) {
+ scrn_blanked = 1;
+ if (count < 64) {
+ outb(PIXMASK, 0xFF); /* no pixelmask */
+ outb(PALWADR, 0x00);
+ outb(PALDATA, 0);
+ outb(PALDATA, 0);
+ outb(PALDATA, 0);
+ for (i = 3; i < 768; i++) {
+ if (palette[i] - count > 15)
+ outb(PALDATA, palette[i]-count);
+ else
+ outb(PALDATA, 15);
+ }
+ inb(crtc_addr+6); /* reset flip/flop */
+ outb(ATC, 0x20); /* enable palette */
+ count++;
+ }
+ }
+ else {
+ count = scrn_blanked = 0;
+ load_palette();
+ }
+}
+
+static void blank_saver(int test)
+{
+ u_char val;
+ if (test) {
+ scrn_blanked = 1;
+ outb(TSIDX, 0x01); val = inb(TSREG);
+ outb(TSIDX, 0x01); outb(TSREG, val | 0x20);
+ }
+ else {
+ scrn_blanked = 0;
+ outb(TSIDX, 0x01); val = inb(TSREG);
+ outb(TSIDX, 0x01); outb(TSREG, val & 0xDF);
+ }
+}
+
+static u_long rand_next = 1;
+
+static int rand()
+{
+ return ((rand_next = rand_next * 1103515245 + 12345) & 0x7FFFFFFF);
+}
+
+/*
+ * Alternate saver that got its inspiration from a well known utility
+ * package for an unfamous OS.
+ */
+
+#define NUM_STARS 50
+
+static void star_saver(int test)
+{
+ scr_stat *scp = cur_console;
+ int cell, i;
+ char pattern[] = {"...........++++*** "};
+ char colors[] = {FG_DARKGREY, FG_LIGHTGREY,
+ FG_WHITE, FG_LIGHTCYAN};
+ static u_short stars[NUM_STARS][2];
+
+ if (test) {
+ if (!scrn_blanked) {
+ bcopy(Crtat, scp->scr_buf,
+ scp->xsize * scp->ysize * 2);
+ fillw((FG_LIGHTGREY|BG_BLACK)<<8 | scr_map[0x20], Crtat,
+ scp->xsize * scp->ysize);
+ set_border(0);
+ i = scp->ysize * scp->xsize + 5;
+ outb(crtc_addr, 14);
+ outb(crtc_addr+1, i >> 8);
+ outb(crtc_addr, 15);
+ outb(crtc_addr+1, i & 0xff);
+ scrn_blanked = 1;
+ for(i=0; i<NUM_STARS; i++) {
+ stars[i][0] =
+ rand() % (scp->xsize*scp->ysize);
+ 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->xsize*scp->ysize);
+ stars[cell][1] = 0;
+ }
+ }
+ else {
+ if (scrn_blanked) {
+ bcopy(scp->scr_buf, Crtat, scp->xsize*scp->ysize*2);
+ cur_cursor_pos = -1;
+ set_border(scp->border);
+ scrn_blanked = 0;
+ }
+ }
+}
+
+
+static void snake_saver(int test)
+{
+ const char saves[] = {"FreeBSD"};
+ static u_char *savs[sizeof(saves)-1];
+ static int dirx, diry;
+ int f;
+ scr_stat *scp = cur_console;
+
+ if (test) {
+ if (!scrn_blanked) {
+ bcopy(Crtat, scp->scr_buf,
+ scp->xsize * scp->ysize * 2);
+ fillw((FG_LIGHTGREY|BG_BLACK)<<8 | scr_map[0x20],
+ Crtat, scp->xsize * scp->ysize);
+ set_border(0);
+ dirx = (scp->xpos ? 1 : -1);
+ diry = (scp->ypos ?
+ scp->xsize : -scp->xsize);
+ for (f=0; f< sizeof(saves)-1; f++)
+ savs[f] = (u_char *)Crtat + 2 *
+ (scp->xpos+scp->ypos*scp->xsize);
+ *(savs[0]) = scr_map[*saves];
+ f = scp->ysize * scp->xsize + 5;
+ outb(crtc_addr, 14);
+ outb(crtc_addr+1, f >> 8);
+ outb(crtc_addr, 15);
+ outb(crtc_addr+1, f & 0xff);
+ scrn_blanked = 1;
+ }
+ if (scrn_blanked++ < 4)
+ return;
+ scrn_blanked = 1;
+ *(savs[sizeof(saves)-2]) = scr_map[0x20];
+ for (f=sizeof(saves)-2; f > 0; f--)
+ savs[f] = savs[f-1];
+ f = (savs[0] - (u_char *)Crtat) / 2;
+ if ((f % scp->xsize) == 0 ||
+ (f % scp->xsize) == scp->xsize - 1 ||
+ (rand() % 50) == 0)
+ dirx = -dirx;
+ if ((f / scp->xsize) == 0 ||
+ (f / scp->xsize) == scp->ysize - 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_buf, Crtat,
+ scp->xsize * scp->ysize * 2);
+ cur_cursor_pos = -1;
+ set_border(scp->border);
+ scrn_blanked = 0;
+ }
+ }
+}
+
+static void cursor_shape(int start, int end)
+{
+ outb(crtc_addr, 10);
+ outb(crtc_addr+1, start & 0xFF);
+ outb(crtc_addr, 11);
+ outb(crtc_addr+1, end & 0xFF);
+}
+
+
+#if !defined(FAT_CURSOR)
+static void get_cursor_shape(int *start, int *end)
+{
+ outb(crtc_addr, 10);
+ *start = inb(crtc_addr+1) & 0x1F;
+ outb(crtc_addr, 11);
+ *end = inb(crtc_addr+1) & 0x1F;
+}
+#endif
+
+
+static void cursor_pos(int force)
+{
+ int pos;
+
+ if (cur_console->status & UNKNOWN_MODE)
+ return;
+ if (scrn_blank_time && (time.tv_sec > scrn_time_stamp+scrn_blank_time))
+ SCRN_SAVER(1);
+ pos = cur_console->crtat - cur_console->crt_base;
+ if (force || (!scrn_blanked && pos != cur_cursor_pos)) {
+ cur_cursor_pos = pos;
+ outb(crtc_addr, 14);
+ outb(crtc_addr+1, pos>>8);
+ outb(crtc_addr, 15);
+ outb(crtc_addr+1, pos&0xff);
+ }
+ timeout((timeout_t)cursor_pos, 0, hz/20);
+}
+
+
+static void clear_screen(scr_stat *scp)
+{
+ move_crsr(scp, 0, 0);
+ fillw(scp->term.cur_attr | scr_map[0x20], scp->crt_base,
+ scp->xsize * scp->ysize);
+}
+
+
+static int switch_scr(u_int next_scr)
+{
+ if (in_putc) { /* delay switch if in putc */
+ delayed_next_scr = next_scr+1;
+ return 0;
+ }
+ if (switch_in_progress &&
+ (cur_console->proc != pfind(cur_console->pid)))
+ switch_in_progress = 0;
+
+ if (next_scr >= NCONS || switch_in_progress) {
+ sysbeep(BELL_PITCH, BELL_DURATION);
+ return EINVAL;
+ }
+
+ /* is the wanted virtual console open ? */
+ if (next_scr) {
+ struct tty *tp = VIRTUAL_TTY(next_scr);
+ if (!(tp->t_state & TS_ISOPEN)) {
+ sysbeep(BELL_PITCH, BELL_DURATION);
+ return EINVAL;
+ }
+ }
+
+ switch_in_progress = 1;
+ old_scp = cur_console;
+ new_scp = &console[next_scr];
+ wakeup((caddr_t)&new_scp->smode);
+ if (new_scp == old_scp) {
+ switch_in_progress = 0;
+ return 0;
+ }
+
+ /* has controlling process died? */
+ if (old_scp->proc && (old_scp->proc != pfind(old_scp->pid)))
+ old_scp->smode.mode = VT_AUTO;
+ if (new_scp->proc && (new_scp->proc != pfind(new_scp->pid)))
+ new_scp->smode.mode = VT_AUTO;
+
+ /* check the modes and switch approbiatly */
+ if (old_scp->smode.mode == VT_PROCESS) {
+ old_scp->status |= SWITCH_WAIT_REL;
+ psignal(old_scp->proc, old_scp->smode.relsig);
+ }
+ else {
+ exchange_scr();
+ if (new_scp->smode.mode == VT_PROCESS) {
+ new_scp->status |= SWITCH_WAIT_ACQ;
+ psignal(new_scp->proc, new_scp->smode.acqsig);
+ }
+ else
+ switch_in_progress = 0;
+ }
+ return 0;
+}
+
+
+static void exchange_scr(void)
+{
+ struct tty *tp;
+
+ bcopy(Crtat, old_scp->scr_buf, old_scp->xsize * old_scp->ysize * 2);
+ old_scp->crt_base = old_scp->scr_buf;
+ move_crsr(old_scp, old_scp->xpos, old_scp->ypos);
+ cur_console = new_scp;
+ set_mode(new_scp);
+ new_scp->crt_base = Crtat;
+ move_crsr(new_scp, new_scp->xpos, new_scp->ypos);
+ bcopy(new_scp->scr_buf, Crtat, new_scp->xsize * new_scp->ysize * 2);
+ update_leds(new_scp->status);
+ if ((old_scp->status & UNKNOWN_MODE) && crtc_vga) {
+ load_font(0, 16, font_8x16);
+ load_font(1, 8, font_8x8);
+ load_font(2, 14, font_8x14);
+ load_palette();
+ }
+ if (old_scp->status & KBD_RAW_MODE || new_scp->status & KBD_RAW_MODE)
+ shfts = ctls = alts = agrs = metas = 0;
+ delayed_next_scr = 0;
+}
+
+
+static void move_crsr(scr_stat *scp, int x, int y)
+{
+ if (x < 0 || y < 0 || x >= scp->xsize || y >= scp->ysize)
+ return;
+ scp->xpos = x;
+ scp->ypos = y;
+ scp->crtat = scp->crt_base + scp->ypos * scp->xsize + scp->xpos;
+}
+
+static void move_up(u_short *s, u_short *d, u_int len)
+{
+ s += len;
+ d += len;
+ while (len-- > 0)
+ *--d = *--s;
+}
+
+static void move_down(u_short *s, u_short *d, u_int len)
+{
+ while (len-- > 0)
+ *d++ = *s++;
+}
+
+static void scan_esc(scr_stat *scp, u_char c)
+{
+ static u_char ansi_col[16] =
+ {0, 4, 2, 6, 1, 5, 3, 7, 8, 12, 10, 14, 9, 13, 11, 15};
+ int i, n;
+ u_short *src, *dst, count;
+
+ if (scp->term.esc == 1) {
+ switch (c) {
+
+ case '[': /* Start ESC [ sequence */
+ scp->term.esc = 2;
+ scp->term.last_param = -1;
+ for (i = scp->term.num_param; i < MAX_ESC_PAR; i++)
+ scp->term.param[i] = 1;
+ scp->term.num_param = 0;
+ return;
+
+ case 'M': /* Move cursor up 1 line, scroll if at top */
+ if (scp->ypos > 0)
+ move_crsr(scp, scp->xpos, scp->ypos - 1);
+ else {
+ move_up(scp->crt_base,
+ scp->crt_base + scp->xsize,
+ (scp->ysize - 1) * scp->xsize);
+ fillw(scp->term.cur_attr | scr_map[0x20],
+ scp->crt_base, scp->xsize);
+ }
+ break;
+#if notyet
+ case 'Q':
+ scp->term.esc = 4;
+ break;
+#endif
+ case 'c': /* Clear screen & home */
+ clear_screen(scp);
+ break;
+ }
+ }
+ else if (scp->term.esc == 2) {
+ if (c >= '0' && c <= '9') {
+ if (scp->term.num_param < MAX_ESC_PAR) {
+ if (scp->term.last_param != scp->term.num_param) {
+ scp->term.last_param = scp->term.num_param;
+ scp->term.param[scp->term.num_param] = 0;
+ }
+ else
+ scp->term.param[scp->term.num_param] *= 10;
+ scp->term.param[scp->term.num_param] += c - '0';
+ return;
+ }
+ }
+ scp->term.num_param = scp->term.last_param + 1;
+ switch (c) {
+
+ case ';':
+ if (scp->term.num_param < MAX_ESC_PAR)
+ return;
+ break;
+
+ case '=':
+ scp->term.esc = 3;
+ scp->term.last_param = -1;
+ for (i = scp->term.num_param; i < MAX_ESC_PAR; i++)
+ scp->term.param[i] = 1;
+ scp->term.num_param = 0;
+ return;
+
+ case 'A': /* up n rows */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ move_crsr(scp, scp->xpos, scp->ypos - n);
+ break;
+
+ case 'B': /* down n rows */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ move_crsr(scp, scp->xpos, scp->ypos + n);
+ break;
+
+ case 'C': /* right n columns */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ move_crsr(scp, scp->xpos + n, scp->ypos);
+ break;
+
+ case 'D': /* left n columns */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ move_crsr(scp, scp->xpos - n, scp->ypos);
+ break;
+
+ case 'E': /* cursor to start of line n lines down */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ move_crsr(scp, 0, scp->ypos + n);
+ break;
+
+ case 'F': /* cursor to start of line n lines up */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ move_crsr(scp, 0, scp->ypos - n);
+ break;
+
+ case 'f': /* System V consoles .. */
+ case 'H': /* Cursor move */
+ if (scp->term.num_param == 0)
+ move_crsr(scp, 0, 0);
+ else if (scp->term.num_param == 2)
+ move_crsr(scp, scp->term.param[1] - 1,
+ scp->term.param[0] - 1);
+ break;
+
+ case 'J': /* Clear all or part of display */
+ if (scp->term.num_param == 0)
+ n = 0;
+ else
+ n = scp->term.param[0];
+ switch (n) {
+ case 0: /* clear form cursor to end of display */
+ fillw(scp->term.cur_attr | scr_map[0x20],
+ scp->crtat, scp->crt_base +
+ scp->xsize * scp->ysize -
+ scp->crtat);
+ break;
+ case 1: /* clear from beginning of display to cursor */
+ fillw(scp->term.cur_attr | scr_map[0x20],
+ scp->crt_base,
+ scp->crtat - scp->crt_base);
+ break;
+ case 2: /* clear entire display */
+ clear_screen(scp);
+ break;
+ }
+ break;
+
+ case 'K': /* Clear all or part of line */
+ if (scp->term.num_param == 0)
+ n = 0;
+ else
+ n = scp->term.param[0];
+ switch (n) {
+ case 0: /* clear form cursor to end of line */
+ fillw(scp->term.cur_attr | scr_map[0x20],
+ scp->crtat, scp->xsize - scp->xpos);
+ break;
+ case 1: /* clear from beginning of line to cursor */
+ fillw(scp->term.cur_attr|scr_map[0x20],
+ scp->crtat - (scp->xsize - scp->xpos),
+ (scp->xsize - scp->xpos) + 1);
+ break;
+ case 2: /* clear entire line */
+ fillw(scp->term.cur_attr|scr_map[0x20],
+ scp->crtat - (scp->xsize - scp->xpos),
+ scp->xsize);
+ break;
+ }
+ break;
+
+ case 'L': /* Insert n lines */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ if (n > scp->ysize - scp->ypos)
+ n = scp->ysize - scp->ypos;
+ src = scp->crt_base + scp->ypos * scp->xsize;
+ dst = src + n * scp->xsize;
+ count = scp->ysize - (scp->ypos + n);
+ move_up(src, dst, count * scp->xsize);
+ fillw(scp->term.cur_attr | scr_map[0x20], src,
+ n * scp->xsize);
+ break;
+
+ case 'M': /* Delete n lines */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ if (n > scp->ysize - scp->ypos)
+ n = scp->ysize - scp->ypos;
+ dst = scp->crt_base + scp->ypos * scp->xsize;
+ src = dst + n * scp->xsize;
+ count = scp->ysize - (scp->ypos + n);
+ move_down(src, dst, count * scp->xsize);
+ src = dst + count * scp->xsize;
+ fillw(scp->term.cur_attr | scr_map[0x20], src,
+ n * scp->xsize);
+ break;
+
+ case 'P': /* Delete n chars */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ if (n > scp->xsize - scp->xpos)
+ n = scp->xsize - scp->xpos;
+ dst = scp->crtat;
+ src = dst + n;
+ count = scp->xsize - (scp->xpos + n);
+ move_down(src, dst, count);
+ src = dst + count;
+ fillw(scp->term.cur_attr | scr_map[0x20], src, n);
+ break;
+
+ case '@': /* Insert n chars */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ if (n > scp->xsize - scp->xpos)
+ n = scp->xsize - scp->xpos;
+ src = scp->crtat;
+ dst = src + n;
+ count = scp->xsize - (scp->xpos + n);
+ move_up(src, dst, count);
+ fillw(scp->term.cur_attr | scr_map[0x20], src, n);
+ break;
+
+ case 'S': /* scroll up n lines */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ if (n > scp->ypos)
+ n = scp->ypos;
+ bcopy(scp->crt_base + (scp->xsize * n),
+ scp->crt_base,
+ scp->xsize * (scp->ysize - n) *
+ sizeof(u_short));
+ fillw(scp->term.cur_attr | scr_map[0x20],
+ scp->crt_base + scp->xsize *
+ (scp->ysize - 1),
+ scp->xsize);
+ break;
+
+ case 'T': /* scroll down n lines */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ if (n > scp->ysize - scp->ypos)
+ n = scp->ysize - scp->ypos;
+ bcopy(scp->crt_base,
+ scp->crt_base + (scp->xsize * n),
+ scp->xsize * (scp->ysize - n) *
+ sizeof(u_short));
+ fillw(scp->term.cur_attr | scr_map[0x20],
+ scp->crt_base, scp->xsize);
+ break;
+
+ case 'X': /* delete n characters in line */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ if (n > scp->xsize - scp->xpos)
+ n = scp->xsize - scp->xpos;
+ fillw(scp->term.cur_attr | scr_map[0x20],
+ scp->crt_base + scp->xpos +
+ ((scp->xsize*scp->ypos) * sizeof(u_short)), n);
+ break;
+
+ case 'Z': /* move n tabs backwards */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ if ((i = scp->xpos & 0xf8) == scp->xpos)
+ i -= 8*n;
+ else
+ i -= 8*(n-1);
+ if (i < 0)
+ i = 0;
+ move_crsr(scp, i, scp->ypos);
+ break;
+
+ case '`': /* move cursor to column n */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ move_crsr(scp, n, scp->ypos);
+ break;
+
+ case 'a': /* move cursor n columns to the right */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ move_crsr(scp, scp->xpos + n, scp->ypos);
+ break;
+
+ case 'd': /* move cursor to row n */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ move_crsr(scp, scp->xpos, n);
+ break;
+
+ case 'e': /* move cursor n rows down */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ move_crsr(scp, scp->xpos, scp->ypos + n);
+ break;
+
+ case 'm': /* change attribute */
+ if (scp->term.num_param == 0)
+ n = 0;
+ else
+ n = scp->term.param[0];
+ switch (n) {
+ case 0: /* back to normal */
+ scp->term.cur_attr = scp->term.std_attr;
+ break;
+ case 1: /* highlight (bold) */
+ scp->term.cur_attr &= 0xFF00;
+ scp->term.cur_attr |= 0x0800;
+ break;
+ case 4: /* highlight (underline) */
+ scp->term.cur_attr &= 0x0F00;
+ scp->term.cur_attr |= 0x0800;
+ break;
+ case 5: /* blink */
+ scp->term.cur_attr &= 0xFF00;
+ scp->term.cur_attr |= 0x8000;
+ break;
+ case 7: /* reverse video */
+ scp->term.cur_attr = scp->term.rev_attr;
+ break;
+ case 30: case 31: case 32: case 33: /* set fg color */
+ case 34: case 35: case 36: case 37:
+ scp->term.cur_attr = (scp->term.cur_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.cur_attr = (scp->term.cur_attr & 0x0FFF)
+ | (ansi_col[(n - 40) & 7] << 12);
+ break;
+ }
+ break;
+
+ case 'x':
+ if (scp->term.num_param == 0)
+ n = 0;
+ else
+ n = scp->term.param[0];
+ switch (n) {
+ case 0: /* reset attributes */
+ scp->term.cur_attr = scp->term.std_attr =
+ current_default->std_attr;
+ scp->term.rev_attr = current_default->rev_attr;
+ break;
+ case 1: /* set ansi background */
+ scp->term.cur_attr = scp->term.std_attr =
+ (scp->term.std_attr & 0x0F00) |
+ (ansi_col[(scp->term.param[1])&0x0F]<<12);
+ break;
+ case 2: /* set ansi foreground */
+ scp->term.cur_attr = scp->term.std_attr =
+ (scp->term.std_attr & 0xF000) |
+ (ansi_col[(scp->term.param[1])&0x0F]<<8);
+ break;
+ case 3: /* set ansi attribute directly */
+ scp->term.cur_attr = scp->term.std_attr =
+ (scp->term.param[1]&0xFF)<<8;
+ break;
+ case 5: /* set ansi reverse video background */
+ scp->term.rev_attr =
+ (scp->term.rev_attr & 0x0F00) |
+ (ansi_col[(scp->term.param[1])&0x0F]<<12);
+ break;
+ case 6: /* set ansi reverse video foreground */
+ scp->term.rev_attr =
+ (scp->term.rev_attr & 0xF000) |
+ (ansi_col[(scp->term.param[1])&0x0F]<<8);
+ break;
+ case 7: /* set ansi reverse video directly */
+ scp->term.rev_attr = (scp->term.param[1]&0xFF)<<8;
+ break;
+ }
+ break;
+
+ case 'z': /* switch to (virtual) console n */
+ if (scp->term.num_param == 1)
+ switch_scr(scp->term.param[0]);
+ break;
+ }
+ }
+ else if (scp->term.esc == 3) {
+ if (c >= '0' && c <= '9') {
+ if (scp->term.num_param < MAX_ESC_PAR) {
+ if (scp->term.last_param != scp->term.num_param) {
+ scp->term.last_param = scp->term.num_param;
+ scp->term.param[scp->term.num_param] = 0;
+ }
+ else
+ scp->term.param[scp->term.num_param] *= 10;
+ scp->term.param[scp->term.num_param] += c - '0';
+ return;
+ }
+ }
+ scp->term.num_param = scp->term.last_param + 1;
+ switch (c) {
+
+ case ';':
+ if (scp->term.num_param < MAX_ESC_PAR)
+ return;
+ break;
+
+ case 'A': /* set display border color */
+ if (scp->term.num_param == 1)
+ scp->border=scp->term.param[0] & 0xff;
+ if (scp == cur_console)
+ set_border(scp->border);
+ break;
+
+ case 'B': /* set bell pitch and duration */
+ if (scp->term.num_param == 2) {
+ scp->bell_pitch = scp->term.param[0];
+ scp->bell_duration = scp->term.param[1]*10;
+ }
+ break;
+
+ case 'C': /* set cursor shape (start & end line) */
+ if (scp->term.num_param == 2) {
+ scp->cursor_start = scp->term.param[0] & 0x1F;
+ scp->cursor_end = scp->term.param[1] & 0x1F;
+ if (scp == cur_console)
+ cursor_shape(scp->cursor_start,
+ scp->cursor_end);
+ }
+ break;
+
+ case 'F': /* set ansi foreground */
+ if (scp->term.num_param == 1)
+ scp->term.cur_attr = scp->term.std_attr =
+ (scp->term.std_attr & 0xF000)
+ | ((scp->term.param[0] & 0x0F) << 8);
+ break;
+
+ case 'G': /* set ansi background */
+ if (scp->term.num_param == 1)
+ scp->term.cur_attr = scp->term.std_attr =
+ (scp->term.std_attr & 0x0F00)
+ | ((scp->term.param[0] & 0x0F) << 12);
+ break;
+
+ case 'H': /* set ansi reverse video foreground */
+ if (scp->term.num_param == 1)
+ scp->term.rev_attr =
+ (scp->term.rev_attr & 0xF000)
+ | ((scp->term.param[0] & 0x0F) << 8);
+ break;
+
+ case 'I': /* set ansi reverse video background */
+ if (scp->term.num_param == 1)
+ scp->term.rev_attr =
+ (scp->term.rev_attr & 0x0F00)
+ | ((scp->term.param[0] & 0x0F) << 12);
+ break;
+ }
+ }
+ scp->term.esc = 0;
+}
+
+
+static void ansi_put(scr_stat *scp, u_char c)
+{
+ if (scp->status & UNKNOWN_MODE)
+ return;
+
+ /* make screensaver happy */
+ if (scp == cur_console) {
+ scrn_time_stamp = time.tv_sec;
+ if (scrn_blanked)
+ SCRN_SAVER(0);
+ }
+ in_putc++;
+ if (scp->term.esc)
+ scan_esc(scp, c);
+ else switch(c) {
+ case 0x1B: /* start escape sequence */
+ scp->term.esc = 1;
+ scp->term.num_param = 0;
+ break;
+ case 0x07:
+ if (scp == cur_console)
+ sysbeep(scp->bell_pitch, scp->bell_duration);
+ break;
+ case '\t': /* non-destructive tab */
+ scp->crtat += (8 - scp->xpos % 8);
+ scp->xpos += (8 - scp->xpos % 8);
+ break;
+ case '\b': /* non-destructive backspace */
+ if (scp->crtat > scp->crt_base) {
+ scp->crtat--;
+ if (scp->xpos > 0)
+ scp->xpos--;
+ else {
+ scp->xpos += scp->xsize - 1;
+ scp->ypos--;
+ }
+ }
+ break;
+ case '\r': /* return to pos 0 */
+ move_crsr(scp, 0, scp->ypos);
+ break;
+ case '\n': /* newline, same pos */
+ scp->crtat += scp->xsize;
+ scp->ypos++;
+ break;
+ case '\f': /* form feed, clears screen */
+ clear_screen(scp);
+ break;
+ default:
+ /* Print only printables */
+ *scp->crtat = (scp->term.cur_attr | scr_map[c]);
+ scp->crtat++;
+ if (++scp->xpos >= scp->xsize) {
+ scp->xpos = 0;
+ scp->ypos++;
+ }
+ break;
+ }
+ if (scp->crtat >= scp->crt_base + scp->ysize * scp->xsize) {
+ bcopy(scp->crt_base + scp->xsize, scp->crt_base,
+ scp->xsize * (scp->ysize - 1) * sizeof(u_short));
+ fillw(scp->term.cur_attr | scr_map[0x20],
+ scp->crt_base + scp->xsize * (scp->ysize - 1),
+ scp->xsize);
+ scp->crtat -= scp->xsize;
+ scp->ypos--;
+ }
+ in_putc--;
+ if (delayed_next_scr)
+ switch_scr(delayed_next_scr - 1);
+}
+
+static void scinit(void)
+{
+ u_short volatile *cp = Crtat + (CGA_BUF-MONO_BUF)/sizeof(u_short), was;
+ unsigned cursorat;
+ int i;
+
+ /*
+ * catch that once in a blue moon occurence when scinit is called
+ * TWICE, adding the CGA_BUF offset again -> poooff
+ */
+ if (crtat != 0)
+ return;
+ /*
+ * Crtat initialized to point to MONO buffer, if not present change
+ * to CGA_BUF offset. ONLY ADD the difference since locore.s adds
+ * in the remapped offset at the "right" time
+ */
+ was = *cp;
+ *cp = (u_short) 0xA55A;
+ if (*cp != 0xA55A) {
+ crtc_addr = MONO_BASE;
+ } else {
+ *cp = was;
+ crtc_addr = COLOR_BASE;
+ Crtat = Crtat + (CGA_BUF-MONO_BUF)/sizeof(u_short);
+ }
+
+ /* Extract cursor location */
+ outb(crtc_addr,14);
+ cursorat = inb(crtc_addr+1)<<8 ;
+ outb(crtc_addr,15);
+ cursorat |= inb(crtc_addr+1);
+ crtat = Crtat + cursorat;
+
+ /* is this a VGA or higher ? */
+ outb(crtc_addr, 7);
+ if (inb(crtc_addr) == 7)
+ crtc_vga = 1;
+
+ current_default = &user_default;
+ console[0].crtat = crtat;
+ console[0].crt_base = Crtat;
+ console[0].term.esc = 0;
+ console[0].term.std_attr = current_default->std_attr;
+ console[0].term.rev_attr = current_default->rev_attr;
+ console[0].term.cur_attr = current_default->std_attr;
+ console[0].xpos = cursorat % COL;
+ console[0].ypos = cursorat / COL;
+ console[0].border = BG_BLACK;;
+ console[0].xsize = COL;
+ console[0].ysize = ROW;
+ console[0].status = 0;
+ console[0].pid = 0;
+ console[0].proc = NULL;
+ console[0].smode.mode = VT_AUTO;
+ console[0].bell_pitch = BELL_PITCH;
+ console[0].bell_duration = BELL_DURATION;
+ kernel_console.esc = 0;
+ kernel_console.std_attr = kernel_default.std_attr;
+ kernel_console.rev_attr = kernel_default.rev_attr;
+ kernel_console.cur_attr = kernel_default.std_attr;
+ /* initialize mapscrn array to a one to one map */
+ for (i=0; i<sizeof(scr_map); i++)
+ scr_map[i] = i;
+ clear_screen(&console[0]);
+}
+
+
+static void scput(u_char c)
+{
+ scr_stat *scp = &console[0];
+ term_stat save;
+
+ if (crtat == 0)
+ scinit();
+ if( in_putc == 0) {
+ ++in_putc;
+ save = scp->term;
+ scp->term = kernel_console;
+ current_default = &kernel_default;
+ ansi_put(scp, c);
+ kernel_console = scp->term;
+ current_default = &user_default;
+ scp->term = save;
+ --in_putc;
+ } else {
+ if( console_buffer_count < CONSOLE_BUFFER_SIZE)
+ console_buffer[console_buffer_count++] = c;
+ }
+}
+
+
+static u_char *get_fstr(u_int c, u_int *len)
+{
+ u_int i;
+
+ if (!(c & FKEY))
+ return(NULL);
+ i = (c & 0xFF) - F_FN;
+ if (i > n_fkey_tab)
+ return(NULL);
+ *len = fkey_tab[i].len;
+ return(fkey_tab[i].str);
+}
+
+
+static void update_leds(int which)
+{
+ static u_char xlate_leds[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
+
+ /* replace CAPS led with ALTGR led for ALTGR keyboards */
+ if (key_map.n_keys > ALTGR_OFFSET) {
+ if (which & ALKED)
+ which |= CLKED;
+ else
+ which &= ~CLKED;
+ }
+ kbd_cmd2(KB_SETLEDS, xlate_leds[which & LED_MASK]);
+}
+
+
+/*
+ * scgetc(noblock) : get a character from the keyboard.
+ * If noblock = 0 wait until a key is gotten. Otherwise return NOKEY.
+ */
+u_int scgetc(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(NOKEY);
+ else
+ goto next_code;
+
+ if (cur_console->status & KBD_RAW_MODE)
+ return val;
+
+ code = val & 0x7F;
+ release = val & 0x80;
+
+ switch (esc_flag) {
+ case 0x00: /* normal scancode */
+ switch(code) {
+ case 0x38: /* left alt (compose key) */
+ if (release && compose) {
+ compose = 0;
+ if (chr > 255) {
+ sysbeep(BELL_PITCH, BELL_DURATION);
+ 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(BELL_PITCH, BELL_DURATION);
+ goto next_code;
+ }
+ break;
+ }
+ }
+
+ state = (shfts ? 1 : 0 ) | (2 * (ctls ? 1 : 0)) | (4 * (alts ? 1 : 0));
+ if ((!agrs && (cur_console->status & ALKED))
+ || (agrs && !(cur_console->status & ALKED)))
+ code += ALTGR_OFFSET;
+ key = &key_map.key[code];
+ if ( ((key->flgs & FLAG_LOCK_C) && (cur_console->status & CLKED))
+ || ((key->flgs & FLAG_LOCK_N) && (cur_console->status & NLKED)) )
+ state ^= 1;
+
+ /* Check for make/break */
+ action = key->map[state];
+ if (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;
+ case META:
+ metas = 0;
+ break;
+ }
+ }
+ if (chr && !compose) {
+ action = chr;
+ chr = 0;
+ return(action);
+ }
+ } else {
+ /* key pressed */
+ if (key->spcl & (0x80>>state)) {
+ switch (action) {
+ /* LOCKING KEYS */
+ case NLK:
+ if (!nlkcnt) {
+ nlkcnt++;
+ if (cur_console->status & NLKED)
+ cur_console->status &= ~NLKED;
+ else
+ cur_console->status |= NLKED;
+ update_leds(cur_console->status);
+ }
+ break;
+ case CLK:
+ if (!clkcnt) {
+ clkcnt++;
+ if (cur_console->status & CLKED)
+ cur_console->status &= ~CLKED;
+ else
+ cur_console->status |= CLKED;
+ update_leds(cur_console->status);
+ }
+ break;
+ case SLK:
+ if (!slkcnt) {
+ slkcnt++;
+ if (cur_console->status & SLKED) {
+ cur_console->status &= ~SLKED;
+ pcstart(VIRTUAL_TTY(get_scr_num()));
+ }
+ else
+ cur_console->status |= SLKED;
+ update_leds(cur_console->status);
+ }
+ break;
+ case ALK:
+ if (!alkcnt) {
+ alkcnt++;
+ if (cur_console->status & ALKED)
+ cur_console->status &= ~ALKED;
+ else
+ cur_console->status |= ALKED;
+ update_leds(cur_console->status);
+ }
+ break;
+
+ /* NON-LOCKING KEYS */
+ case NOP:
+ break;
+ case RBT:
+#if defined(__FreeBSD__)
+ shutdown_nice();
+#else
+ cpu_reset();
+#endif
+ break;
+ case DBG:
+#if DDB > 0 /* try to switch to console 0 */
+ if (cur_console->smode.mode == VT_AUTO &&
+ console[0].smode.mode == VT_AUTO)
+ switch_scr(0);
+ Debugger("manual escape to debugger");
+ return(NOKEY);
+#else
+ printf("No debugger in kernel\n");
+#endif
+ break;
+ case LSH:
+ shfts |= 1;
+ break;
+ case RSH:
+ shfts |= 2;
+ break;
+ case LCTR:
+ ctls |= 1;
+ break;
+ case RCTR:
+ ctls |= 2;
+ break;
+ case LALT:
+ alts |= 1;
+ break;
+ case RALT:
+ alts |= 2;
+ break;
+ case ASH:
+ agrs = 1;
+ break;
+ case META:
+ metas = 1;
+ break;
+ case NEXT:
+ switch_scr((get_scr_num()+1)%NCONS);
+ break;
+ default:
+ if (action >= F_SCR && action <= L_SCR) {
+ switch_scr(action - F_SCR);
+ break;
+ }
+ if (action >= F_FN && action <= L_FN)
+ action |= FKEY;
+ return(action);
+ }
+ }
+ else {
+ if (metas)
+ action |= MKEY;
+ return(action);
+ }
+ }
+ goto next_code;
+}
+
+
+int getchar(void)
+{
+ u_char thechar;
+ int s;
+
+ polling = 1;
+ s = splhigh();
+ scput('>');
+ thechar = (u_char) scgetc(0);
+ polling = 0;
+ splx(s);
+ switch (thechar) {
+ default:
+ if (thechar >= scr_map[0x20])
+ scput(thechar);
+ return(thechar);
+ case cr:
+ case lf:
+ scput(cr); scput(lf);
+ return(lf);
+ case bs:
+ case del:
+ scput(bs); scput(scr_map[0x20]); scput(bs);
+ return(thechar);
+ case cntld:
+ scput('^'); scput('D'); scput('\r'); scput('\n');
+ return(0);
+ }
+}
+
+
+u_int sgetc(int noblock)
+{
+ return (scgetc(noblock) & 0xff);
+}
+
+int pcmmap(dev_t dev, int offset, int nprot)
+{
+ if (offset > 0x20000)
+ return EINVAL;
+ return i386_btop((VIDEOMEM + offset));
+}
+
+
+static void kbd_wait(void)
+{
+ int i;
+
+ for (i=0; i<1000; i++) { /* up to 10 msec */
+ if ((inb(KB_STAT) & KB_READY) == 0)
+ break;
+ DELAY (10);
+ }
+}
+
+
+static void kbd_cmd(u_char command)
+{
+ kbd_wait();
+ outb(KB_DATA, command);
+}
+
+
+static void kbd_cmd2(u_char command, u_char arg)
+{
+ int r, s = spltty();
+ do {
+ kbd_cmd(command);
+ r = kbd_reply();
+ if (r == KB_ACK) {
+ kbd_cmd(arg & 0x7f);
+ r = kbd_reply();
+ }
+ } while (r != KB_ACK);
+ splx(s);
+}
+
+
+static int kbd_reply()
+{
+ int i;
+
+ kbd_wait();
+ for (i=0; i<60000; i++) { /* at least 300 msec, 600 msec enough */
+ if (inb(KB_STAT) & KB_BUF_FULL)
+ return ((u_char) inb(KB_DATA));
+ DELAY (10);
+ }
+ return(-1);
+}
+
+
+static void set_mode(scr_stat *scp)
+{
+ u_char byte;
+ int s;
+
+ if (scp != cur_console)
+ return;
+
+ /* (re)activate cursor */
+ untimeout((timeout_t)cursor_pos, 0);
+ cursor_pos(1);
+
+ /* change cursor type if set */
+ if (scp->cursor_start != -1 && scp->cursor_end != -1)
+ cursor_shape(scp->cursor_start, scp->cursor_end);
+
+ /* mode change only on VGA's */
+ if (!crtc_vga)
+ return;
+
+ /* setup video hardware for the given mode */
+ s = splhigh();
+ switch(scp->mode) {
+ case TEXT80x25:
+ outb(crtc_addr, 9); byte = inb(crtc_addr+1);
+ outb(crtc_addr, 9); outb(crtc_addr+1, byte | 0x0F);
+ outb(TSIDX, 0x03); outb(TSREG, 0x00); /* select font 0 */
+ break;
+ case TEXT80x50:
+ outb(crtc_addr, 9); byte = inb(crtc_addr+1);
+ outb(crtc_addr, 9); outb(crtc_addr+1, (byte & 0xF0) | 0x07);
+ outb(TSIDX, 0x03); outb(TSREG, 0x05); /* select font 1 */
+ break;
+ default:
+ break;
+ }
+ splx(s);
+
+ /* set border color for this (virtual) console */
+ set_border(scp->border);
+ return;
+}
+
+
+static void set_border(int color)
+{
+ inb(crtc_addr+6); /* reset flip-flop */
+ outb(ATC, 0x11); outb(ATC, color);
+ inb(crtc_addr+6); /* reset flip-flop */
+ outb(ATC, 0x20); /* enable Palette */
+}
+
+static void 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 void change_winsize(struct tty *tp, int x, int y)
+{
+ if (tp->t_winsize.ws_col != x || tp->t_winsize.ws_row != y) {
+ tp->t_winsize.ws_col = x;
+ tp->t_winsize.ws_row = y;
+ pgsignal(tp->t_pgrp, SIGWINCH, 1);
+ }
+}
+
+#endif /* NSC */
OpenPOWER on IntegriCloud