summaryrefslogtreecommitdiff
path: root/sys/arch/arm32/mainbus
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arch/arm32/mainbus')
-rw-r--r--sys/arch/arm32/mainbus/beep.c369
-rw-r--r--sys/arch/arm32/mainbus/com.c1034
-rw-r--r--sys/arch/arm32/mainbus/comreg.h133
-rw-r--r--sys/arch/arm32/mainbus/cpu.c500
-rw-r--r--sys/arch/arm32/mainbus/fd.c1339
-rw-r--r--sys/arch/arm32/mainbus/fdreg.h102
-rw-r--r--sys/arch/arm32/mainbus/iic.c403
-rw-r--r--sys/arch/arm32/mainbus/iic_asm.S239
-rw-r--r--sys/arch/arm32/mainbus/kbd.c1357
-rw-r--r--sys/arch/arm32/mainbus/lpt.c1314
-rw-r--r--sys/arch/arm32/mainbus/lptreg.h64
-rw-r--r--sys/arch/arm32/mainbus/mainbus.c136
-rw-r--r--sys/arch/arm32/mainbus/mainbus.h62
-rw-r--r--sys/arch/arm32/mainbus/pms.c612
-rw-r--r--sys/arch/arm32/mainbus/qmouse.c440
-rw-r--r--sys/arch/arm32/mainbus/rtc.c384
-rw-r--r--sys/arch/arm32/mainbus/vidcaudio.c870
-rw-r--r--sys/arch/arm32/mainbus/waveform.h551
-rw-r--r--sys/arch/arm32/mainbus/wd.c1764
-rw-r--r--sys/arch/arm32/mainbus/wdreg.h161
20 files changed, 11834 insertions, 0 deletions
diff --git a/sys/arch/arm32/mainbus/beep.c b/sys/arch/arm32/mainbus/beep.c
new file mode 100644
index 00000000000..762830309f5
--- /dev/null
+++ b/sys/arch/arm32/mainbus/beep.c
@@ -0,0 +1,369 @@
+/* $NetBSD: beep.c,v 1.4 1996/03/27 22:08:36 mark Exp $ */
+
+/*
+ * Copyright (c) 1995 Mark Brinicombe
+ *
+ * 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 RiscBSD team.
+ * 4. 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.
+ */
+
+/*
+ * Simple beep sounds using VIDC
+ */
+
+/*
+ * To use the driver, open /dev/beep and write lines.
+ * Each write will generate a beep
+ *
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/ioctl.h>
+#include <sys/tty.h>
+#include <sys/kernel.h>
+#include <sys/types.h>
+#include <sys/device.h>
+#include <sys/proc.h>
+#include <sys/time.h>
+#include <sys/errno.h>
+#include <dev/cons.h>
+#include <vm/vm.h>
+#include <vm/vm_kern.h>
+
+#include <machine/irqhandler.h>
+#include <machine/katelib.h>
+#include <machine/iomd.h>
+#include <machine/vidc.h>
+#include <machine/pmap.h>
+#include <machine/beep.h>
+#include <arm32/mainbus/mainbus.h>
+#include <arm32/mainbus/waveform.h>
+
+#include "beep.h"
+
+struct beep_softc {
+ struct device sc_device;
+ irqhandler_t sc_ih;
+ int sc_iobase;
+ int sc_open;
+ int sc_count;
+ u_int sc_sound_cur0;
+ u_int sc_sound_end0;
+ u_int sc_sound_cur1;
+ u_int sc_sound_end1;
+ vm_offset_t sc_buffer0;
+ vm_offset_t sc_buffer1;
+};
+
+int beepprobe __P((struct device *parent, void *match, void *aux));
+void beepattach __P((struct device *parent, struct device *self, void *aux));
+int beepopen __P((dev_t, int, int, struct proc *));
+int beepclose __P((dev_t, int, int, struct proc *));
+int beepintr __P((struct beep_softc *sc));
+void beepdma __P((struct beep_softc *sc, int buf));
+
+struct cfattach beep_ca = {
+ sizeof(struct beep_softc), beepprobe, beepattach
+};
+
+struct cfdriver beep_cd = {
+ NULL, "beep", DV_TTY
+};
+
+
+int
+beepprobe(parent, match, aux)
+ struct device *parent;
+ void *match;
+ void *aux;
+{
+/* struct mainbus_attach_args *mb = aux;*/
+ int id;
+
+/* Make sure we have an IOMD we understand */
+
+ id = ReadByte(IOMD_ID0) | (ReadByte(IOMD_ID1) << 8);
+
+/* So far I only know about this IOMD */
+
+ switch (id) {
+ case RPC600_IOMD_ID:
+ return(1);
+ break;
+ default:
+ printf("beep: Unknown IOMD id=%04x", id);
+ break;
+ }
+ return(0);
+}
+
+
+void
+beepattach(parent, self, aux)
+ struct device *parent;
+ struct device *self;
+ void *aux;
+{
+ struct beep_softc *sc = (void *)self;
+ struct mainbus_attach_args *mb = aux;
+
+ sc->sc_iobase = mb->mb_iobase;
+ sc->sc_open = 0;
+ sc->sc_count = 0;
+
+ sc->sc_buffer0 = kmem_alloc(kernel_map, NBPG);
+ if (sc->sc_buffer0 == 0)
+ panic("beep: Cannot allocate buffer memory\n");
+ if ((sc->sc_buffer0 & (NBPG -1)) != 0)
+ panic("beep: Cannot allocate page aligned buffer\n");
+ sc->sc_buffer1 = sc->sc_buffer0;
+
+ sc->sc_sound_cur0 = pmap_extract(kernel_pmap,
+ (vm_offset_t)sc->sc_buffer0 & PG_FRAME);
+ sc->sc_sound_end0 = (sc->sc_sound_cur0 + NBPG - 16) | 0x00000000;
+ sc->sc_sound_cur1 = pmap_extract(kernel_pmap,
+ (vm_offset_t)sc->sc_buffer1 & PG_FRAME);
+ sc->sc_sound_end1 = (sc->sc_sound_cur1 + NBPG - 16) | 0x00000000;
+
+ bcopy(beep_waveform, (void *)sc->sc_buffer0, sizeof(beep_waveform));
+
+/* Reset the sound DMA channel */
+
+ WriteWord(IOMD_SD0CURA, sc->sc_sound_cur0);
+ WriteWord(IOMD_SD0ENDA, sc->sc_sound_end0 | 0xc0000000);
+ WriteWord(IOMD_SD0CURB, sc->sc_sound_cur1);
+ WriteWord(IOMD_SD0ENDB, sc->sc_sound_end1 | 0xc0000000);
+
+ WriteByte(IOMD_SD0CR, 0x90);
+
+/* Install an IRQ handler */
+
+ sc->sc_ih.ih_func = beepintr;
+ sc->sc_ih.ih_arg = sc;
+ sc->sc_ih.ih_level = IPL_NONE;
+ sc->sc_ih.ih_name = "dma snd ch 0";
+
+ if (irq_claim(IRQ_DMASCH0, &sc->sc_ih))
+ panic("Cannot claim DMASCH0 IRQ for beep%d\n", parent->dv_unit);
+
+ disable_irq(IRQ_DMASCH0);
+
+/*
+ printf(" [ buf0=%08x:%08x->%08x buf1=%08x:%08x->%08x ]",
+ (u_int)sc->sc_buffer0, sc->sc_sound_cur0, sc->sc_sound_end0,
+ (u_int)sc->sc_buffer1, sc->sc_sound_cur1, sc->sc_sound_end1);
+*/
+ printf("\n");
+
+/* Set sample rate to 32us */
+
+ WriteWord(VIDC_BASE, VIDC_SFR | 32);
+
+/* Set the stereo postions to centred for all channels */
+
+ WriteWord(VIDC_BASE, VIDC_SIR0 | SIR_CENTRE);
+ WriteWord(VIDC_BASE, VIDC_SIR1 | SIR_CENTRE);
+ WriteWord(VIDC_BASE, VIDC_SIR2 | SIR_CENTRE);
+ WriteWord(VIDC_BASE, VIDC_SIR3 | SIR_CENTRE);
+ WriteWord(VIDC_BASE, VIDC_SIR4 | SIR_CENTRE);
+ WriteWord(VIDC_BASE, VIDC_SIR5 | SIR_CENTRE);
+ WriteWord(VIDC_BASE, VIDC_SIR6 | SIR_CENTRE);
+ WriteWord(VIDC_BASE, VIDC_SIR7 | SIR_CENTRE);
+}
+
+
+int
+beepopen(dev, flag, mode, p)
+ dev_t dev;
+ int flag;
+ int mode;
+ struct proc *p;
+{
+ struct beep_softc *sc;
+ int unit = minor(dev);
+ int s;
+
+ if (unit >= beep_cd.cd_ndevs)
+ return(ENXIO);
+
+ sc = beep_cd.cd_devs[unit];
+ if (!sc) return(ENXIO);
+
+/* HACK hack hack */
+
+ s = splhigh();
+ if (sc->sc_open) {
+ (void)splx(s);
+ return(EBUSY);
+ }
+
+ ++sc->sc_open;
+ (void)splx(s);
+
+ return(0);
+}
+
+
+int
+beepclose(dev, flag, mode, p)
+ dev_t dev;
+ int flag;
+ int mode;
+ struct proc *p;
+{
+ int unit = minor(dev);
+ struct beep_softc *sc = beep_cd.cd_devs[unit];
+ int s;
+
+ if (sc->sc_open == 0) return(ENXIO);
+
+/* HACK hack hack */
+
+ s = splhigh();
+ --sc->sc_open;
+ (void)splx(s);
+
+ return(0);
+}
+
+
+void
+beep_generate(void)
+{
+ struct beep_softc *sc = beep_cd.cd_devs[0];
+/* int status;*/
+
+ if (sc->sc_count > 0) {
+/* printf("beep: active\n");*/
+ return;
+ }
+/* printf("beep: generate ");*/
+ ++sc->sc_count;
+
+/* status = ReadByte(IOMD_SD0ST);
+ printf("st=%02x\n", status);*/
+ WriteByte(IOMD_SD0CR, 0x90);
+ WriteByte(IOMD_SD0CR, 0x30);
+ beepdma(sc, 0);
+}
+
+
+int
+beepioctl(dev, cmd, data, flag, p)
+ dev_t dev;
+ int cmd;
+ caddr_t data;
+ int flag;
+ struct proc *p;
+{
+ struct beep_softc *sc = beep_cd.cd_devs[minor(dev)];
+ int rate;
+ struct wavebuffer *wave = (struct wavebuffer *)data;
+
+ switch (cmd) {
+ case BEEP_GENERATE:
+ beep_generate();
+ break;
+
+ case BEEP_SETRATE:
+ rate = *(int *)data;
+
+ if (rate < 3 || rate > 255)
+ return(EINVAL);
+
+ WriteWord(VIDC_BASE, VIDC_SFR | rate);
+ break;
+
+ case BEEP_SET:
+ printf("set %08x\n", (u_int)data);
+ printf("set %08x %08x\n", (u_int)wave->addr, wave->size);
+ if (wave->size < 16 || wave->size > NBPG)
+ return(ENXIO);
+ copyin(wave->addr, (char *)sc->sc_buffer0, wave->size);
+ sc->sc_sound_end0 = (sc->sc_sound_cur0 + wave->size - 16);
+ sc->sc_sound_end1 = (sc->sc_sound_cur1 + wave->size - 16);
+ break;
+
+ default:
+ return(ENXIO);
+ break;
+ }
+
+ return(0);
+}
+
+
+int
+beepintr(sc)
+ struct beep_softc *sc;
+{
+/* printf("beepintr: %02x,%02x,%02x,%d\n", ReadByte(IOMD_DMARQ),
+ ReadByte(IOMD_SD0CR), ReadByte(IOMD_SD0ST), sc->sc_count);*/
+ WriteByte(IOMD_DMARQ, 0x10);
+ --sc->sc_count;
+ if (sc->sc_count <= 0) {
+ WriteWord(IOMD_SD0CURB, sc->sc_sound_cur1);
+ WriteWord(IOMD_SD0ENDB, sc->sc_sound_end1 | (1 << 30));
+ disable_irq(IRQ_DMASCH0);
+/* printf("stop:st=%02x\n", ReadByte(IOMD_SD0ST));*/
+ return(1);
+ }
+
+ beepdma(sc, sc->sc_count & 1);
+ return(1);
+}
+
+
+void
+beepdma(sc, buf)
+ struct beep_softc *sc;
+ int buf;
+{
+ int status;
+/* printf("beep:dma %d", buf); */
+ status = ReadByte(IOMD_SD0ST);
+/* printf("st=%02x\n", status);*/
+
+ if (buf == 0) {
+ WriteWord(IOMD_SD0CURA, sc->sc_sound_cur0);
+ WriteWord(IOMD_SD0ENDA, sc->sc_sound_end0);
+ WriteWord(IOMD_SD0CURB, sc->sc_sound_cur1);
+ WriteWord(IOMD_SD0ENDB, sc->sc_sound_end1 | (1 << 30));
+ }
+
+ if (buf == 1) {
+ WriteWord(IOMD_SD0CURB, sc->sc_sound_cur1);
+ WriteWord(IOMD_SD0ENDB, sc->sc_sound_end1 | (1 << 30));
+ }
+
+/* status = ReadByte(IOMD_SD0ST);
+ printf("st=%02x\n", status);*/
+
+ enable_irq(IRQ_DMASCH0);
+}
+
+/* End of beep.c */
diff --git a/sys/arch/arm32/mainbus/com.c b/sys/arch/arm32/mainbus/com.c
new file mode 100644
index 00000000000..ee9b812f796
--- /dev/null
+++ b/sys/arch/arm32/mainbus/com.c
@@ -0,0 +1,1034 @@
+/* $NetBSD: com.c,v 1.5 1996/03/28 21:52:32 mark Exp $ */
+
+/*-
+ * Copyright (c) 1993, 1994, 1995 Charles M. Hannum. All rights reserved.
+ * 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.
+ *
+ * @(#)com.c 7.5 (Berkeley) 5/16/91
+ */
+
+/*
+ * COM driver, based on HP dca driver
+ * uses National Semiconductor NS16450/NS16550AF UART
+ */
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/ioctl.h>
+#include <sys/select.h>
+#include <sys/tty.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/conf.h>
+#include <sys/file.h>
+#include <sys/uio.h>
+#include <sys/kernel.h>
+#include <sys/syslog.h>
+#include <sys/types.h>
+#include <sys/device.h>
+
+#include <machine/cpu.h>
+#include <machine/katelib.h>
+#include <machine/irqhandler.h>
+#include <machine/io.h>
+#include <arm32/mainbus/comreg.h>
+#include <arm32/mainbus/mainbus.h>
+
+#define com_lcr com_cfcr
+
+#define COM_IBUFSIZE (2 * 256)
+#define COM_IHIGHWATER ((3 * COM_IBUFSIZE) / 4)
+
+struct com_softc {
+ struct device sc_dev;
+ irqhandler_t sc_ih;
+ struct tty *sc_tty;
+
+ int sc_overflows;
+ int sc_floods;
+ int sc_errors;
+
+ int sc_iobase;
+ u_char sc_hwflags;
+#define COM_HW_NOIEN 0x01
+#define COM_HW_FIFO 0x02
+#define COM_HW_CONSOLE 0x40
+ u_char sc_swflags;
+#define COM_SW_SOFTCAR 0x01
+#define COM_SW_CLOCAL 0x02
+#define COM_SW_CRTSCTS 0x04
+#define COM_SW_MDMBUF 0x08
+ u_char sc_msr, sc_mcr, sc_lcr;
+ u_char sc_dtr;
+
+ u_char *sc_ibuf, *sc_ibufp, *sc_ibufhigh, *sc_ibufend;
+ u_char sc_ibufs[2][COM_IBUFSIZE];
+};
+
+int comprobe __P((struct device *, void *, void *));
+void comattach __P((struct device *, struct device *, void *));
+int comopen __P((dev_t, int, int, struct proc *));
+int comclose __P((dev_t, int, int, struct proc *));
+void comdiag __P((void *));
+int comintr __P((void *));
+void compoll __P((void *));
+int comparam __P((struct tty *, struct termios *));
+void comstart __P((struct tty *));
+
+struct cfattach com_ca = {
+ sizeof(struct com_softc), comprobe, comattach
+};
+
+struct cfdriver com_cd = {
+ NULL, "com", DV_TTY
+};
+
+int comdefaultrate = TTYDEF_SPEED;
+#ifdef COMCONSOLE
+int comconsole = COMCONSOLE;
+#else
+int comconsole = -1;
+#endif
+int comconsinit;
+int commajor;
+int comsopen = 0;
+int comevents = 0;
+
+#ifdef KGDB
+#include <machine/remote-sl.h>
+extern int kgdb_dev;
+extern int kgdb_rate;
+extern int kgdb_debug_init;
+#endif
+
+#define COMUNIT(x) (minor(x))
+
+/* Macros to clear/set/test flags. */
+#define SET(t, f) (t) |= (f)
+#define CLR(t, f) (t) &= ~(f)
+#define ISSET(t, f) ((t) & (f))
+
+int
+comspeed(speed)
+ long speed;
+{
+#define divrnd(n, q) (((n)*2/(q)+1)/2) /* divide and round off */
+
+ int x, err;
+
+ if (speed == 0)
+ return 0;
+ if (speed < 0)
+ return -1;
+ x = divrnd((COM_FREQ / 16), speed);
+ if (x <= 0)
+ return -1;
+ err = divrnd((COM_FREQ / 16) * 1000, speed * x) - 1000;
+ if (err < 0)
+ err = -err;
+ if (err > COM_TOLERANCE)
+ return -1;
+ return x;
+
+#undef divrnd(n, q)
+}
+
+int
+comprobe1(iobase)
+ int iobase;
+{
+
+ /* force access to id reg */
+ outb(iobase + com_lcr, 0);
+ outb(iobase + com_iir, 0);
+ if (inb(iobase + com_iir) & 0x38)
+ return 0;
+
+ return 1;
+}
+
+int
+comprobe(parent, match, aux)
+ struct device *parent;
+ void *match, *aux;
+{
+ struct mainbus_attach_args *mb = aux;
+ int iobase = mb->mb_iobase;
+
+ if (!comprobe1(iobase))
+ return 0;
+
+ mb->mb_iosize = COM_NPORTS;
+ return 1;
+}
+
+void
+comattach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct com_softc *sc = (void *)self;
+ struct mainbus_attach_args *mb = aux;
+ struct cfdata *cf = sc->sc_dev.dv_cfdata;
+ int iobase = mb->mb_iobase;
+ struct tty *tp;
+
+ sc->sc_iobase = iobase;
+ sc->sc_hwflags = ISSET(cf->cf_flags, COM_HW_NOIEN);
+ sc->sc_swflags = 0;
+
+ if (sc->sc_dev.dv_unit == comconsole)
+ delay(1000);
+
+ /* look for a NS 16550AF UART with FIFOs */
+ outb(iobase + com_fifo,
+ FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER_14);
+ delay(100);
+ if (ISSET(inb(iobase + com_iir), IIR_FIFO_MASK) == IIR_FIFO_MASK)
+ if (ISSET(inb(iobase + com_fifo), FIFO_TRIGGER_14) == FIFO_TRIGGER_14) {
+ SET(sc->sc_hwflags, COM_HW_FIFO);
+ printf(": ns16550a, working fifo\n");
+ } else
+ printf(": ns16550, broken fifo\n");
+ else
+ printf(": ns8250 or ns16450, no fifo\n");
+ outb(iobase + com_fifo, 0);
+
+ /* disable interrupts */
+ outb(iobase + com_ier, 0);
+ outb(iobase + com_mcr, 0);
+
+ sc->sc_ih.ih_func = comintr;
+ sc->sc_ih.ih_arg = sc;
+ sc->sc_ih.ih_level = IPL_TTY;
+ sc->sc_ih.ih_name = "serial";
+ if (mb->mb_irq != IRQUNK)
+ if (irq_claim(mb->mb_irq, &sc->sc_ih))
+ panic("Cannot claim IRQ %d for com%d\n", mb->mb_irq, sc->sc_dev.dv_unit);
+
+#ifdef KGDB
+ if (kgdb_dev == makedev(commajor, unit)) {
+ if (comconsole == unit)
+ kgdb_dev = -1; /* can't debug over console port */
+ else {
+ (void) cominit(unit, kgdb_rate);
+ if (kgdb_debug_init) {
+ /*
+ * Print prefix of device name,
+ * let kgdb_connect print the rest.
+ */
+ printf("%s: ", sc->sc_dev.dv_xname);
+ kgdb_connect(1);
+ } else
+ printf("%s: kgdb enabled\n",
+ sc->sc_dev.dv_xname);
+ }
+ }
+#endif
+
+ if (sc->sc_dev.dv_unit == comconsole) {
+ /*
+ * Need to reset baud rate, etc. of next print so reset
+ * comconsinit. Also make sure console is always "hardwired".
+ */
+ comconsinit = 0;
+ SET(sc->sc_hwflags, COM_HW_CONSOLE);
+ SET(sc->sc_swflags, COM_SW_SOFTCAR);
+ }
+}
+
+int
+comopen(dev, flag, mode, p)
+ dev_t dev;
+ int flag, mode;
+ struct proc *p;
+{
+ int unit = COMUNIT(dev);
+ struct com_softc *sc;
+ int iobase;
+ struct tty *tp;
+ int s;
+ int error = 0;
+
+ if (unit >= com_cd.cd_ndevs)
+ return ENXIO;
+ sc = com_cd.cd_devs[unit];
+ if (!sc)
+ return ENXIO;
+
+ if (!sc->sc_tty)
+ tp = sc->sc_tty = ttymalloc();
+ else
+ tp = sc->sc_tty;
+
+ tp->t_oproc = comstart;
+ tp->t_param = comparam;
+ tp->t_dev = dev;
+ if (!ISSET(tp->t_state, TS_ISOPEN)) {
+ SET(tp->t_state, TS_WOPEN);
+ ttychars(tp);
+ tp->t_iflag = TTYDEF_IFLAG;
+ tp->t_oflag = TTYDEF_OFLAG;
+ tp->t_cflag = TTYDEF_CFLAG;
+ if (ISSET(sc->sc_swflags, COM_SW_CLOCAL))
+ SET(tp->t_cflag, CLOCAL);
+ if (ISSET(sc->sc_swflags, COM_SW_CRTSCTS))
+ SET(tp->t_cflag, CRTSCTS);
+ if (ISSET(sc->sc_swflags, COM_SW_MDMBUF))
+ SET(tp->t_cflag, MDMBUF);
+ tp->t_lflag = TTYDEF_LFLAG;
+ tp->t_ispeed = tp->t_ospeed = comdefaultrate;
+
+ s = spltty();
+
+ comparam(tp, &tp->t_termios);
+ ttsetwater(tp);
+
+ if (comsopen++ == 0)
+ timeout(compoll, NULL, 1);
+
+ sc->sc_ibufp = sc->sc_ibuf = sc->sc_ibufs[0];
+ sc->sc_ibufhigh = sc->sc_ibuf + COM_IHIGHWATER;
+ sc->sc_ibufend = sc->sc_ibuf + COM_IBUFSIZE;
+
+ iobase = sc->sc_iobase;
+ /* Set the FIFO threshold based on the receive speed. */
+ if (ISSET(sc->sc_hwflags, COM_HW_FIFO))
+ outb(iobase + com_fifo,
+ FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST |
+ (tp->t_ispeed <= 1200 ? FIFO_TRIGGER_1 : FIFO_TRIGGER_8));
+ /* flush any pending I/O */
+ while (ISSET(inb(iobase + com_lsr), LSR_RXRDY))
+ (void) inb(iobase + com_data);
+ /* you turn me on, baby */
+ sc->sc_mcr = MCR_DTR | MCR_RTS;
+ if (!ISSET(sc->sc_hwflags, COM_HW_NOIEN))
+ SET(sc->sc_mcr, MCR_IENABLE);
+ outb(iobase + com_mcr, sc->sc_mcr);
+ outb(iobase + com_ier,
+ IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC);
+
+ sc->sc_msr = inb(iobase + com_msr);
+ if (ISSET(sc->sc_swflags, COM_SW_SOFTCAR) ||
+ ISSET(sc->sc_msr, MSR_DCD) || ISSET(tp->t_cflag, MDMBUF))
+ SET(tp->t_state, TS_CARR_ON);
+ else
+ CLR(tp->t_state, TS_CARR_ON);
+ } else if (ISSET(tp->t_state, TS_XCLUDE) && p->p_ucred->cr_uid != 0)
+ return EBUSY;
+ else
+ s = spltty();
+
+ /* wait for carrier if necessary */
+ if (!ISSET(flag, O_NONBLOCK))
+ while (!ISSET(tp->t_cflag, CLOCAL) &&
+ !ISSET(tp->t_state, TS_CARR_ON)) {
+ SET(tp->t_state, TS_WOPEN);
+ error = ttysleep(tp, &tp->t_rawq, TTIPRI | PCATCH,
+ ttopen, 0);
+ if (error) {
+ /* XXX should turn off chip if we're the
+ only waiter */
+ splx(s);
+ return error;
+ }
+ }
+ splx(s);
+
+ return (*linesw[tp->t_line].l_open)(dev, tp);
+}
+
+int
+comclose(dev, flag, mode, p)
+ dev_t dev;
+ int flag, mode;
+ struct proc *p;
+{
+ int unit = COMUNIT(dev);
+ struct com_softc *sc = com_cd.cd_devs[unit];
+ struct tty *tp = sc->sc_tty;
+ int iobase = sc->sc_iobase;
+ int s;
+
+ /* XXX This is for cons.c. */
+ if (!ISSET(tp->t_state, TS_ISOPEN))
+ return 0;
+
+ (*linesw[tp->t_line].l_close)(tp, flag);
+ s = spltty();
+ CLR(sc->sc_lcr, LCR_SBREAK);
+ outb(iobase + com_lcr, sc->sc_lcr);
+ outb(iobase + com_ier, 0);
+ if (ISSET(tp->t_cflag, HUPCL) &&
+ !ISSET(sc->sc_swflags, COM_SW_SOFTCAR)) {
+ /* XXX perhaps only clear DTR */
+ outb(iobase + com_mcr, 0);
+ }
+ CLR(tp->t_state, TS_BUSY | TS_FLUSH);
+ if (--comsopen == 0)
+ untimeout(compoll, NULL);
+ splx(s);
+ ttyclose(tp);
+#ifdef notyet /* XXXX */
+ if (unit != comconsole) {
+ ttyfree(tp);
+ sc->sc_tty = 0;
+ }
+#endif
+ return 0;
+}
+
+int
+comread(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ struct com_softc *sc = com_cd.cd_devs[COMUNIT(dev)];
+ struct tty *tp = sc->sc_tty;
+
+ return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
+}
+
+int
+comwrite(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ struct com_softc *sc = com_cd.cd_devs[COMUNIT(dev)];
+ struct tty *tp = sc->sc_tty;
+
+ return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
+}
+
+struct tty *
+comtty(dev)
+ dev_t dev;
+{
+ struct com_softc *sc = com_cd.cd_devs[COMUNIT(dev)];
+ struct tty *tp = sc->sc_tty;
+
+ return (tp);
+}
+
+static u_char
+tiocm_xxx2mcr(data)
+ int data;
+{
+ u_char m = 0;
+
+ if (ISSET(data, TIOCM_DTR))
+ SET(m, MCR_DTR);
+ if (ISSET(data, TIOCM_RTS))
+ SET(m, MCR_RTS);
+ return m;
+}
+
+int
+comioctl(dev, cmd, data, flag, p)
+ dev_t dev;
+ u_long cmd;
+ caddr_t data;
+ int flag;
+ struct proc *p;
+{
+ int unit = COMUNIT(dev);
+ struct com_softc *sc = com_cd.cd_devs[unit];
+ struct tty *tp = sc->sc_tty;
+ int iobase = sc->sc_iobase;
+ int error;
+
+ error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
+ if (error >= 0)
+ return error;
+ error = ttioctl(tp, cmd, data, flag, p);
+ if (error >= 0)
+ return error;
+
+ switch (cmd) {
+ case TIOCSBRK:
+ SET(sc->sc_lcr, LCR_SBREAK);
+ outb(iobase + com_lcr, sc->sc_lcr);
+ break;
+ case TIOCCBRK:
+ CLR(sc->sc_lcr, LCR_SBREAK);
+ outb(iobase + com_lcr, sc->sc_lcr);
+ break;
+ case TIOCSDTR:
+ SET(sc->sc_mcr, sc->sc_dtr);
+ outb(iobase + com_mcr, sc->sc_mcr);
+ break;
+ case TIOCCDTR:
+ CLR(sc->sc_mcr, sc->sc_dtr);
+ outb(iobase + com_mcr, sc->sc_mcr);
+ break;
+ case TIOCMSET:
+ CLR(sc->sc_mcr, MCR_DTR | MCR_RTS);
+ case TIOCMBIS:
+ SET(sc->sc_mcr, tiocm_xxx2mcr(*(int *)data));
+ outb(iobase + com_mcr, sc->sc_mcr);
+ break;
+ case TIOCMBIC:
+ CLR(sc->sc_mcr, tiocm_xxx2mcr(*(int *)data));
+ outb(iobase + com_mcr, sc->sc_mcr);
+ break;
+ case TIOCMGET: {
+ u_char m;
+ int bits = 0;
+
+ m = sc->sc_mcr;
+ if (ISSET(m, MCR_DTR))
+ SET(bits, TIOCM_DTR);
+ if (ISSET(m, MCR_RTS))
+ SET(bits, TIOCM_RTS);
+ m = sc->sc_msr;
+ if (ISSET(m, MSR_DCD))
+ SET(bits, TIOCM_CD);
+ if (ISSET(m, MSR_CTS))
+ SET(bits, TIOCM_CTS);
+ if (ISSET(m, MSR_DSR))
+ SET(bits, TIOCM_DSR);
+ if (ISSET(m, MSR_RI | MSR_TERI))
+ SET(bits, TIOCM_RI);
+ if (inb(iobase + com_ier))
+ SET(bits, TIOCM_LE);
+ *(int *)data = bits;
+ break;
+ }
+ case TIOCGFLAGS: {
+ int driverbits, userbits = 0;
+
+ driverbits = sc->sc_swflags;
+ if (ISSET(driverbits, COM_SW_SOFTCAR))
+ SET(userbits, TIOCFLAG_SOFTCAR);
+ if (ISSET(driverbits, COM_SW_CLOCAL))
+ SET(userbits, TIOCFLAG_CLOCAL);
+ if (ISSET(driverbits, COM_SW_CRTSCTS))
+ SET(userbits, TIOCFLAG_CRTSCTS);
+ if (ISSET(driverbits, COM_SW_MDMBUF))
+ SET(userbits, TIOCFLAG_MDMBUF);
+
+ *(int *)data = userbits;
+ break;
+ }
+ case TIOCSFLAGS: {
+ int userbits, driverbits = 0;
+
+ error = suser(p->p_ucred, &p->p_acflag);
+ if (error != 0)
+ return(EPERM);
+
+ userbits = *(int *)data;
+ if (ISSET(userbits, TIOCFLAG_SOFTCAR) ||
+ ISSET(sc->sc_hwflags, COM_HW_CONSOLE))
+ SET(driverbits, COM_SW_SOFTCAR);
+ if (ISSET(userbits, TIOCFLAG_CLOCAL))
+ SET(driverbits, COM_SW_CLOCAL);
+ if (ISSET(userbits, TIOCFLAG_CRTSCTS))
+ SET(driverbits, COM_SW_CRTSCTS);
+ if (ISSET(userbits, TIOCFLAG_MDMBUF))
+ SET(driverbits, COM_SW_MDMBUF);
+
+ sc->sc_swflags = driverbits;
+ break;
+ }
+ default:
+ return ENOTTY;
+ }
+
+ return 0;
+}
+
+int
+comparam(tp, t)
+ struct tty *tp;
+ struct termios *t;
+{
+ struct com_softc *sc = com_cd.cd_devs[COMUNIT(tp->t_dev)];
+ int iobase = sc->sc_iobase;
+ int ospeed = comspeed(t->c_ospeed);
+ u_char lcr;
+ tcflag_t oldcflag;
+ int s;
+
+ /* check requested parameters */
+ if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
+ return EINVAL;
+
+ lcr = sc->sc_lcr & LCR_SBREAK;
+
+ switch (ISSET(t->c_cflag, CSIZE)) {
+ case CS5:
+ SET(lcr, LCR_5BITS);
+ break;
+ case CS6:
+ SET(lcr, LCR_6BITS);
+ break;
+ case CS7:
+ SET(lcr, LCR_7BITS);
+ break;
+ case CS8:
+ SET(lcr, LCR_8BITS);
+ break;
+ }
+ if (ISSET(t->c_cflag, PARENB)) {
+ SET(lcr, LCR_PENAB);
+ if (!ISSET(t->c_cflag, PARODD))
+ SET(lcr, LCR_PEVEN);
+ }
+ if (ISSET(t->c_cflag, CSTOPB))
+ SET(lcr, LCR_STOPB);
+
+ sc->sc_lcr = lcr;
+
+ s = spltty();
+
+ if (ospeed == 0) {
+ CLR(sc->sc_mcr, MCR_DTR);
+ outb(iobase + com_mcr, sc->sc_mcr);
+ }
+
+ /*
+ * Set the FIFO threshold based on the receive speed, if we are
+ * changing it.
+ */
+ if (tp->t_ispeed != t->c_ispeed) {
+ if (ISSET(sc->sc_hwflags, COM_HW_FIFO))
+ outb(iobase + com_fifo,
+ FIFO_ENABLE |
+ (t->c_ispeed <= 1200 ? FIFO_TRIGGER_1 : FIFO_TRIGGER_8));
+ }
+
+ if (ospeed != 0) {
+ outb(iobase + com_lcr, lcr | LCR_DLAB);
+ outb(iobase + com_dlbl, ospeed);
+ outb(iobase + com_dlbh, ospeed >> 8);
+ outb(iobase + com_lcr, lcr);
+ SET(sc->sc_mcr, MCR_DTR);
+ outb(iobase + com_mcr, sc->sc_mcr);
+ } else
+ outb(iobase + com_lcr, lcr);
+
+ /* When not using CRTSCTS, RTS follows DTR. */
+ if (!ISSET(t->c_cflag, CRTSCTS)) {
+ if (ISSET(sc->sc_mcr, MCR_DTR)) {
+ if (!ISSET(sc->sc_mcr, MCR_RTS)) {
+ SET(sc->sc_mcr, MCR_RTS);
+ outb(iobase + com_mcr, sc->sc_mcr);
+ }
+ } else {
+ if (ISSET(sc->sc_mcr, MCR_RTS)) {
+ CLR(sc->sc_mcr, MCR_RTS);
+ outb(iobase + com_mcr, sc->sc_mcr);
+ }
+ }
+ sc->sc_dtr = MCR_DTR | MCR_RTS;
+ } else
+ sc->sc_dtr = MCR_DTR;
+
+ /* and copy to tty */
+ tp->t_ispeed = t->c_ispeed;
+ tp->t_ospeed = t->c_ospeed;
+ oldcflag = tp->t_cflag;
+ tp->t_cflag = t->c_cflag;
+
+ /*
+ * If DCD is off and MDMBUF is changed, ask the tty layer if we should
+ * stop the device.
+ */
+ if (!ISSET(sc->sc_msr, MSR_DCD) &&
+ !ISSET(sc->sc_swflags, COM_SW_SOFTCAR) &&
+ ISSET(oldcflag, MDMBUF) != ISSET(tp->t_cflag, MDMBUF) &&
+ (*linesw[tp->t_line].l_modem)(tp, 0) == 0) {
+ CLR(sc->sc_mcr, sc->sc_dtr);
+ outb(iobase + com_mcr, sc->sc_mcr);
+ }
+
+ splx(s);
+ return 0;
+}
+
+void
+comstart(tp)
+ struct tty *tp;
+{
+ struct com_softc *sc = com_cd.cd_devs[COMUNIT(tp->t_dev)];
+ int iobase = sc->sc_iobase;
+ int s;
+
+ s = spltty();
+ if (ISSET(tp->t_state, TS_TTSTOP | TS_BUSY))
+ goto out;
+ if (ISSET(tp->t_cflag, CRTSCTS) && !ISSET(sc->sc_msr, MSR_CTS))
+ goto out;
+ if (tp->t_outq.c_cc <= tp->t_lowat) {
+ if (ISSET(tp->t_state, TS_ASLEEP)) {
+ CLR(tp->t_state, TS_ASLEEP);
+ wakeup(&tp->t_outq);
+ }
+ if (tp->t_outq.c_cc == 0)
+ goto out;
+ selwakeup(&tp->t_wsel);
+ }
+ SET(tp->t_state, TS_BUSY);
+ if (ISSET(sc->sc_hwflags, COM_HW_FIFO)) {
+ u_char buffer[16], *cp = buffer;
+ int n = q_to_b(&tp->t_outq, cp, sizeof buffer);
+ do {
+ outb(iobase + com_data, *cp++);
+ } while (--n);
+ } else
+ outb(iobase + com_data, getc(&tp->t_outq));
+out:
+ splx(s);
+}
+
+/*
+ * Stop output on a line.
+ */
+void
+comstop(tp, flag)
+ struct tty *tp;
+{
+ int s;
+
+ s = spltty();
+ if (ISSET(tp->t_state, TS_BUSY))
+ if (!ISSET(tp->t_state, TS_TTSTOP))
+ SET(tp->t_state, TS_FLUSH);
+ splx(s);
+}
+
+void
+comdiag(arg)
+ void *arg;
+{
+ struct com_softc *sc = arg;
+ int overflows, floods;
+ int s;
+
+ s = spltty();
+ sc->sc_errors = 0;
+ overflows = sc->sc_overflows;
+ sc->sc_overflows = 0;
+ floods = sc->sc_floods;
+ sc->sc_floods = 0;
+ splx(s);
+
+ log(LOG_WARNING, "%s: %d silo overflow%s, %d ibuf overflow%s\n",
+ sc->sc_dev.dv_xname,
+ overflows, overflows == 1 ? "" : "s",
+ floods, floods == 1 ? "" : "s");
+}
+
+void
+compoll(arg)
+ void *arg;
+{
+ int unit;
+ struct com_softc *sc;
+ struct tty *tp;
+ register u_char *ibufp;
+ u_char *ibufend;
+ register int c;
+ int s;
+ static int lsrmap[8] = {
+ 0, TTY_PE,
+ TTY_FE, TTY_PE|TTY_FE,
+ TTY_FE, TTY_PE|TTY_FE,
+ TTY_FE, TTY_PE|TTY_FE
+ };
+
+ s = spltty();
+ if (comevents == 0) {
+ splx(s);
+ goto out;
+ }
+ comevents = 0;
+ splx(s);
+
+ for (unit = 0; unit < com_cd.cd_ndevs; unit++) {
+ sc = com_cd.cd_devs[unit];
+ if (sc == 0 || sc->sc_ibufp == sc->sc_ibuf)
+ continue;
+
+ tp = sc->sc_tty;
+
+ s = spltty();
+
+ ibufp = sc->sc_ibuf;
+ ibufend = sc->sc_ibufp;
+
+ if (ibufp == ibufend) {
+ splx(s);
+ continue;
+ }
+
+ sc->sc_ibufp = sc->sc_ibuf = (ibufp == sc->sc_ibufs[0]) ?
+ sc->sc_ibufs[1] : sc->sc_ibufs[0];
+ sc->sc_ibufhigh = sc->sc_ibuf + COM_IHIGHWATER;
+ sc->sc_ibufend = sc->sc_ibuf + COM_IBUFSIZE;
+
+ if (tp == 0 || !ISSET(tp->t_state, TS_ISOPEN)) {
+ splx(s);
+ continue;
+ }
+
+ if (ISSET(tp->t_cflag, CRTSCTS) &&
+ !ISSET(sc->sc_mcr, MCR_RTS)) {
+ /* XXX */
+ SET(sc->sc_mcr, MCR_RTS);
+ outb(sc->sc_iobase + com_mcr, sc->sc_mcr);
+ }
+
+ splx(s);
+
+ while (ibufp < ibufend) {
+ c = *ibufp++;
+ if (*ibufp & LSR_OE) {
+ sc->sc_overflows++;
+ if (sc->sc_errors++ == 0)
+ timeout(comdiag, sc, 60 * hz);
+ }
+ /* This is ugly, but fast. */
+ c |= lsrmap[(*ibufp++ & (LSR_BI|LSR_FE|LSR_PE)) >> 2];
+ (*linesw[tp->t_line].l_rint)(c, tp);
+ }
+ }
+
+out:
+ timeout(compoll, NULL, 1);
+}
+
+int
+comintr(arg)
+ void *arg;
+{
+ struct com_softc *sc = arg;
+ int iobase = sc->sc_iobase;
+ struct tty *tp;
+ u_char lsr, data, msr, delta;
+
+ if (ISSET(inb(iobase + com_iir), IIR_NOPEND))
+ return (0);
+
+ tp = sc->sc_tty;
+
+ for (;;) {
+ lsr = inb(iobase + com_lsr);
+
+ if (ISSET(lsr, LSR_RCV_MASK)) {
+ register u_char *p = sc->sc_ibufp;
+
+ comevents = 1;
+ do {
+ data = ISSET(lsr, LSR_RXRDY) ?
+ inb(iobase + com_data) : 0;
+ if (ISSET(lsr, LSR_BI)) {
+#ifdef DDB
+ if (sc->sc_dev.dv_unit == comconsole) {
+ Debugger();
+ goto next;
+ }
+#endif
+ data = '\0';
+ }
+ if (p >= sc->sc_ibufend) {
+ sc->sc_floods++;
+ if (sc->sc_errors++ == 0)
+ timeout(comdiag, sc, 60 * hz);
+ } else {
+ *p++ = data;
+ *p++ = lsr;
+ if (p == sc->sc_ibufhigh &&
+ ISSET(tp->t_cflag, CRTSCTS)) {
+ /* XXX */
+ CLR(sc->sc_mcr, MCR_RTS);
+ outb(iobase + com_mcr,
+ sc->sc_mcr);
+ }
+ }
+ next:
+ lsr = inb(iobase + com_lsr);
+ } while (ISSET(lsr, LSR_RCV_MASK));
+
+ sc->sc_ibufp = p;
+ }
+#if 0
+ else if (ISSET(lsr, LSR_BI|LSR_FE|LSR_PE|LSR_OE))
+ printf("weird lsr %02x\n", lsr);
+#endif
+
+ msr = inb(iobase + com_msr);
+
+ if (msr != sc->sc_msr) {
+ delta = msr ^ sc->sc_msr;
+ sc->sc_msr = msr;
+ if (ISSET(delta, MSR_DCD) &&
+ !ISSET(sc->sc_swflags, COM_SW_SOFTCAR) &&
+ (*linesw[tp->t_line].l_modem)(tp, ISSET(msr, MSR_DCD)) == 0) {
+ CLR(sc->sc_mcr, sc->sc_dtr);
+ outb(iobase + com_mcr, sc->sc_mcr);
+ }
+ if (ISSET(delta & msr, MSR_CTS) &&
+ ISSET(tp->t_cflag, CRTSCTS)) {
+ /* the line is up and we want to do rts/cts flow control */
+ (*linesw[tp->t_line].l_start)(tp);
+ }
+ }
+
+ if (ISSET(lsr, LSR_TXRDY) && ISSET(tp->t_state, TS_BUSY)) {
+ CLR(tp->t_state, TS_BUSY);
+ if (ISSET(tp->t_state, TS_FLUSH))
+ CLR(tp->t_state, TS_FLUSH);
+ else
+ (*linesw[tp->t_line].l_start)(tp);
+ }
+
+ if (ISSET(inb(iobase + com_iir), IIR_NOPEND))
+ return (1);
+ }
+}
+
+/*
+ * Following are all routines needed for COM to act as console
+ */
+#include <dev/cons.h>
+
+void
+comcnprobe(cp)
+ struct consdev *cp;
+{
+
+ if (!comprobe1(CONADDR)) {
+ cp->cn_pri = CN_DEAD;
+ return;
+ }
+
+ /* locate the major number */
+ for (commajor = 0; commajor < nchrdev; commajor++)
+ if (cdevsw[commajor].d_open == comopen)
+ break;
+
+ /* initialize required fields */
+ cp->cn_dev = makedev(commajor, CONUNIT);
+#ifdef COMCONSOLE
+ cp->cn_pri = CN_REMOTE; /* Force a serial port console */
+#else
+ cp->cn_pri = CN_NORMAL;
+#endif
+}
+
+void
+comcninit(cp)
+ struct consdev *cp;
+{
+
+ cominit(CONUNIT, comdefaultrate);
+ comconsole = CONUNIT;
+ comconsinit = 0;
+}
+
+cominit(unit, rate)
+ int unit, rate;
+{
+ int s = splhigh();
+ int iobase = CONADDR;
+ u_char stat;
+
+ outb(iobase + com_lcr, LCR_DLAB);
+ rate = comspeed(comdefaultrate);
+ outb(iobase + com_dlbl, rate);
+ outb(iobase + com_dlbh, rate >> 8);
+ outb(iobase + com_lcr, LCR_8BITS);
+ outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY);
+ outb(iobase + com_fifo, FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER_4);
+ stat = inb(iobase + com_iir);
+ splx(s);
+}
+
+comcngetc(dev)
+ dev_t dev;
+{
+ int s = splhigh();
+ int iobase = CONADDR;
+ u_char stat, c;
+
+ while (!ISSET(stat = inb(iobase + com_lsr), LSR_RXRDY))
+ ;
+ c = inb(iobase + com_data);
+ stat = inb(iobase + com_iir);
+ splx(s);
+ return c;
+}
+
+/*
+ * Console kernel output character routine.
+ */
+void
+comcnputc(dev, c)
+ dev_t dev;
+ int c;
+{
+ int s = splhigh();
+ int iobase = CONADDR;
+ u_char stat;
+ register int timo;
+
+#ifdef KGDB
+ if (dev != kgdb_dev)
+#endif
+ if (comconsinit == 0) {
+ (void) cominit(COMUNIT(dev), comdefaultrate);
+ comconsinit = 1;
+ }
+ /* wait for any pending transmission to finish */
+ timo = 50000;
+ while (!ISSET(stat = inb(iobase + com_lsr), LSR_TXRDY) && --timo)
+ ;
+ outb(iobase + com_data, c);
+ /* wait for this transmission to complete */
+ timo = 1500000;
+ while (!ISSET(stat = inb(iobase + com_lsr), LSR_TXRDY) && --timo)
+ ;
+ /* clear any interrupts generated by this transmission */
+ stat = inb(iobase + com_iir);
+ splx(s);
+}
+
+void
+comcnpollc(dev, on)
+ dev_t dev;
+ int on;
+{
+
+}
diff --git a/sys/arch/arm32/mainbus/comreg.h b/sys/arch/arm32/mainbus/comreg.h
new file mode 100644
index 00000000000..7b1464d0a68
--- /dev/null
+++ b/sys/arch/arm32/mainbus/comreg.h
@@ -0,0 +1,133 @@
+/* $NetBSD: comreg.h,v 1.1 1996/01/31 23:24:29 mark Exp $ */
+
+/*-
+ * 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.
+ *
+ * @(#)comreg.h 7.2 (Berkeley) 5/9/91
+ */
+
+/*
+ * NS16550 UART registers
+ */
+
+#define com_data 0 /* data register (R/W) */
+#define com_dlbl 0 /* divisor latch low (W) */
+#define com_dlbh 4 /* divisor latch high (W) */
+#define com_ier 4 /* interrupt enable (W) */
+#define com_iir 8 /* interrupt identification (R) */
+#define com_fifo 8 /* FIFO control (W) */
+#define com_lctl 12 /* line control register (R/W) */
+#define com_cfcr 12 /* line control register (R/W) */
+#define com_mcr 16 /* modem control register (R/W) */
+#define com_lsr 20 /* line status register (R/W) */
+#define com_msr 24 /* modem status register (R/W) */
+#define com_scratch 28 /* scratch register (R/W) */
+
+#define COM_FREQ 1843200 /* 16-bit baud rate divisor */
+#define COM_TOLERANCE 30 /* baud rate tolerance, in 0.1% units */
+
+/* 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
+
+/* line control register */
+#define LCR_DLAB 0x80
+#define LCR_SBREAK 0x40
+#define LCR_PZERO 0x30
+#define LCR_PONE 0x20
+#define LCR_PEVEN 0x10
+#define LCR_PODD 0x00
+#define LCR_PENAB 0x08
+#define LCR_STOPB 0x04
+#define LCR_8BITS 0x03
+#define LCR_7BITS 0x02
+#define LCR_6BITS 0x01
+#define LCR_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
+
+#define COM_NPORTS 32
+
+/*
+ * WARNING: Serial console is assumed to be at COM1 address
+ * and CONUNIT must be 0.
+ */
+#define CONADDR (SERIAL0_CONTROLLER_BASE)
+#define CONUNIT (0)
diff --git a/sys/arch/arm32/mainbus/cpu.c b/sys/arch/arm32/mainbus/cpu.c
new file mode 100644
index 00000000000..b5b8551dbdd
--- /dev/null
+++ b/sys/arch/arm32/mainbus/cpu.c
@@ -0,0 +1,500 @@
+/* $NetBSD: cpu.c,v 1.4 1996/03/18 20:50:00 mark Exp $ */
+
+/*
+ * Copyright (c) 1995 Mark Brinicombe.
+ * Copyright (c) 1995 Brini.
+ * 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 Brini.
+ * 4. The name of the company 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 BRINI ``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 BRINI 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.
+ *
+ * RiscBSD kernel project
+ *
+ * cpu.c
+ *
+ * Probing and configuration for the master cpu
+ *
+ * Created : 10/10/95
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/conf.h>
+#include <sys/malloc.h>
+#include <sys/device.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <vm/vm_kern.h>
+#include <machine/io.h>
+#include <machine/katelib.h>
+#include <machine/cpu.h>
+#include <machine/pte.h>
+#include <machine/undefined.h>
+#include <machine/cpus.h>
+
+#include "cpu.h"
+#if NCPU < 1
+#error Need at least 1 CPU configured
+#endif
+
+/* Array of cpu structures, one per possible cpu */
+
+cpu_t cpus[MAX_CPUS];
+
+char cpu_model[48];
+extern int cpu_ctrl; /* Control bits for boot CPU */
+volatile int undefined_test; /* Used for FPA test */
+
+extern char *boot_args;
+
+/* Declare prototypes */
+
+/* Prototypes */
+
+void identify_master_cpu __P((int /*cpu_number*/));
+void identify_arm_cpu __P((int /*cpu_number*/));
+void identify_arm_fpu __P((int /*cpu_number*/));
+char *strstr __P((char */*s1*/, char */*s2*/));
+
+
+/*
+ * int cpumatch(struct device *parent, void *match, void *aux)
+ *
+ * Probe for the main cpu. Currently all this does is return 1 to
+ * indicate that the cpu was found.
+ */
+
+int
+cpumatch(parent, match, aux)
+ struct device *parent;
+ void *match;
+ void *aux;
+{
+ struct device *dev = match;
+
+ if (dev->dv_unit == 0)
+ return(1);
+ return(0);
+}
+
+
+/*
+ * void cpusattach(struct device *parent, struct device *dev, void *aux)
+ *
+ * Attach the main cpu
+ */
+
+void
+cpuattach(parent, self, aux)
+ struct device *parent;
+ struct device *self;
+ void *aux;
+{
+ int loop;
+
+ for (loop = 0; loop < MAX_CPUS; ++loop)
+ bzero(&cpus[loop], sizeof(cpu_t));
+
+ identify_master_cpu(CPU_MASTER);
+}
+
+struct cfattach cpu_ca = {
+ sizeof(struct cpu_softc), cpumatch, cpuattach
+};
+
+struct cfdriver cpu_cd = {
+ NULL, "cpu", DV_DULL, 1
+};
+
+
+/*
+ * Used to test for an FPA. The following function is installed as a coproc1 handler
+ * on the undefined instruction vector and then we issue a FPA instruction.
+ * If undefined_test is non zero then the FPA did not handle the instruction so
+ * must be absent.
+ */
+
+int
+fpa_test(address, instruction, frame)
+ u_int address;
+ u_int instruction;
+ trapframe_t *frame;
+{
+ ++undefined_test;
+ return(0);
+}
+
+/*
+ * If an FPA was found then this function is installed as the coproc1 handler
+ * on the undefined instruction vector. Currently we don't support FPA's
+ * so this just triggers an exception.
+ */
+
+int
+fpa_handler(address, instruction, frame)
+ u_int address;
+ u_int instruction;
+ trapframe_t *frame;
+{
+ u_int fpsr;
+
+ __asm __volatile("stmfd sp!, {r0}; .word 0xee300110; mov %0, r0; ldmfd sp!, {r0}" : "=r" (fpsr));
+
+ printf("FPA exception: fpsr = %08x\n", fpsr);
+
+ return(1);
+}
+
+
+/*
+ * Identify the master (boot) CPU
+ * This also probes for an FPU and will install an FPE if necessary
+ */
+
+void
+identify_master_cpu(cpu_number)
+ int cpu_number;
+{
+ u_int fpsr;
+
+ cpus[cpu_number].cpu_class = CPU_CLASS_ARM;
+ cpus[cpu_number].cpu_host = CPU_HOST_MAINBUS;
+ cpus[cpu_number].cpu_flags = CPU_FLAG_PRESENT;
+ cpus[cpu_number].cpu_ctrl = cpu_ctrl;
+
+/* Get the cpu ID from coprocessor 15 */
+
+ cpus[cpu_number].cpu_id = cpu_id();
+
+ identify_arm_cpu(cpu_number);
+ strcpy(cpu_model, cpus[cpu_number].cpu_model);
+
+/*
+ * Ok now we test for an FPA
+ * At this point no floating point emulator has been installed.
+ * This means any FP instruction will cause undefined exception.
+ * We install a temporay coproc 1 handler which will modify undefined_test
+ * if it is called.
+ * We then try to read the FP status register. If undefined_test has been
+ * decremented then the instruction was not handled by an FPA so we know
+ * the FPA is missing. If undefined_test is still 1 then we know the
+ * instruction was handled by an FPA.
+ * We then remove our test handler and look at the
+ * FP status register for identification.
+ */
+
+ install_coproc_handler(FP_COPROC, fpa_test);
+
+ undefined_test = 0;
+
+ __asm __volatile("stmfd sp!, {r0}; .word 0xee300110; mov %0, r0; ldmfd sp!, {r0}" : "=r" (fpsr));
+
+ if (undefined_test == 0) {
+ cpus[cpu_number].fpu_type = (fpsr >> 24);
+ switch (fpsr >> 24) {
+ case 0x81 :
+ cpus[cpu_number].fpu_class = FPU_CLASS_FPA;
+
+#if 0
+/* Experimental stuff used when playing with an ARM700+FPA11 */
+ printf("FPA11: FPSR=%08x\n", fpsr);
+ fpsr=0x00070400;
+ __asm __volatile("wfs %0" : "=r" (fpsr));
+ __asm __volatile("rfc %0" : "=r" (fpsr));
+ printf("FPA11: FPCR=%08x", fpsr);
+ __asm __volatile("stmfd sp!, {r0}; mov r0, #0x00000e00 ; wfc r0; ldmfd sp!, {r0}");
+ __asm __volatile("rfc %0" : "=r" (fpsr));
+ printf("FPA11: FPCR=%08x", fpsr);
+#endif
+ break;
+
+ default :
+ cpus[cpu_number].fpu_class = FPU_CLASS_FPU;
+ break;
+ }
+ cpus[cpu_number].fpu_flags = 0;
+ install_coproc_handler(FP_COPROC, fpa_handler);
+ } else {
+ cpus[cpu_number].fpu_class = FPU_CLASS_NONE;
+ cpus[cpu_number].fpu_flags = 0;
+
+/* Ok if ARMFPE is defined and the boot options request the ARM FPE then it will
+ * be installed as the FPE. If the installation fails the existing FPE is used as
+ * a fall back.
+ * If either ARMFPE is not defined or the boot args did not request it the old FPE
+ * is installed.
+ * This is just while I work on integrating the new FPE.
+ * It means the new FPE gets installed if compiled int (ARMFPE defined)
+ * and also gives me a on/off option when I boot in case the new FPE is
+ * causing panics.
+ * In all cases it falls back on the existing FPE is the ARMFPE was not successfully
+ * installed.
+ */
+
+#ifdef ARMFPE
+ if (boot_args) {
+ char *ptr;
+
+ ptr = strstr(boot_args, "noarmfpe");
+ if (!ptr) {
+ if (initialise_arm_fpe(&cpus[cpu_number]) != 0) {
+ identify_arm_fpu(cpu_number);
+#ifdef FPE
+ initialise_fpe(&cpus[cpu_number]);
+#endif
+ }
+#ifdef FPE
+ } else
+ initialise_fpe(&cpus[cpu_number]);
+
+ } else
+ initialise_fpe(&cpus[cpu_number]);
+#else
+ }
+ }
+#endif
+
+#else
+#ifdef FPE
+ initialise_fpe(&cpus[cpu_number]);
+#else
+#error No FPE built in
+#endif
+#endif
+ }
+
+ identify_arm_fpu(cpu_number);
+}
+
+
+
+/*
+ * Report the type of the specifed arm processor. This uses the generic and arm specific
+ * information in the cpu structure to identify the processor. The remaining fields
+ * in the cpu structure are filled in appropriately.
+ */
+
+void
+identify_arm_cpu(cpu_number)
+ int cpu_number;
+{
+ cpu_t *cpu;
+ u_int cpuid;
+
+ cpu = &cpus[cpu_number];
+ if (cpu->cpu_host == CPU_HOST_NONE || cpu->cpu_class == CPU_CLASS_NONE) {
+ printf("No installed processor\n");
+ return;
+ }
+ if (cpu->cpu_class != CPU_CLASS_ARM) {
+ printf("identify_arm_cpu: Can only identify ARM CPU's\n");
+ return;
+ }
+ cpuid = cpu->cpu_id;
+
+ if (cpuid == 0) {
+ printf("Processor failed probe - no CPU ID\n");
+ return;
+ }
+
+ if ((cpuid & CPU_ID_DESIGNER_MASK) != CPU_ID_ARM_LTD)
+ printf("Unrecognised designer ID = %08x\n", cpuid);
+
+ switch (cpuid & CPU_ID_CPU_MASK) {
+ case ID_ARM610:
+ cpu->cpu_type = cpuid & CPU_ID_CPU_MASK;
+ break;
+
+ case ID_ARM710 :
+ case ID_ARM700 :
+ cpu->cpu_type = (cpuid & CPU_ID_CPU_MASK) >> 4;
+ break;
+
+ default :
+ printf("Unrecognised processor ID = %08x\n", cpuid);
+ cpu->cpu_type = cpuid & CPU_ID_CPU_MASK;
+ break;
+ }
+
+ sprintf(cpu->cpu_model, "ARM%x rev %d", cpu->cpu_type, cpuid & CPU_ID_REVISION_MASK);
+
+ if ((cpu->cpu_ctrl & CPU_CONTROL_IDC_ENABLE) == 0)
+ strcat(cpu->cpu_model, " IDC disabled");
+ else
+ strcat(cpu->cpu_model, " IDC enabled");
+
+ if ((cpu->cpu_ctrl & CPU_CONTROL_WBUF_ENABLE) == 0)
+ strcat(cpu->cpu_model, " WB disabled");
+ else
+ strcat(cpu->cpu_model, " WB enabled");
+
+ if (cpu->cpu_ctrl & CPU_CONTROL_LABT_ENABLE)
+ strcat(cpu->cpu_model, " LABT");
+ else
+ strcat(cpu->cpu_model, " EABT");
+
+/* Print the info */
+
+ printf(": %s\n", cpu->cpu_model);
+}
+
+
+/*
+ * Report the type of the specifed arm fpu. This uses the generic and arm specific
+ * information in the cpu structure to identify the fpu. The remaining fields
+ * in the cpu structure are filled in appropriately.
+ */
+
+void
+identify_arm_fpu(cpu_number)
+ int cpu_number;
+{
+ cpu_t *cpu;
+
+ cpu = &cpus[cpu_number];
+ if (cpu->cpu_host == CPU_HOST_NONE || cpu->cpu_class == CPU_CLASS_NONE) {
+ printf("No installed processor\n");
+ return;
+ }
+
+ if (cpu->cpu_class != CPU_CLASS_ARM) {
+ printf("identify_arm_cpu: Can only identify ARM FPU's\n");
+ return;
+ }
+
+/* Now for the FP info */
+
+ switch (cpu->fpu_class) {
+ case FPU_CLASS_NONE :
+ strcpy(cpu->fpu_model, "None");
+ break;
+ case FPU_CLASS_FPE :
+ printf("fpe%d at cpu%d: %s\n", cpu_number, cpu_number, cpu->fpu_model);
+ printf("fpe%d: no hardware found\n", cpu_number);
+ break;
+ case FPU_CLASS_FPA :
+ printf("fpe%d at cpu%d: %s\n", cpu_number, cpu_number, cpu->fpu_model);
+ if (cpu->fpu_type == FPU_TYPE_FPA11) {
+ strcpy(cpu->fpu_model, "FPA11");
+ printf("fpe%d: fpa11 found\n", cpu_number);
+ } else {
+ strcpy(cpu->fpu_model, "FPA");
+ printf("fpe%d: fpa10 found\n", cpu_number);
+ }
+ if ((cpu->fpu_flags & 4) == 0)
+ strcat(cpu->fpu_model, "");
+ else
+ strcat(cpu->fpu_model, " clk/2");
+ break;
+ case FPU_CLASS_FPU :
+ sprintf(cpu->fpu_model, "Unknown FPU (ID=%02x)\n", cpu->fpu_type);
+ printf("fpu%d at cpu%d: %s\n", cpu_number, cpu_number, cpu->fpu_model);
+ break;
+ }
+}
+
+
+int
+cpuopen(dev, flag, mode, p)
+ dev_t dev;
+ int flag;
+ int mode;
+ struct proc *p;
+{
+ struct cpu_softc *sc;
+ int unit;
+ int s;
+
+ unit = minor(dev);
+ if (unit >= cpu_cd.cd_ndevs)
+ return(ENXIO);
+
+ sc = cpu_cd.cd_devs[unit];
+ if (!sc) return(ENXIO);
+
+ s = splhigh();
+ if (sc->sc_open) {
+ (void)splx(s);
+ return(EBUSY);
+ }
+
+ ++sc->sc_open;
+ (void)splx(s);
+
+ return(0);
+}
+
+
+int
+cpuclose(dev, flag, mode, p)
+ dev_t dev;
+ int flag;
+ int mode;
+ struct proc *p;
+{
+ struct cpu_softc *sc;
+ int unit;
+ int s;
+
+ unit = minor(dev);
+ sc = cpu_cd.cd_devs[unit];
+
+ if (sc->sc_open == 0) return(ENXIO);
+
+ s = splhigh();
+ --sc->sc_open;
+ (void)splx(s);
+
+ return(0);
+}
+
+
+int
+cpuioctl(dev, cmd, data, flag, p)
+ dev_t dev;
+ int cmd;
+ caddr_t data;
+ int flag;
+ struct proc *p;
+{
+ struct cpu_softc *sc;
+ int unit;
+
+ unit = minor(dev);
+ sc = cpu_cd.cd_devs[unit];
+
+ switch (cmd) {
+ default:
+ return(ENXIO);
+ break;
+ }
+
+ return(0);
+}
+
+/* End of cpu.c */
diff --git a/sys/arch/arm32/mainbus/fd.c b/sys/arch/arm32/mainbus/fd.c
new file mode 100644
index 00000000000..d12e73d46b9
--- /dev/null
+++ b/sys/arch/arm32/mainbus/fd.c
@@ -0,0 +1,1339 @@
+/* $NetBSD: fd.c,v 1.5 1996/03/28 21:52:41 mark Exp $ */
+
+/*-
+ * Copyright (c) 1993, 1994, 1995 Charles Hannum.
+ * 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.
+ *
+ * @(#)fd.c 7.4 (Berkeley) 5/25/91
+ */
+
+/* The new config stuff do no use to use and need to be pulled out */
+
+#undef NEWCONFIG
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/conf.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/device.h>
+#include <sys/disklabel.h>
+#include <sys/dkstat.h>
+#include <sys/disk.h>
+#include <sys/buf.h>
+#include <sys/uio.h>
+#include <sys/syslog.h>
+#include <sys/queue.h>
+
+
+#include <machine/cpu.h>
+#include <machine/irqhandler.h>
+#include <machine/iomd.h>
+#include <machine/io.h>
+#include <machine/katelib.h>
+
+#include <arm32/mainbus/mainbus.h>
+#include <arm32/mainbus/fdreg.h>
+
+#define FDUNIT(dev) (minor(dev) / 8)
+#define FDTYPE(dev) (minor(dev) % 8)
+
+#define b_cylin b_resid
+
+enum fdc_state {
+ DEVIDLE = 0,
+ MOTORWAIT,
+ DOSEEK,
+ SEEKWAIT,
+ SEEKTIMEDOUT,
+ SEEKCOMPLETE,
+ DOIO,
+ IOCOMPLETE,
+ IOTIMEDOUT,
+ DORESET,
+ RESETCOMPLETE,
+ RESETTIMEDOUT,
+ DORECAL,
+ RECALWAIT,
+ RECALTIMEDOUT,
+ RECALCOMPLETE,
+};
+
+/* software state, per controller */
+struct fdc_softc {
+ struct device sc_dev; /* boilerplate */
+ irqhandler_t sc_ih;
+
+ int sc_iobase;
+ int sc_drq;
+
+ struct fd_softc *sc_fd[4]; /* pointers to children */
+ TAILQ_HEAD(drivehead, fd_softc) sc_drives;
+ enum fdc_state sc_state;
+ int sc_errors; /* number of retries so far */
+ u_char sc_status[7]; /* copy of registers */
+};
+
+/* controller driver configuration */
+int fdcprobe __P((struct device *, void *, void *));
+#ifdef NEWCONFIG
+void fdcforceintr __P((void *));
+#endif
+void fdcattach __P((struct device *, struct device *, void *));
+
+static fiqhandler_t fiqhandler;
+
+void floppy_read_fiq __P((void));
+void floppy_write_fiq __P((void));
+
+struct cfattach fdc_ca = {
+ sizeof(struct fdc_softc), fdcprobe, fdcattach
+};
+
+struct cfdriver fdc_cd = {
+ NULL, "fdc", DV_DULL
+};
+
+/*
+ * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how
+ * we tell them apart.
+ */
+struct fd_type {
+ int sectrac; /* sectors per track */
+ int heads; /* number of heads */
+ int seccyl; /* sectors per cylinder */
+ int secsize; /* size code for sectors */
+ int datalen; /* data len when secsize = 0 */
+ int steprate; /* step rate and head unload time */
+ int gap1; /* gap len between sectors */
+ int gap2; /* formatting gap */
+ int tracks; /* total num of tracks */
+ int size; /* size of disk in sectors */
+ int step; /* steps per cylinder */
+ int rate; /* transfer speed code */
+ char *name;
+};
+
+/* The order of entries in the following table is important -- BEWARE! */
+struct fd_type fd_types[] = {
+ { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_500KBPS,"1.44MB" }, /* 1.44MB diskette */
+ { 15,2,30,2,0xff,0xdf,0x1b,0x54,80,2400,1,FDC_500KBPS, "1.2MB" }, /* 1.2 MB AT-diskettes */
+ { 9,2,18,2,0xff,0xdf,0x23,0x50,40, 720,2,FDC_300KBPS, "360KB/AT" }, /* 360kB in 1.2MB drive */
+ { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,1,FDC_250KBPS, "360KB/PC" }, /* 360kB PC diskettes */
+ { 9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS, "720KB" }, /* 3.5" 720kB diskette */
+ { 9,2,18,2,0xff,0xdf,0x23,0x50,80,1440,1,FDC_300KBPS, "720KB/x" }, /* 720kB in 1.2MB drive */
+ { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_250KBPS, "360KB/x" }, /* 360kB in 720kB drive */
+};
+
+/* software state, per disk (with up to 4 disks per ctlr) */
+struct fd_softc {
+ struct device sc_dev;
+ struct disk sc_dk;
+
+ struct fd_type *sc_deftype; /* default type descriptor */
+ struct fd_type *sc_type; /* current type descriptor */
+
+ daddr_t sc_blkno; /* starting block number */
+ int sc_bcount; /* byte count left */
+ int sc_skip; /* bytes already transferred */
+ int sc_nblks; /* number of blocks currently tranferring */
+ int sc_nbytes; /* number of bytes currently tranferring */
+
+ int sc_drive; /* physical unit number */
+ int sc_flags;
+#define FD_OPEN 0x01 /* it's open */
+#define FD_MOTOR 0x02 /* motor should be on */
+#define FD_MOTOR_WAIT 0x04 /* motor coming up */
+ int sc_cylin; /* where we think the head is */
+
+ void *sc_sdhook; /* saved shutdown hook for drive. */
+
+ TAILQ_ENTRY(fd_softc) sc_drivechain;
+ int sc_ops; /* I/O ops since last switch */
+ struct buf sc_q; /* head of buf chain */
+};
+
+/* floppy driver configuration */
+int fdprobe __P((struct device *, void *, void *));
+void fdattach __P((struct device *, struct device *, void *));
+
+struct cfattach fd_ca = {
+ sizeof(struct fd_softc), fdprobe, fdattach
+};
+
+struct cfdriver fd_cd = {
+ NULL, "fd", DV_DISK
+};
+
+void fdgetdisklabel __P((struct fd_softc *));
+int fd_get_parms __P((struct fd_softc *));
+void fdstrategy __P((struct buf *));
+void fdstart __P((struct fd_softc *));
+
+struct dkdriver fddkdriver = { fdstrategy };
+
+struct fd_type *fd_nvtotype __P((char *, int, int));
+void fd_set_motor __P((struct fdc_softc *fdc, int reset));
+void fd_motor_off __P((void *arg));
+void fd_motor_on __P((void *arg));
+int fdcresult __P((struct fdc_softc *fdc));
+int out_fdc __P((int iobase, u_char x));
+void fdcstart __P((struct fdc_softc *fdc));
+void fdcstatus __P((struct device *dv, int n, char *s));
+void fdctimeout __P((void *arg));
+void fdcpseudointr __P((void *arg));
+int fdcintr __P((void *));
+void fdcretry __P((struct fdc_softc *fdc));
+void fdfinish __P((struct fd_softc *fd, struct buf *bp));
+
+int
+fdcprobe(parent, match, aux)
+ struct device *parent;
+ void *match, *aux;
+{
+ register struct mainbus_attach_args *mb = aux;
+ int iobase = mb->mb_iobase;
+
+ /* reset */
+ outb(iobase + fdout, 0);
+ delay(100);
+ outb(iobase + fdout, FDO_FRST);
+
+ /* see if it can handle a command */
+ if (out_fdc(iobase, NE7CMD_SPECIFY) < 0)
+ return 0;
+ out_fdc(iobase, 0xdf);
+ out_fdc(iobase, 6/*2*/); /* Don't remember why - mark */
+
+#ifdef NEWCONFIG
+ if (iobase == IOBASEUNK || ia->ia_drq == DRQUNK)
+ return 0;
+
+ if (ia->ia_irq == IRQUNK) {
+ ia->ia_irq = isa_discoverintr(fdcforceintr, aux);
+ if (ia->ia_irq == IRQNONE)
+ return 0;
+
+ /* reset it again */
+ outb(iobase + fdout, 0);
+ delay(100);
+ outb(iobase + fdout, FDO_FRST);
+ }
+#endif
+
+ mb->mb_iosize = FDC_NPORT;
+ return 1;
+}
+
+#ifdef NEWCONFIG
+void
+fdcforceintr(aux)
+ void *aux;
+{
+ struct mainbus_attach_args *mb = aux;
+ int iobase = mb->mb_iobase;
+
+ /* the motor is off; this should generate an error with or
+ without a disk drive present */
+ out_fdc(iobase, NE7CMD_SEEK);
+ out_fdc(iobase, 0);
+ out_fdc(iobase, 0);
+}
+#endif
+
+/*
+ * Arguments passed between fdcattach and fdprobe.
+ */
+struct fdc_attach_args {
+ int fa_drive;
+ struct fd_type *fa_deftype;
+};
+
+/*
+ * Print the location of a disk drive (called just before attaching the
+ * the drive). If `fdc' is not NULL, the drive was found but was not
+ * in the system config file; print the drive name as well.
+ * Return QUIET (config_find ignores this if the device was configured) to
+ * avoid printing `fdN not configured' messages.
+ */
+int
+fdprint(aux, fdc)
+ void *aux;
+ char *fdc;
+{
+ register struct fdc_attach_args *fa = aux;
+
+ if (!fdc)
+ printf(" drive %d", fa->fa_drive);
+ return QUIET;
+}
+
+void
+fdcattach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct fdc_softc *fdc = (void *)self;
+ struct mainbus_attach_args *mb = aux;
+ struct fdc_attach_args fa;
+ int type;
+
+ fdc->sc_iobase = mb->mb_iobase;
+ fdc->sc_drq = mb->mb_iobase + mb->mb_drq;
+ fdc->sc_state = DEVIDLE;
+ TAILQ_INIT(&fdc->sc_drives);
+
+ printf("\n");
+
+/*#ifdef NEWCONFIG
+ at_setup_dmachan(fdc->sc_drq, FDC_MAXIOSIZE);
+ isa_establish(&fdc->sc_id, &fdc->sc_dev);
+#endif*/
+
+ fdc->sc_ih.ih_func = fdcintr;
+ fdc->sc_ih.ih_arg = fdc;
+ fdc->sc_ih.ih_level = IPL_BIO;
+ fdc->sc_ih.ih_name = "fdc";
+ if (irq_claim(mb->mb_irq, &fdc->sc_ih))
+ panic("Cannot claim IRQ %d for fdc%d\n", mb->mb_irq, parent->dv_unit);
+
+ /*
+ * The NVRAM info only tells us about the first two disks on the
+ * `primary' floppy controller.
+ */
+/* if (fdc->sc_dev.dv_unit == 0)
+ type = mc146818_read(NULL, NVRAM_DISKETTE);
+ else
+ type = -1;*/
+
+ type = 0x10;
+
+ /* physical limit: four drives per controller. */
+ for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) {
+ if (type >= 0 && fa.fa_drive < 2)
+ fa.fa_deftype = fd_nvtotype(fdc->sc_dev.dv_xname,
+ type, fa.fa_drive);
+ else
+ fa.fa_deftype = NULL; /* unknown */
+ (void)config_found(self, (void *)&fa, fdprint);
+ }
+}
+
+int
+fdprobe(parent, match, aux)
+ struct device *parent;
+ void *match, *aux;
+{
+ struct fdc_softc *fdc = (void *)parent;
+ struct cfdata *cf = match;
+ struct fdc_attach_args *fa = aux;
+ int drive = fa->fa_drive;
+ int iobase = fdc->sc_iobase;
+ int n;
+
+ if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != drive)
+ return 0;
+ /*
+ * XXX
+ * This is to work around some odd interactions between this driver
+ * and SMC Ethernet cards.
+ */
+
+ /* Don't need this for arm32 port but leave for the time being (it won't hurt) */
+
+ if (cf->cf_loc[0] == -1 && drive >= 2)
+ return 0;
+
+ /* select drive and turn on motor */
+ outb(iobase + fdout, drive | FDO_FRST | FDO_MOEN(drive));
+ /* wait for motor to spin up */
+ delay(250000);
+ out_fdc(iobase, NE7CMD_RECAL);
+ out_fdc(iobase, drive);
+ /* wait for recalibrate */
+ delay(2000000);
+ out_fdc(iobase, NE7CMD_SENSEI);
+ n = fdcresult(fdc);
+#ifdef FD_DEBUG
+ {
+ int i;
+ printf("fdprobe: status");
+ for (i = 0; i < n; i++)
+ printf(" %x", fdc->sc_status[i]);
+ printf("\n");
+ }
+#endif
+ if (n != 2 || (fdc->sc_status[0] & 0xf8) != 0x20)
+ return 0;
+ /* turn off motor */
+ outb(iobase + fdout, FDO_FRST);
+
+ return 1;
+}
+
+/*
+ * Controller is working, and drive responded. Attach it.
+ */
+void
+fdattach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct fdc_softc *fdc = (void *)parent;
+ struct fd_softc *fd = (void *)self;
+ struct fdc_attach_args *fa = aux;
+ struct fd_type *type = fa->fa_deftype;
+ int drive = fa->fa_drive;
+
+ /* XXX Allow `flags' to override device type? */
+
+ if (type)
+ printf(": %s %d cyl, %d head, %d sec\n", type->name,
+ type->tracks, type->heads, type->sectrac);
+ else
+ printf(": density unknown\n");
+
+ fd->sc_cylin = -1;
+ fd->sc_drive = drive;
+ fd->sc_deftype = type;
+ fdc->sc_fd[drive] = fd;
+
+ /*
+ * Initialize and attach the disk structure.
+ */
+ fd->sc_dk.dk_name = fd->sc_dev.dv_xname;
+ fd->sc_dk.dk_driver = &fddkdriver;
+ disk_attach(&fd->sc_dk);
+
+#ifdef NEWCONFIG
+ /* XXX Need to do some more fiddling with sc_dk. */
+ dk_establish(&fd->sc_dk, &fd->sc_dev);
+#endif
+ /* Needed to power off if the motor is on when we halt. */
+ fd->sc_sdhook = shutdownhook_establish(fd_motor_off, fd);
+}
+
+/*
+ * Translate nvram type into internal data structure. Return NULL for
+ * none/unknown/unusable.
+ */
+struct fd_type *
+fd_nvtotype(fdc, nvraminfo, drive)
+ char *fdc;
+ int nvraminfo, drive;
+{
+ int type;
+
+ type = (drive == 0 ? nvraminfo : nvraminfo << 4) & 0xf0;
+ switch (type) {
+/* case 0x00 :
+ return NULL;*/
+ case 0x10 :
+ return &fd_types[0];
+ default:
+ printf("%s: drive %d: unknown device type 0x%x\n",
+ fdc, drive, type);
+ return NULL;
+ }
+}
+
+inline struct fd_type *
+fd_dev_to_type(fd, dev)
+ struct fd_softc *fd;
+ dev_t dev;
+{
+ int type = FDTYPE(dev);
+
+ if (type > (sizeof(fd_types) / sizeof(fd_types[0])))
+ return NULL;
+ return type ? &fd_types[type - 1] : fd->sc_deftype;
+}
+
+void
+fdstrategy(bp)
+ register struct buf *bp; /* IO operation to perform */
+{
+ struct fd_softc *fd;
+ int unit = FDUNIT(bp->b_dev);
+ int sz;
+ int s;
+
+/* printf("fdstrategy: bp=%08x\n", bp);*/
+
+ /* Valid unit, controller, and request? */
+ if (unit >= fd_cd.cd_ndevs ||
+ (fd = fd_cd.cd_devs[unit]) == 0 ||
+ bp->b_blkno < 0 ||
+ (bp->b_bcount % FDC_BSIZE) != 0) {
+ bp->b_error = EINVAL;
+ goto bad;
+ }
+
+ /* If it's a null transfer, return immediately. */
+ if (bp->b_bcount == 0)
+ goto done;
+
+ sz = howmany(bp->b_bcount, FDC_BSIZE);
+
+ if (bp->b_blkno + sz > fd->sc_type->size) {
+ sz = fd->sc_type->size - bp->b_blkno;
+ if (sz == 0) {
+ /* If exactly at end of disk, return EOF. */
+ bp->b_resid = bp->b_bcount;
+ goto done;
+ }
+ if (sz < 0) {
+ /* If past end of disk, return EINVAL. */
+ bp->b_error = EINVAL;
+ goto bad;
+ }
+ /* Otherwise, truncate request. */
+ bp->b_bcount = sz << DEV_BSHIFT;
+ }
+
+ bp->b_cylin = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE) / fd->sc_type->seccyl;
+
+#ifdef FD_DEBUG
+ printf("fdstrategy: b_blkno %d b_bcount %d blkno %d cylin %d sz %d\n",
+ bp->b_blkno, bp->b_bcount, fd->sc_blkno, bp->b_cylin, sz);
+#endif
+
+ /* Queue transfer on drive, activate drive and controller if idle. */
+ s = splbio();
+ disksort(&fd->sc_q, bp);
+ untimeout(fd_motor_off, fd); /* a good idea */
+ /* Instrumentation. */
+ disk_busy(&fd->sc_dk);
+ if (!fd->sc_q.b_active)
+ fdstart(fd);
+#ifdef DIAGNOSTIC
+ else {
+ struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
+ if (fdc->sc_state == DEVIDLE) {
+ printf("fdstrategy: controller inactive\n");
+ fdcstart(fdc);
+ }
+ }
+#endif
+ splx(s);
+ return;
+
+bad:
+ bp->b_flags |= B_ERROR;
+done:
+ /* Toss transfer; we're done early. */
+ biodone(bp);
+}
+
+void
+fdstart(fd)
+ struct fd_softc *fd;
+{
+ struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
+ int active = fdc->sc_drives.tqh_first != 0;
+
+/* printf("fdstart:\n");*/
+
+ /* Link into controller queue. */
+ fd->sc_q.b_active = 1;
+ TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
+
+ /* Instrumentation. */
+/* disk_busy(&fd->sc_dk);*/
+
+ /* If controller not already active, start it. */
+ if (!active)
+ fdcstart(fdc);
+}
+
+void
+fdfinish(fd, bp)
+ struct fd_softc *fd;
+ struct buf *bp;
+{
+ struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
+
+ /*
+ * Move this drive to the end of the queue to give others a `fair'
+ * chance. We only force a switch if N operations are completed while
+ * another drive is waiting to be serviced, since there is a long motor
+ * startup delay whenever we switch.
+ */
+ if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) {
+ fd->sc_ops = 0;
+ TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
+ if (bp->b_actf) {
+ TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
+ } else
+ fd->sc_q.b_active = 0;
+ }
+ bp->b_resid = fd->sc_bcount;
+ fd->sc_skip = 0;
+ fd->sc_q.b_actf = bp->b_actf;
+
+/* printf("fdfinish: fd=%08x buf=%08x busy=%d\n", (u_int)fd, (u_int)bp, fd->sc_dk.dk_busy);*/
+
+ disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid));
+
+ biodone(bp);
+ /* turn off motor 5s from now */
+ timeout(fd_motor_off, fd, 5 * hz);
+ fdc->sc_state = DEVIDLE;
+}
+
+int
+fdread(dev, uio)
+ dev_t dev;
+ struct uio *uio;
+{
+
+ return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio));
+}
+
+int
+fdwrite(dev, uio)
+ dev_t dev;
+ struct uio *uio;
+{
+
+ return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio));
+}
+
+void
+fd_set_motor(fdc, reset)
+ struct fdc_softc *fdc;
+ int reset;
+{
+ struct fd_softc *fd;
+ u_char status;
+ int n;
+
+ if (fd = fdc->sc_drives.tqh_first)
+ status = fd->sc_drive;
+ else
+ status = 0;
+ if (!reset)
+ status |= FDO_FRST | FDO_FDMAEN;
+ for (n = 0; n < 4; n++)
+ if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR))
+ status |= FDO_MOEN(n);
+ outb(fdc->sc_iobase + fdout, status);
+}
+
+void
+fd_motor_off(arg)
+ void *arg;
+{
+ struct fd_softc *fd = arg;
+ int s;
+
+ s = splbio();
+ fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
+ fd_set_motor((struct fdc_softc *)fd->sc_dev.dv_parent, 0);
+ splx(s);
+}
+
+void
+fd_motor_on(arg)
+ void *arg;
+{
+ struct fd_softc *fd = arg;
+ struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
+ int s;
+
+ s = splbio();
+ fd->sc_flags &= ~FD_MOTOR_WAIT;
+ if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT))
+ (void) fdcintr(fdc);
+ splx(s);
+}
+
+int
+fdcresult(fdc)
+ struct fdc_softc *fdc;
+{
+ int iobase = fdc->sc_iobase;
+ u_char i;
+ int j = 100000,
+ n = 0;
+
+ for (; j; j--) {
+ i = inb(iobase + fdsts) & (NE7_DIO | NE7_RQM | NE7_CB);
+ if (i == NE7_RQM)
+ return n;
+ if (i == (NE7_DIO | NE7_RQM | NE7_CB)) {
+ if (n >= sizeof(fdc->sc_status)) {
+ log(LOG_ERR, "fdcresult: overrun\n");
+ return -1;
+ }
+ fdc->sc_status[n++] = inb(iobase + fddata);
+ }
+ }
+ log(LOG_ERR, "fdcresult: timeout\n");
+ return -1;
+}
+
+int
+out_fdc(iobase, x)
+ int iobase;
+ u_char x;
+{
+ int i = 100000;
+
+ while ((inb(iobase + fdsts) & NE7_DIO) && i-- > 0);
+ if (i <= 0)
+ return -1;
+ while ((inb(iobase + fdsts) & NE7_RQM) == 0 && i-- > 0);
+ if (i <= 0)
+ return -1;
+ outb(iobase + fddata, x);
+ return 0;
+}
+
+int
+fdopen(dev, flags)
+ dev_t dev;
+ int flags;
+{
+ int unit;
+ struct fd_softc *fd;
+ struct fd_type *type;
+
+ unit = FDUNIT(dev);
+ if (unit >= fd_cd.cd_ndevs)
+ return ENXIO;
+ fd = fd_cd.cd_devs[unit];
+ if (fd == 0)
+ return ENXIO;
+ type = fd_dev_to_type(fd, dev);
+ if (type == NULL)
+ return ENXIO;
+
+ if ((fd->sc_flags & FD_OPEN) != 0 &&
+ fd->sc_type != type)
+ return EBUSY;
+
+ fd->sc_type = type;
+ fd->sc_cylin = -1;
+ fd->sc_flags |= FD_OPEN;
+
+ return 0;
+}
+
+int
+fdclose(dev, flags)
+ dev_t dev;
+ int flags;
+{
+ struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
+
+ fd->sc_flags &= ~FD_OPEN;
+ return 0;
+}
+
+void
+fdcstart(fdc)
+ struct fdc_softc *fdc;
+{
+
+#ifdef DIAGNOSTIC
+ /* only got here if controller's drive queue was inactive; should
+ be in idle state */
+ if (fdc->sc_state != DEVIDLE) {
+ printf("fdcstart: not idle\n");
+ return;
+ }
+#endif
+ (void) fdcintr(fdc);
+}
+
+void
+fdcstatus(dv, n, s)
+ struct device *dv;
+ int n;
+ char *s;
+{
+ struct fdc_softc *fdc = (void *)dv->dv_parent;
+ int iobase = fdc->sc_iobase;
+
+ if (n == 0) {
+ out_fdc(fdc->sc_iobase, NE7CMD_SENSEI);
+ (void) fdcresult(fdc);
+ n = 2;
+ }
+
+ printf("%s: %s", dv->dv_xname, s);
+
+ switch (n) {
+ case 0:
+ printf("\n");
+ break;
+ case 2:
+ printf(" (st0 %b cyl %d)\n",
+ fdc->sc_status[0], NE7_ST0BITS,
+ fdc->sc_status[1]);
+ break;
+ case 7:
+ printf(" (st0 %b st1 %b st2 %b cyl %d head %d sec %d)\n",
+ fdc->sc_status[0], NE7_ST0BITS,
+ fdc->sc_status[1], NE7_ST1BITS,
+ fdc->sc_status[2], NE7_ST2BITS,
+ fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
+ break;
+#ifdef DIAGNOSTIC
+ default:
+ printf("\nfdcstatus: weird size");
+ break;
+#endif
+ }
+}
+
+void
+fdctimeout(arg)
+ void *arg;
+{
+ struct fdc_softc *fdc = arg;
+ struct fd_softc *fd = fdc->sc_drives.tqh_first;
+ int s;
+
+ s = splbio();
+ fdcstatus(&fd->sc_dev, 0, "timeout");
+
+ if (fd->sc_q.b_actf)
+ fdc->sc_state++;
+ else
+ fdc->sc_state = DEVIDLE;
+
+ (void) fdcintr(fdc);
+ splx(s);
+}
+
+void
+fdcpseudointr(arg)
+ void *arg;
+{
+ int s;
+
+ /* Just ensure it has the right spl. */
+ s = splbio();
+ (void) fdcintr(arg);
+ splx(s);
+}
+
+int
+fdcintr(arg)
+ void *arg;
+{
+ struct fdc_softc *fdc = arg;
+#define st0 fdc->sc_status[0]
+#define cyl fdc->sc_status[1]
+ struct fd_softc *fd;
+ struct buf *bp;
+ int iobase = fdc->sc_iobase;
+ int read, head, trac, sec, i, s, nblks;
+ struct fd_type *type;
+
+loop:
+ /* Is there a drive for the controller to do a transfer with? */
+ fd = fdc->sc_drives.tqh_first;
+ if (fd == NULL) {
+ fdc->sc_state = DEVIDLE;
+ return 1;
+ }
+
+ /* Is there a transfer to this drive? If not, deactivate drive. */
+ bp = fd->sc_q.b_actf;
+ if (bp == NULL) {
+ fd->sc_ops = 0;
+ TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
+ fd->sc_q.b_active = 0;
+ goto loop;
+ }
+
+ switch (fdc->sc_state) {
+ case DEVIDLE:
+ fdc->sc_errors = 0;
+ fd->sc_skip = 0;
+ fd->sc_bcount = bp->b_bcount;
+ fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE);
+ untimeout(fd_motor_off, fd);
+ if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) {
+ fdc->sc_state = MOTORWAIT;
+ return 1;
+ }
+ if ((fd->sc_flags & FD_MOTOR) == 0) {
+ /* Turn on the motor, being careful about pairing. */
+ struct fd_softc *ofd = fdc->sc_fd[fd->sc_drive ^ 1];
+ if (ofd && ofd->sc_flags & FD_MOTOR) {
+ untimeout(fd_motor_off, ofd);
+ ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
+ }
+ fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
+ fd_set_motor(fdc, 0);
+ fdc->sc_state = MOTORWAIT;
+ /* Allow .25s for motor to stabilize. */
+ timeout(fd_motor_on, fd, hz / 4);
+ return 1;
+ }
+ /* Make sure the right drive is selected. */
+ fd_set_motor(fdc, 0);
+
+ /* fall through */
+ case DOSEEK:
+ doseek:
+ if (fd->sc_cylin == bp->b_cylin)
+ goto doio;
+
+ out_fdc(iobase, NE7CMD_CONFIGURE);/* configure command */
+ out_fdc(iobase, 0);
+ out_fdc(iobase, 0x1a);
+ out_fdc(iobase, 0);
+
+ out_fdc(iobase, NE7CMD_SPECIFY);/* specify command */
+ out_fdc(iobase, fd->sc_type->steprate);
+ out_fdc(iobase, 6); /* XXX head load time == 6ms */
+
+ out_fdc(iobase, NE7CMD_SEEK); /* seek function */
+ out_fdc(iobase, fd->sc_drive); /* drive number */
+ out_fdc(iobase, bp->b_cylin * fd->sc_type->step);
+
+ fd->sc_cylin = -1;
+ fdc->sc_state = SEEKWAIT;
+ timeout(fdctimeout, fdc, 4 * hz);
+ return 1;
+
+ case DOIO:
+ doio:
+ type = fd->sc_type;
+ sec = fd->sc_blkno % type->seccyl;
+ nblks = type->seccyl - sec;
+ nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
+ nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE);
+ fd->sc_nblks = nblks;
+ fd->sc_nbytes = nblks * FDC_BSIZE;
+ head = sec / type->sectrac;
+ sec -= head * type->sectrac;
+#ifdef DIAGNOSTIC
+ {int block;
+ block = (fd->sc_cylin * type->heads + head) * type->sectrac + sec;
+ if (block != fd->sc_blkno) {
+ printf("fdcintr: block %d != blkno %d\n", block, fd->sc_blkno);
+#ifdef DDB
+ Debugger();
+#endif
+ }}
+#endif
+ read = bp->b_flags & B_READ;
+/*#ifdef NEWCONFIG
+ at_dma(read, bp->b_data + fd->sc_skip, fd->sc_nbytes,
+ fdc->sc_drq);
+#else
+ isa_dmastart(read, bp->b_data + fd->sc_skip, fd->sc_nbytes,
+ fdc->sc_drq);
+#endif*/
+ if (read)
+ fiqhandler.fh_func = floppy_read_fiq;
+ else
+ fiqhandler.fh_func = floppy_write_fiq;
+ fiqhandler.fh_r11 = nblks * FDC_BSIZE;
+ fiqhandler.fh_r12 = (int)bp->b_data + (int)fd->sc_skip;
+ fiqhandler.fh_r13 = fdc->sc_drq;
+ fiqhandler.fh_mask = 0x01;
+ if (fiq_claim(&fiqhandler) == -1)
+ panic("Cannot claim FIQ vector\n");
+
+ outb(iobase + fdctl, type->rate);
+#ifdef FD_DEBUG
+ printf("fdcintr: %s drive %d track %d head %d sec %d nblks %d\n",
+ read ? "read" : "write", fd->sc_drive, fd->sc_cylin, head,
+ sec, nblks);
+#endif
+ if (read)
+ out_fdc(iobase, NE7CMD_READ); /* READ */
+ else
+ out_fdc(iobase, NE7CMD_WRITE); /* WRITE */
+ out_fdc(iobase, (head << 2) | fd->sc_drive);
+ out_fdc(iobase, fd->sc_cylin); /* track */
+ out_fdc(iobase, head);
+ out_fdc(iobase, sec + 1); /* sector +1 */
+ out_fdc(iobase, type->secsize); /* sector size */
+ out_fdc(iobase, type->sectrac); /* sectors/track */
+ out_fdc(iobase, type->gap1); /* gap1 size */
+ out_fdc(iobase, type->datalen); /* data length */
+ fdc->sc_state = IOCOMPLETE;
+ /* allow 2 seconds for operation */
+ timeout(fdctimeout, fdc, 2 * hz);
+ return 1; /* will return later */
+
+ case SEEKWAIT:
+ untimeout(fdctimeout, fdc);
+ fdc->sc_state = SEEKCOMPLETE;
+ /* allow 1/50 second for heads to settle */
+/* timeout(fdcpseudointr, fdc, hz / 50);*/
+ return 1;
+
+ case SEEKCOMPLETE:
+ /* Make sure seek really happened. */
+ out_fdc(iobase, NE7CMD_SENSEI);
+ if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 ||
+ cyl != bp->b_cylin * fd->sc_type->step) {
+#ifdef FD_DEBUG
+ fdcstatus(&fd->sc_dev, 2, "seek failed");
+#endif
+ fdcretry(fdc);
+ goto loop;
+ }
+ fd->sc_cylin = bp->b_cylin;
+ goto doio;
+
+ case IOTIMEDOUT:
+/*#ifdef NEWCONFIG
+ at_dma_abort(fdc->sc_drq);
+#else
+ isa_dmaabort(fdc->sc_drq);
+#endif*/
+ if (fiq_release(&fiqhandler) == -1)
+ panic("Cannot release FIQ vector\n");
+ case SEEKTIMEDOUT:
+ case RECALTIMEDOUT:
+ case RESETTIMEDOUT:
+ fdcretry(fdc);
+ goto loop;
+
+ case IOCOMPLETE: /* IO DONE, post-analyze */
+ untimeout(fdctimeout, fdc);
+ if (fdcresult(fdc) != 7 || (st0 & 0xf8) != 0) {
+/*#ifdef NEWCONFIG
+ at_dma_abort(fdc->sc_drq);
+#else
+ isa_dmaabort(fdc->sc_drq);
+#endif*/
+ if (fiq_release(&fiqhandler) == -1)
+ panic("Cannot release FIQ vector\n");
+#ifdef FD_DEBUG
+ fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
+ "read failed" : "write failed");
+ printf("blkno %d nblks %d\n",
+ fd->sc_blkno, fd->sc_nblks);
+#endif
+ fdcretry(fdc);
+ goto loop;
+ }
+/*#ifdef NEWCONFIG
+ at_dma_terminate(fdc->sc_drq);
+#else
+ read = bp->b_flags & B_READ;
+ isa_dmadone(read, bp->b_data + fd->sc_skip, fd->sc_nbytes,
+ fdc->sc_drq);
+#endif*/
+ if (fiq_release(&fiqhandler) == -1)
+ panic("Cannot release FIQ vector\n");
+
+ if (fdc->sc_errors) {
+/* diskerr(bp, "fd", "soft error", LOG_PRINTF,
+ fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
+ printf("\n");*/
+ fdc->sc_errors = 0;
+ }
+ fd->sc_blkno += fd->sc_nblks;
+ fd->sc_skip += fd->sc_nbytes;
+ fd->sc_bcount -= fd->sc_nbytes;
+ if (fd->sc_bcount > 0) {
+ bp->b_cylin = fd->sc_blkno / fd->sc_type->seccyl;
+ goto doseek;
+ }
+/* printf("IOCOMPLETE:calling fdfinish fd=%08x bp=%08x blkno=%d\n", (u_int)fd, (u_int)bp, fd->sc_blkno);*/
+ fdfinish(fd, bp);
+ goto loop;
+
+ case DORESET:
+ /* try a reset, keep motor on */
+ fd_set_motor(fdc, 1);
+ delay(100);
+ fd_set_motor(fdc, 0);
+ fdc->sc_state = RESETCOMPLETE;
+ timeout(fdctimeout, fdc, hz / 2);
+ return 1; /* will return later */
+
+ case RESETCOMPLETE:
+ untimeout(fdctimeout, fdc);
+ /* clear the controller output buffer */
+ for (i = 0; i < 4; i++) {
+ out_fdc(iobase, NE7CMD_SENSEI);
+ (void) fdcresult(fdc);
+ }
+
+ /* fall through */
+ case DORECAL:
+ out_fdc(iobase, NE7CMD_RECAL); /* recalibrate function */
+ out_fdc(iobase, fd->sc_drive);
+ fdc->sc_state = RECALWAIT;
+ timeout(fdctimeout, fdc, 5 * hz);
+ return 1; /* will return later */
+
+ case RECALWAIT:
+ untimeout(fdctimeout, fdc);
+ fdc->sc_state = RECALCOMPLETE;
+ /* allow 1/30 second for heads to settle */
+/* timeout(fdcpseudointr, fdc, hz / 30);*/
+ return 1; /* will return later */
+
+ case RECALCOMPLETE:
+ out_fdc(iobase, NE7CMD_SENSEI);
+ if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
+#ifdef FD_DEBUG
+ fdcstatus(&fd->sc_dev, 2, "recalibrate failed");
+#endif
+ fdcretry(fdc);
+ goto loop;
+ }
+ fd->sc_cylin = 0;
+ goto doseek;
+
+ case MOTORWAIT:
+ if (fd->sc_flags & FD_MOTOR_WAIT)
+ return 1; /* time's not up yet */
+ goto doseek;
+
+ default:
+ fdcstatus(&fd->sc_dev, 0, "stray interrupt");
+ return 1;
+ }
+#ifdef DIAGNOSTIC
+ panic("fdcintr: impossible");
+#endif
+#undef st0
+#undef cyl
+}
+
+void
+fdcretry(fdc)
+ struct fdc_softc *fdc;
+{
+ struct fd_softc *fd;
+ struct buf *bp;
+
+ fd = fdc->sc_drives.tqh_first;
+ bp = fd->sc_q.b_actf;
+
+ switch (fdc->sc_errors) {
+ case 0:
+ /* try again */
+/* fdc->sc_state = SEEKCOMPLETE;*/
+ fdc->sc_state = DOSEEK;
+ break;
+
+ case 1: case 2: case 3:
+ /* didn't work; try recalibrating */
+ fdc->sc_state = DORECAL;
+ break;
+
+ case 4:
+ /* still no go; reset the bastard */
+ fdc->sc_state = DORESET;
+ break;
+
+ default:
+ diskerr(bp, "fd", "hard error", LOG_PRINTF,
+ fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
+ printf(" (st0 %b st1 %b st2 %b cyl %d head %d sec %d)\n",
+ fdc->sc_status[0], NE7_ST0BITS,
+ fdc->sc_status[1], NE7_ST1BITS,
+ fdc->sc_status[2], NE7_ST2BITS,
+ fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
+
+ bp->b_flags |= B_ERROR;
+ bp->b_error = EIO;
+ fdfinish(fd, bp);
+ }
+ fdc->sc_errors++;
+}
+
+int
+fdsize(dev)
+ dev_t dev;
+{
+
+ /* Swapping to floppies would not make sense. */
+ return -1;
+}
+
+int
+fddump(dev, blkno, va, size)
+ dev_t dev;
+ daddr_t blkno;
+ caddr_t va;
+ size_t size;
+{
+
+ /* Not implemented. */
+ return ENXIO;
+}
+
+int
+fdioctl(dev, cmd, addr, flag)
+ dev_t dev;
+ u_long cmd;
+ caddr_t addr;
+ int flag;
+{
+ struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
+ struct disklabel buffer;
+ int error;
+
+ switch (cmd) {
+ case DIOCGDINFO:
+ bzero(&buffer, sizeof(buffer));
+
+ buffer.d_secpercyl = fd->sc_type->seccyl;
+ buffer.d_type = DTYPE_FLOPPY;
+ buffer.d_secsize = FDC_BSIZE;
+
+ if (readdisklabel(dev, fdstrategy, &buffer, NULL) != NULL)
+ return EINVAL;
+
+ *(struct disklabel *)addr = buffer;
+ return 0;
+
+ case DIOCWLABEL:
+ if ((flag & FWRITE) == 0)
+ return EBADF;
+ /* XXX do something */
+ return 0;
+
+ case DIOCWDINFO:
+ if ((flag & FWRITE) == 0)
+ return EBADF;
+
+ error = setdisklabel(&buffer, (struct disklabel *)addr, 0, NULL);
+ if (error)
+ return error;
+
+ error = writedisklabel(dev, fdstrategy, &buffer, NULL);
+ return error;
+
+ default:
+ return ENOTTY;
+ }
+
+#ifdef DIAGNOSTIC
+ panic("fdioctl: impossible");
+#endif
+}
+
+
+#include "rd.h"
+#if NRD > 0
+
+#include <dev/ramdisk.h>
+
+int
+load_ramdisc_from_floppy(rd, dev)
+ struct rd_conf *rd;
+ dev_t dev;
+{
+ struct buf *bp;
+ int loop;
+ int s;
+ int type;
+ int floppysize;
+
+ if (major(dev) != 17)
+ return(EINVAL);
+
+ if (rd->rd_type == RD_UNCONFIGURED || rd->rd_addr == 0)
+ return(EBUSY);
+
+ type = FDTYPE(dev) - 1;
+ if (type < 0) type = 0;
+ floppysize = fd_types[type].size << (fd_types[type].secsize + 7);
+
+ if (rd->rd_size < floppysize) {
+ printf("Ramdisc not big enough for floppy image\n");
+ return(EINVAL);
+ }
+
+/* We have the ramdisk ! */
+
+ printf("Loading ramdisc : %4dK ", 0);
+
+/* obtain a buffer */
+
+ bp = geteblk(fd_types[type].sectrac * DEV_BSIZE);
+
+/* request no partition relocation by driver on I/O operations */
+
+ bp->b_dev = dev;
+
+ s = spl0();
+
+ if (fdopen(bp->b_dev, 0) != 0) {
+ brelse(bp);
+ printf("Cannot open floppy device\n");
+ return(EINVAL);
+ }
+
+ for (loop = 0;
+ loop < (floppysize / DEV_BSIZE / fd_types[type].sectrac);
+ ++loop) {
+ printf("\x08\x08\x08\x08\x08\x08%4dK ",
+ loop * fd_types[type].sectrac * DEV_BSIZE / 1024);
+ bp->b_blkno = loop * fd_types[type].sectrac;
+ bp->b_bcount = fd_types[type].sectrac * DEV_BSIZE;
+ bp->b_flags = B_BUSY | B_READ;
+ bp->b_error = 0;
+ bp->b_resid = 0;
+ fdstrategy(bp);
+
+ if (biowait(bp))
+ panic("Cannot load floppy image\n");
+
+ bcopy((caddr_t)bp->b_data, (caddr_t)rd->rd_addr
+ + loop * fd_types[type].sectrac * DEV_BSIZE,
+ fd_types[type].sectrac * DEV_BSIZE);
+ }
+ printf("\x08\x08\x08\x08\x08\x08%4dK done\n",
+ loop * fd_types[type].sectrac * DEV_BSIZE / 1024);
+
+ fdclose(bp->b_dev, 0);
+
+ brelse(bp);
+
+ splx(s);
+ return(0);
+}
+
+#endif
diff --git a/sys/arch/arm32/mainbus/fdreg.h b/sys/arch/arm32/mainbus/fdreg.h
new file mode 100644
index 00000000000..bdfd8fe2760
--- /dev/null
+++ b/sys/arch/arm32/mainbus/fdreg.h
@@ -0,0 +1,102 @@
+/* $NetBSD: fdreg.h,v 1.2 1996/03/18 20:50:02 mark Exp $ */
+
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)fdreg.h 7.1 (Berkeley) 5/9/91
+ */
+
+/*
+ * AT floppy controller registers and bitfields
+ */
+
+
+/*
+ * 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 */
+#define NE7CMD_CONFIGURE 0x13
+
+/* registers */
+#define fdout 8 /* 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_MOEN(n) ((1 << n) * 0x10) /* motor enable */
+
+#define fdsts 16 /* NEC 765 Main Status Register (R) */
+#define fddata 20 /* NEC 765 Data Register (R/W) */
+
+#define fdctl 28 /* 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 28 /* Digital Input Register (R) */
+#define FDI_DCHG 0x80 /* diskette has been changed */
+
+#define FDC_BSIZE 512
+#define FDC_NPORT 32
+#define FDC_MAXIOSIZE NBPG /* XXX should be MAXBSIZE */
diff --git a/sys/arch/arm32/mainbus/iic.c b/sys/arch/arm32/mainbus/iic.c
new file mode 100644
index 00000000000..334b6030443
--- /dev/null
+++ b/sys/arch/arm32/mainbus/iic.c
@@ -0,0 +1,403 @@
+/* $NetBSD: iic.c,v 1.1 1996/04/19 19:49:03 mark Exp $ */
+
+/*
+ * Copyright (c) 1994-1996 Mark Brinicombe.
+ * Copyright (c) 1994 Brini.
+ * All rights reserved.
+ *
+ * This code is derived from software written for Brini by Mark Brinicombe
+ *
+ * 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 Mark Brinicombe.
+ * 4. The name of the company 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 BRINI ``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 BRINI 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.
+ *
+ * RiscBSD kernel project
+ *
+ * iic.c
+ *
+ * Routines to communicate with IIC devices
+ *
+ * Created : 13/10/94
+ *
+ * Based of kate/display/iiccontrol.c
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/conf.h>
+#include <sys/malloc.h>
+#include <sys/device.h>
+
+#include <machine/io.h>
+#include <machine/iomd.h>
+#include <machine/katelib.h>
+#include <machine/cpu.h>
+#include <machine/irqhandler.h>
+#include <machine/iic.h>
+#include <arm32/mainbus/mainbus.h>
+
+/* Local function prototypes */
+
+static int iic_getack __P((void));
+static void iic_write_bit __P((int bit));
+static int iic_write_byte __P((u_char value));
+static u_char iic_read_byte __P((void));
+static void iic_start_bit __P((void));
+static void iic_stop_bit __P((void));
+
+struct iic_softc {
+ struct device sc_dev;
+ int sc_flags;
+#define IIC_BROKEN 1
+#define IIC_OPEN 2
+#define IIC_BUSY 4
+};
+
+void iicattach __P((struct device *parent, struct device *self, void *aux));
+int iicmatch __P((struct device *parent, void *match, void *aux));
+
+/*
+ * Main entry to IIC driver.
+ */
+
+int
+iic_control(address, buffer, count)
+ u_char address;
+ u_char *buffer;
+ int count;
+{
+ int loop;
+
+/* Send the start bit */
+
+ iic_start_bit();
+
+/* Send the address */
+
+ if (!iic_write_byte(address)) {
+ iic_stop_bit();
+ return(-1);
+ }
+
+/* Read or write the data as required */
+
+ if ((address & 1) == 0) {
+/* Write bytes */
+ for (loop = 0; loop < count; ++loop) {
+ if (!iic_write_byte(buffer[loop])) {
+ iic_stop_bit();
+ return(-1);
+ }
+ }
+ }
+ else {
+/* Read bytes */
+ for (loop = 0; loop < count; ++loop) {
+ buffer[loop] = iic_read_byte();
+
+/* Send final acknowledge */
+
+ if (loop == (count - 1))
+ iic_write_bit(1);
+ else
+ iic_write_bit(0);
+ }
+ }
+
+/* Send stop bit */
+
+ iic_stop_bit();
+
+ return(0);
+}
+
+
+static int
+iic_getack()
+{
+ u_int oldirqstate;
+ int ack;
+
+ iic_set_state(1, 0);
+ oldirqstate = disable_interrupts(I32_bit);
+ iic_set_state_and_ack(1, 1);
+ ack = ReadByte(IOMD_IOCR);
+ iic_set_state(1, 0);
+ restore_interrupts(oldirqstate);
+
+ return((ack & 1) == 0);
+}
+
+
+static void
+iic_write_bit(bit)
+ int bit;
+{
+ u_int oldirqstate;
+
+ iic_set_state(bit, 0);
+ oldirqstate = disable_interrupts(I32_bit);
+ iic_set_state_and_ack(bit, 1);
+ iic_set_state(bit, 0);
+ restore_interrupts(oldirqstate);
+}
+
+
+static int
+iic_write_byte(value)
+ u_char value;
+{
+ int loop;
+ int bit;
+
+ for (loop = 0x80; loop != 0; loop = loop >> 1) {
+ bit = ((value & loop) != 0);
+ iic_write_bit(bit);
+ }
+
+ return(iic_getack());
+}
+
+
+static u_char
+iic_read_byte()
+{
+ int loop;
+ u_char byte;
+ u_int oldirqstate;
+
+ iic_set_state(1,0);
+
+ byte = 0;
+
+ for (loop = 0; loop < 8; ++loop) {
+ oldirqstate = disable_interrupts(I32_bit);
+ iic_set_state_and_ack(1, 1);
+ byte = (byte << 1) + (ReadByte(IOMD_IOCR) & 1);
+ iic_set_state(1, 0);
+ restore_interrupts(oldirqstate);
+ }
+
+ return(byte);
+}
+
+
+static void
+iic_start_bit()
+{
+ iic_set_state(1, 1);
+ iic_set_state(0, 1);
+ iic_delay(10);
+ iic_set_state(0, 0);
+}
+
+
+static void
+iic_stop_bit()
+{
+ iic_set_state(0, 1);
+ iic_set_state(1, 1);
+}
+
+
+struct cfattach iic_ca = {
+ sizeof(struct iic_softc), iicmatch, iicattach
+};
+
+struct cfdriver iic_cd = {
+ NULL, "iic", DV_DULL, 0
+};
+
+int
+iicmatch(parent, match, aux)
+ struct device *parent;
+ void *match;
+ void *aux;
+{
+ int id;
+
+/* Make sure we have an IOMD we understand */
+
+ id = ReadByte(IOMD_ID0) | (ReadByte(IOMD_ID1) << 8);
+
+/* So far I only know about this IOMD */
+
+ switch (id) {
+ case RPC600_IOMD_ID:
+ case RC7500_IOC_ID:
+ return(1);
+ break;
+ default:
+ printf("iic: Unknown IOMD id=%04x", id);
+ break;
+ }
+
+ return(0);
+}
+
+int
+iicprint(aux, name)
+ void *aux;
+ char *name;
+{
+ struct iicbus_attach_args *ib = aux;
+
+ if (!name) {
+ if (ib->ib_addr)
+ printf(" addr 0x%02x", ib->ib_addr);
+ }
+
+/* XXXX print flags */
+ return (QUIET);
+}
+
+
+int
+iicsubmatch(parent, match, aux)
+ struct device *parent;
+ void *match;
+ void *aux;
+{
+ struct cfdata *cf = match;
+ struct iicbus_attach_args *ib = aux;
+
+ if (cf->cf_fstate == FSTATE_STAR)
+ panic("eekkk, I'm stuffed");
+
+ ib->ib_addr = cf->cf_loc[0];
+
+ if (ib->ib_addr == -1)
+ return(0);
+
+ return((*cf->cf_attach->ca_match)(parent, match, aux));
+}
+
+void
+iicattach(parent, self, aux)
+ struct device *parent;
+ struct device *self;
+ void *aux;
+{
+ struct iicbus_attach_args iaa;
+
+ printf("\n");
+
+ while (config_found_sm(self, &iaa, iicprint, iicsubmatch));
+}
+
+
+int
+iicopen(dev, flag, mode, p)
+ dev_t dev;
+ int flag;
+ int mode;
+ struct proc *p;
+{
+ struct iic_softc *sc;
+ int unit = minor(dev);
+
+ if (unit >= iic_cd.cd_ndevs)
+ return(ENXIO);
+
+ sc = iic_cd.cd_devs[unit];
+
+ if (!sc) return(ENXIO);
+
+ if (sc->sc_flags & IIC_OPEN) return(EBUSY);
+
+ sc->sc_flags |= IIC_OPEN;
+
+ return(0);
+}
+
+
+int
+iicclose(dev, flag, mode, p)
+ dev_t dev;
+ int flag;
+ int mode;
+ struct proc *p;
+{
+ int unit = minor(dev);
+ struct iic_softc *sc = iic_cd.cd_devs[unit];
+
+ sc->sc_flags &= ~IIC_OPEN;
+
+ return(0);
+}
+
+
+int
+iicread(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ int unit = minor(dev);
+ struct iic_softc *sc = iic_cd.cd_devs[unit];
+
+ return(ENXIO);
+}
+
+
+int
+iicwrite(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ int unit = minor(dev);
+ struct iic_softc *sc = iic_cd.cd_devs[unit];
+
+ return(ENXIO);
+}
+
+
+int
+iicioctl(dev, cmd, data, flag, p)
+ dev_t dev;
+ int cmd;
+ caddr_t data;
+ int flag;
+ struct proc *p;
+{
+ struct iic_softc *sc = iic_cd.cd_devs[minor(dev)];
+
+/*
+ switch (cmd) {
+ case IICIOC_CONTROL:
+ if (iiccontrol() != 0) {
+ return(EIO);
+ }
+ return(0);
+ }
+*/
+
+ return(EINVAL);
+}
+
+/* End of iic.c */
diff --git a/sys/arch/arm32/mainbus/iic_asm.S b/sys/arch/arm32/mainbus/iic_asm.S
new file mode 100644
index 00000000000..10ceb8a0238
--- /dev/null
+++ b/sys/arch/arm32/mainbus/iic_asm.S
@@ -0,0 +1,239 @@
+/* $NetBSD: iic_asm.S,v 1.1 1996/04/19 19:49:04 mark Exp $ */
+
+/*
+ * Copyright (c) 1994-1996 Mark Brinicombe.
+ * Copyright (c) 1994 Brini.
+ * All rights reserved.
+ *
+ * This code is derived from software written for Brini by Mark Brinicombe
+ *
+ * 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 Mark Brinicombe.
+ * 4. The name of the company 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 BRINI ``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 BRINI 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.
+ *
+ * RiscBSD kernel project
+ *
+ * iic.s
+ *
+ * Low level routines to with IIC devices
+ *
+ * Created : 13/10/94
+ *
+ * Based of kate/display/iic.s
+ */
+
+#include <machine/cpu.h>
+#include <machine/iomd.h>
+
+#define IIC_BITDELAY 10
+
+sp .req r13
+lr .req r14
+pc .req r15
+
+.text
+
+ .global _iic_set_state
+
+_iic_set_state:
+/*
+ * Parameters
+ * r0 - IIC data bit
+ * r1 - IIC clock bit
+ */
+
+/* Store temporary register */
+/* stmfd sp!, {r4}*/
+
+/*
+ * Mask the data and clock bits
+ * Since these routines are only called from iiccontrol.c this is not
+ * really needed
+ */
+ and r0, r0, #0x00000001
+ and r1, r1, #0x00000001
+
+/* Get address of IOMD control register */
+
+ mov r2, #(IOMD_BASE)
+
+/* Get the current CPSR */
+/* mrs r4, cpsr_all
+ orr r3, r4, #(I32_bit | F32_bit)
+ msr cpsr_all, r3
+*/
+
+ IRQdisable
+
+/* Get current value of control register */
+
+ ldrb r3, [r2, #(IOMD_IOCR - IOMD_BASE)]
+
+/* Preserve non-IIC bits */
+
+ bic r3, r3, #0x00000003
+ orr r3, r3, #0x000000c0
+
+/* Set the IIC clock and data bits */
+
+ orr r3, r3, r0
+ orr r3, r3, r1, lsl #1
+
+/* Store the new value of control register */
+
+ strb r3, [r2, #(IOMD_IOCR - IOMD_BASE)]
+
+/* Restore CPSR state */
+/* msr cpsr_all, r4 */
+
+ IRQenable
+
+/* Restore temporary register */
+/* ldmfd sp!, {r4} */
+
+/* Pause a bit */
+
+ mov r0, #(IIC_BITDELAY)
+
+/* Exit via iic_delay routine */
+ b _iic_delay
+
+
+ .global _iic_set_state_and_ack
+
+_iic_set_state_and_ack:
+/*
+ * Parameters
+ * r0 - IIC data bit
+ * r1 - IIC clock bit
+ */
+/* Store temporary register */
+/* stmfd sp!, {r4} */
+
+/*
+ * Mask the data and clock bits
+ * Since these routines are only called from iiccontrol.c this is not
+ * really needed
+ */
+
+ and r0, r0, #0x00000001
+ and r1, r1, #0x00000001
+
+/* Get address of IOMD control register */
+
+ mov r2, #(IOMD_BASE)
+
+/* Get the current CPSR */
+/* mrs r4, cpsr_all
+ orr r3, r4, #(I32_bit | F32_bit)
+ msr cpsr_all, r3
+*/
+ IRQdisable
+
+/* Get current value of control register */
+
+ ldrb r3, [r2, #(IOMD_IOCR - IOMD_BASE)]
+
+/* Preserve non-IIC bits */
+
+ bic r3, r3, #0x00000003
+ orr r3, r3, #0x000000c0
+
+/* Set the IIC clock and data bits */
+
+ orr r3, r3, r0
+ orr r3, r3, r1, lsl #1
+
+/* Store the new value of control register */
+
+ strb r3, [r2, #(IOMD_IOCR - IOMD_BASE)]
+
+iic_set_state_and_ack_loop:
+ ldrb r3, [r2, #(IOMD_IOCR - IOMD_BASE)]
+ tst r3, #0x00000002
+ beq iic_set_state_and_ack_loop
+
+/* Restore CPSR state */
+/* msr cpsr_all, r4 */
+
+ IRQenable
+
+/* Restore temporary register */
+/* ldmfd sp!, {r4} */
+
+/* Pause a bit */
+
+ mov r0, #(IIC_BITDELAY)
+
+/* Exit via iic_delay routine */
+ b _iic_delay
+
+
+ .global _iic_delay
+
+_iic_delay:
+/*
+ * Parameters
+ * r0 - time to wait
+ */
+
+/* Load address of IOMD */
+
+ mov r2, #(IOMD_BASE)
+
+/* Latch current value of timer 1 */
+
+ strb r2, [r2, #(IOMD_T0LATCH - IOMD_BASE)]
+
+/* Get the latched value */
+
+ ldrb r1, [r2, #(IOMD_T0LOW - IOMD_BASE)]
+
+/* Loop until timer reaches end value */
+
+iic_delay_loop:
+
+/* Latch the current value of timer1 */
+
+ strb r2, [r2, #(IOMD_T0LATCH - IOMD_BASE)]
+
+/* Get the latched value */
+
+ ldrb r3, [r2, #(IOMD_T0LOW - IOMD_BASE)]
+
+/* Loop until timer reached expected value */
+
+ teq r3, r1
+ movne r1, r3
+ beq iic_delay_loop
+
+ subs r0, r0, #0x00000001
+ bne iic_delay_loop
+
+/* Exit */
+ mov pc, lr
+
+/* End of iic_asm.S */
diff --git a/sys/arch/arm32/mainbus/kbd.c b/sys/arch/arm32/mainbus/kbd.c
new file mode 100644
index 00000000000..3b85bdba7e8
--- /dev/null
+++ b/sys/arch/arm32/mainbus/kbd.c
@@ -0,0 +1,1357 @@
+/* $NetBSD: kbd.c,v 1.7 1996/03/28 21:55:15 mark Exp $ */
+
+/*
+ * Copyright (c) 1994 Mark Brinicombe.
+ * Copyright (c) 1994 Brini.
+ * All rights reserved.
+ *
+ * This code is derived from software written for Brini by Mark Brinicombe
+ *
+ * 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 Brini.
+ * 4. The name of the company 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 BRINI ``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 BRINI 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.
+ *
+ * RiscBSD kernel project
+ *
+ * kbd.c
+ *
+ * Keyboard driver functions
+ *
+ * Created : 09/10/94
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/conf.h>
+#include <sys/proc.h>
+#include <sys/reboot.h>
+#include <sys/device.h>
+#include <sys/ioctl.h>
+#include <sys/malloc.h>
+#include <sys/tty.h>
+#include <sys/vnode.h>
+#include <sys/select.h>
+#include <sys/fcntl.h>
+#include <sys/signalvar.h>
+#include <sys/time.h>
+
+#include <machine/irqhandler.h>
+#include <machine/iomd.h>
+#include <machine/vidc.h>
+#include <machine/katelib.h>
+#include <machine/kbd.h>
+#include <arm32/mainbus/mainbus.h>
+#include "vt.h"
+#include "kbd.h"
+
+/* Declare global variables */
+
+/* Declare external variables */
+
+/* Local function prototypes */
+
+/* Now for the main code */
+
+/* Define the key_struct structure */
+
+typedef struct {
+ int base_code; /* Base ASCII code */
+ int shift_code; /* Shifted ASCII code */
+ int ctrl_code; /* CTRL code */
+ int alt_code; /* Alt code */
+ int flags; /* Flags field */
+} key_struct;
+
+/* Define mappings for each possible code */
+
+key_struct keys[256] = {
+/* 0x00 - 0x0f */
+ { 0x00, 0x00, 0x00, 0x00, 0x80 },
+ { 0x89, 0x99, 0x00, 0x489, 0x00 },
+ { 0x8a, 0x9a, 0x00, 0x00, 0x00 },
+ { 0x85, 0x95, 0x00, 0x485, 0x00 },
+ { 0x83, 0x93, 0x00, 0x483, 0x00 },
+ { 0x81, 0x91, 0x00, 0x481, 0x00 },
+ { 0x82, 0x92, 0x00, 0x482, 0x00 },
+ { 0x8c, 0x9c, 0x00, 0x48c, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x88, 0x98, 0x00, 0x488, 0x00 },
+ { 0x86, 0x96, 0x00, 0x486, 0x00 },
+ { 0x84, 0x94, 0x00, 0x484, 0x00 },
+ { 0x09, 0x09, 0x09, 0x09, 0x00 },
+ { 0x60, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+
+/* 0x10 - 0x1f */
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x84 },
+ { 0x00, 0x00, 0x00, 0x00, 0x82 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x81 },
+ { 0x71, 0x51, 0x11, 0x00, 0x40 },
+ { 0x31, 0x21, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x7a, 0x5a, 0x1a, 0x00, 0x40 },
+ { 0x73, 0x53, 0x13, 0x00, 0x40 },
+ { 0x61, 0x41, 0x01, 0x00, 0x40 },
+ { 0x77, 0x57, 0x17, 0x00, 0x40 },
+ { 0x32, 0x22, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+
+/* 0x20 - 0x2f */
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x63, 0x43, 0x03, 0x00, 0x40 },
+ { 0x78, 0x58, 0x18, 0x00, 0x40 },
+ { 0x64, 0x44, 0x04, 0x00, 0x40 },
+ { 0x65, 0x45, 0x05, 0x00, 0x40 },
+ { 0x34, 0x24, 0x00, 0x00, 0x00 },
+ { 0x33, 0x23, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x20, 0x20, 0x20, 0x20, 0x00 },
+ { 0x76, 0x56, 0x16, 0x00, 0x40 },
+ { 0x66, 0x46, 0x06, 0x00, 0x40 },
+ { 0x74, 0x54, 0x14, 0x00, 0x40 },
+ { 0x72, 0x52, 0x12, 0x00, 0x40 },
+ { 0x35, 0x25, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+
+/* 0x30 - 0x3f */
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x6e, 0x4e, 0x0e, 0x00, 0x40 },
+ { 0x62, 0x42, 0x02, 0x00, 0x40 },
+ { 0x68, 0x48, 0x08, 0x00, 0x40 },
+ { 0x67, 0x47, 0x07, 0x00, 0x40 },
+ { 0x79, 0x59, 0x19, 0x00, 0x40 },
+ { 0x36, 0x5e, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x6d, 0x4d, 0x0d, 0x00, 0x40 },
+ { 0x6a, 0x4a, 0x0a, 0x00, 0x40 },
+ { 0x75, 0x55, 0x15, 0x00, 0x40 },
+ { 0x37, 0x26, 0x00, 0x00, 0x00 },
+ { 0x38, 0x2a, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+
+/* 0x40 - 0x4f */
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x2c, 0x3c, 0x00, 0x00, 0x00 },
+ { 0x6b, 0x4b, 0x0b, 0x00, 0x40 },
+ { 0x69, 0x49, 0x09, 0x00, 0x40 },
+ { 0x6f, 0x4f, 0x0f, 0x00, 0x40 },
+ { 0x30, 0x29, 0x00, 0x00, 0x00 },
+ { 0x39, 0x28, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x2e, 0x3e, 0x00, 0x00, 0x00 },
+ { 0x2f, 0x3f, 0x00, 0x00, 0x00 },
+ { 0x6c, 0x4c, 0x0c, 0x00, 0x40 },
+ { 0x3b, 0x3a, 0x00, 0x00, 0x00 },
+ { 0x70, 0x50, 0x10, 0x00, 0x40 },
+ { 0x2d, 0x5f, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+
+/* 0x50 - 0x5f */
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x27, 0x40, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x5b, 0x7b, 0x00, 0x00, 0x00 },
+ { 0x3d, 0x2b, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0xa0 },
+ { 0x00, 0x00, 0x00, 0x00, 0x82 },
+ { 0x0d, 0x0d, 0x0d, 0x00, 0x00 },
+ { 0x5d, 0x7d, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x23, 0x7e, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+
+/* 0x60 - 0x6f */
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x5c, 0x7c, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x08, 0x7f, 0x08, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x31, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x34, 0x00, 0x00, 0x00, 0x00 },
+ { 0x37, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+
+/* 0x70 - 0x7f */
+ { 0x30, 0x00, 0x00, 0x00, 0x00 },
+ { 0x2e, 0x00, 0x00, 0x00, 0x00 },
+ { 0x32, 0x00, 0x00, 0x00, 0x00 },
+ { 0x35, 0x00, 0x00, 0x00, 0x00 },
+ { 0x36, 0x00, 0x00, 0x00, 0x00 },
+ { 0x38, 0x00, 0x00, 0x00, 0x00 },
+ { 0x1b, 0x1b, 0x21b, 0x1b, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x90 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x2b, 0x00, 0x00, 0x22b, 0x00 },
+ { 0x33, 0x00, 0x00, 0x00, 0x00 },
+ { 0x2d, 0x00, 0x00, 0x22d, 0x00 },
+ { 0x2a, 0x00, 0x00, 0x00, 0x00 },
+ { 0x39, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x88 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+
+/* 0x80 - 0x8f */
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x87, 0x97, 0x00, 0x487, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+
+/* 0x90 - 0x9f */
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+
+/* 0xa0 - 0xaf */
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+
+/* 0xb0 - 0xbf */
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+
+/* 0xc0 - 0xcf */
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+
+/* 0xd0 - 0xdf */
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+
+/* 0xe0 - 0xef */
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+
+/* 0xf0 - 0xff */
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 }
+};
+
+/* Define mappings for each possible code */
+
+key_struct E0keys[128] = {
+
+/* 0x00 - 0x0f */
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+
+/* 0x10 - 0x1f */
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x84 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x81 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+
+/* 0x20 - 0x2f */
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+
+/* 0x30 - 0x3f */
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+
+/* 0x40 - 0x4f */
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x2f, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+
+/* 0x50 - 0x5f */
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x0d, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+
+/* 0x60 - 0x6f */
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x10b, 0x00, 0x00, 0x20b, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x102, 0x00, 0x00, 0x202, 0x00 },
+ { 0x10a, 0x00, 0x00, 0x20a, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+
+/* 0x70 - 0x7f */
+ { 0x108, 0x00, 0x00, 0x208, 0x00 },
+ { 0x109, 0x00, 0x00, 0x209, 0x00 },
+ { 0x101, 0x105, 0x00, 0x201, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x103, 0x00, 0x00, 0x203, 0x00 },
+ { 0x100, 0x104, 0x00, 0x200, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x104, 0x100, 0x00, 0x204, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x105, 0x101, 0x00, 0x205, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00 },
+};
+
+/* Special keycodes */
+
+#define KEYCODE_UP 0x100
+#define KEYCODE_DOWN 0x101
+#define KEYCODE_LEFT 0x102
+#define KEYCODE_RIGHT 0x103
+#define KEYCODE_PGUP 0x104
+#define KEYCODE_PGDN 0x105
+#define KEYCODE_INSERT 0x108
+#define KEYCODE_DELETE 0x109
+#define KEYCODE_HOME 0x10a
+#define KEYCODE_END 0x10b
+
+/* Key modifiers flags */
+
+#define MODIFIER_CTRL 0x01
+#define MODIFIER_SHIFT 0x02
+#define MODIFIER_ALT 0x04
+#define MODIFIER_MASK 0x07
+
+#define MODIFIER_CAPS 0x20
+#define MODIFIER_NUM 0x10
+#define MODIFIER_SCROLL 0x08
+#define MODIFIER_LOCK_MASK 0x38
+
+#define MODIFIER_CAPSLOCK 0x40
+#define MODIFIER_NORETURN 0x80
+
+/* Keyboard buffer variables */
+
+#define BUFFER_SIZE 32
+#define RAWKBD_BSIZE 128
+
+static int autorepeatkey = -1;
+static struct kbd_autorepeat kbdautorepeat = { 5, 20 };
+static int rawkbd_device = 0;
+int modifiers = 0;
+static int kbd_ack = 0;
+static int kbd_resend = 0;
+
+extern int pmap_debug_level;
+
+struct kbd_softc {
+ struct device sc_device;
+ irqhandler_t sc_ih;
+
+ int sc_state;
+#define RAWKBD_OPEN 0x01
+#define KBD_OPEN 0x02
+#define RAWKBD_ASLEEP 0x04
+ int sc_iobase;
+ struct clist sc_q;
+ struct selinfo sc_rsel;
+ struct proc *sc_proc;
+};
+
+#define KBDUNIT(u) (minor(u) / 2)
+#define KBDFLAG(u) (minor(u) % 2)
+
+#define KBDFLAG_RAWUNIT 0
+#define KBDFLAG_CONUNIT 1
+
+int kbdprobe __P((struct device *, void *, void *));
+void kbdattach __P((struct device *, struct device *, void *));
+
+int kbdopen __P((dev_t, int, int, struct proc *));
+int kbdclose __P((dev_t, int, int, struct proc *));
+int kbdread __P((dev_t, struct uio *, int));
+int kbdselect __P((dev_t, int, struct proc *));
+int kbdioctl __P((dev_t, int, caddr_t, int, struct proc *));
+
+void kbdinit __P((struct kbd_softc *sc));
+void kbdsetleds __P((int /*leds*/));
+
+int PollKeyboard __P((int));
+int kbddecodekey __P((struct kbd_softc *, int));
+int kbdintr __P((struct kbd_softc *));
+
+void autorepeatstart __P((void *));
+void autorepeat __P((void *));
+
+struct cfattach kbd_ca = {
+ sizeof(struct kbd_softc), kbdprobe, kbdattach
+};
+
+struct cfdriver kbd_cd = {
+ NULL, "kbd", DV_TTY
+};
+
+
+int
+kbdprobe(parent, match, aux)
+ struct device *parent;
+ void *match;
+ void *aux;
+{
+/* struct mainbus_attach_args *mb = aux;*/
+ int id;
+
+/* Make sure we have an IOMD we understand */
+
+ id = ReadByte(IOMD_ID0) | (ReadByte(IOMD_ID1) << 8);
+
+/* So far I only know about this IOMD */
+
+ switch (id) {
+ case RPC600_IOMD_ID:
+ case RC7500_IOC_ID:
+ return(1);
+ break;
+ default:
+ printf("kbd: Unknown IOMD id=%04x", id);
+ break;
+ }
+
+ return(0);
+}
+
+
+void
+kbdattach(parent, self, aux)
+ struct device *parent;
+ struct device *self;
+ void *aux;
+{
+ struct kbd_softc *sc = (void *)self;
+ struct mainbus_attach_args *mb = aux;
+
+ sc->sc_iobase = mb->mb_iobase;
+
+ kbdinit(sc);
+
+ printf("\n");
+}
+
+
+int
+kbdopen(dev, flag, mode, p)
+ dev_t dev;
+ int flag;
+ int mode;
+ struct proc *p;
+{
+ struct kbd_softc *sc;
+ int unit = KBDUNIT(dev);
+
+ if (unit >= kbd_cd.cd_ndevs)
+ return(ENXIO);
+
+ sc = kbd_cd.cd_devs[unit];
+
+ if (!sc) return(ENXIO);
+
+ switch (KBDFLAG(dev)) {
+ case KBDFLAG_RAWUNIT :
+ if (sc->sc_state & RAWKBD_OPEN)
+ return(EBUSY);
+ sc->sc_state |= RAWKBD_OPEN;
+ if (clalloc(&sc->sc_q, RAWKBD_BSIZE, 0) == -1)
+ return(ENOMEM);
+ sc->sc_proc = p;
+ rawkbd_device = 1;
+ break;
+ case KBDFLAG_CONUNIT :
+ if (sc->sc_state & KBD_OPEN)
+ return(EBUSY);
+ sc->sc_state |= KBD_OPEN;
+ break;
+ }
+
+/* Kill any active autorepeat */
+
+ untimeout(autorepeatstart, &autorepeatkey);
+ untimeout(autorepeat, &autorepeatkey);
+
+ return(0);
+}
+
+
+int
+kbdclose(dev, flag, mode, p)
+ dev_t dev;
+ int flag;
+ int mode;
+ struct proc *p;
+{
+ int unit = KBDUNIT(dev);
+ struct kbd_softc *sc = kbd_cd.cd_devs[unit];
+
+ switch (KBDFLAG(dev)) {
+ case KBDFLAG_RAWUNIT :
+ if (!(sc->sc_state & RAWKBD_OPEN))
+ return(EINVAL);
+ sc->sc_state &= ~RAWKBD_OPEN;
+ clfree(&sc->sc_q);
+ sc->sc_proc = NULL;
+ rawkbd_device = 0;
+ break;
+ case KBDFLAG_CONUNIT :
+ if (!(sc->sc_state & KBD_OPEN))
+ return(EINVAL);
+ sc->sc_state &= ~KBD_OPEN;
+ break;
+ }
+
+ return(0);
+}
+
+
+int
+kbdread(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ struct kbd_softc *sc = kbd_cd.cd_devs[KBDUNIT(dev)];
+ int s;
+ int error = 0;
+ size_t length;
+ u_char buffer[128];
+
+ if (KBDFLAG(dev) == KBDFLAG_CONUNIT)
+ return(ENXIO);
+
+ /* Block until keyboard activity occured. */
+
+ s = spltty();
+ while (sc->sc_q.c_cc == 0) {
+ if (flag & IO_NDELAY) {
+ splx(s);
+ return EWOULDBLOCK;
+ }
+ sc->sc_state |= RAWKBD_ASLEEP;
+ if ((error = tsleep((caddr_t)sc, PZERO | PCATCH, "kbdread", 0))) {
+ sc->sc_state &= (~RAWKBD_ASLEEP);
+ splx(s);
+ return error;
+ }
+ }
+ splx(s);
+
+ /* Transfer as many chunks as possible. */
+
+ while (sc->sc_q.c_cc > 0 && uio->uio_resid > 0) {
+ length = min(sc->sc_q.c_cc, uio->uio_resid);
+ if (length > sizeof(buffer))
+ length = sizeof(buffer);
+
+ /* Remove a small chunk from the input queue. */
+ (void) q_to_b(&sc->sc_q, buffer, length);
+
+ /* Copy the data to the user process. */
+ if ((error = (uiomove(buffer, length, uio))))
+ break;
+ }
+ return error;
+}
+
+int
+kbdselect(dev, rw, p)
+ dev_t dev;
+ int rw;
+ struct proc *p;
+{
+ struct kbd_softc *sc = kbd_cd.cd_devs[KBDUNIT(dev)];
+ int s;
+ int ret;
+
+ if (KBDFLAG(dev) == KBDFLAG_CONUNIT)
+ return(ENXIO);
+
+ if (rw == FWRITE)
+ return 0;
+
+ s = spltty();
+ if (!sc->sc_q.c_cc) {
+ selrecord(p, &sc->sc_rsel);
+ ret = 0;
+ } else
+ ret = 1;
+ splx(s);
+ return ret;
+}
+
+
+int
+kbdioctl(dev, cmd, data, flag, p)
+ dev_t dev;
+ int cmd;
+ caddr_t data;
+ int flag;
+ struct proc *p;
+{
+/* struct kbd_softc *sc = kbd_cd.cd_devs[KBDUNIT(dev)];*/
+ struct kbd_autorepeat *kbdar = (void *)data;
+ int *leds = (int *)data;
+ int s;
+
+ switch (cmd) {
+ case KBD_GETAUTOREPEAT:
+/* if (KBDFLAG(dev) == KBDFLAG_RAWUNIT)
+ return(EINVAL);*/
+
+ *kbdar = kbdautorepeat;
+ break;
+ case KBD_SETAUTOREPEAT:
+/* if (KBDFLAG(dev) == KBDFLAG_RAWUNIT)
+ return(EINVAL);*/
+ s = spltty();
+ kbdautorepeat = *kbdar;
+ if (kbdautorepeat.ka_rate < 1)
+ kbdautorepeat.ka_rate = 1;
+ if (kbdautorepeat.ka_rate > 50)
+ kbdautorepeat.ka_rate = 50;
+ if (kbdautorepeat.ka_delay > 50)
+ kbdautorepeat.ka_delay = 50;
+ if (kbdautorepeat.ka_delay < 1)
+ kbdautorepeat.ka_delay = 1;
+ (void)splx(s);
+ break;
+ case KBD_SETLEDS:
+ kbdsetleds(*leds);
+ break;
+ default:
+ return(ENXIO);
+ }
+ return(0);
+}
+
+
+void
+kbdsetleds(leds)
+ int leds;
+{
+ int loop;
+
+ if ((ReadByte(IOMD_KBDCR) & 0x80)) {
+ WriteByte(IOMD_KBDDAT, 0xed);
+ loop = 10000;
+ while ((ReadByte(IOMD_KBDCR) & 0x40) && loop > 0)
+ --loop;
+ if ((ReadByte(IOMD_KBDCR) & 0x80)) {
+ WriteByte(IOMD_KBDDAT, leds);
+ loop = 10000;
+ while ((ReadByte(IOMD_KBDCR) & 0x40) && loop > 0)
+ --loop;
+ }
+ }
+}
+
+
+void
+kbdsetstate(state)
+ int state;
+{
+ modifiers = state & MODIFIER_LOCK_MASK;
+}
+
+
+int
+kdbgetstate()
+{
+ return(modifiers);
+}
+
+
+void
+kbdinit(sc)
+ struct kbd_softc *sc;
+{
+ sc->sc_ih.ih_func = kbdintr;
+ sc->sc_ih.ih_arg = sc;
+ sc->sc_ih.ih_level = IPL_TTY;
+ sc->sc_ih.ih_name = "kbd rx";
+ if (irq_claim(IRQ_KBDRX, &sc->sc_ih))
+ panic("Cannot claim IRQ for kbd%d\n", sc->sc_device.dv_unit);
+
+ modifiers = 0;
+ kbdsetleds((modifiers >> 3) & 7);
+}
+
+
+int
+getkey_polled()
+{
+ int code;
+ int key;
+ int up;
+ key_struct *ks;
+ int s;
+
+ s = splhigh();
+
+ key = 0;
+
+ do {
+ while ((ReadByte(IOMD_KBDCR) & (1<<5)) == 0) ;
+
+/* Read the IOMD keyboard register and process the key */
+
+ code = PollKeyboard(ReadByte(IOMD_KBDDAT));
+
+ if (code != 0) {
+ up = (code & 0x100);
+ key = code & 0xff;
+
+/* printf("code=%04x mod=%04x\n", code, modifiers);*/
+
+/* By default we use the main keycode lookup table */
+
+ ks = keys;
+
+/* If we have an E0 or E1 sqeuence we use the extended table */
+
+ if (code > 0x1ff)
+ ks = E0keys;
+
+/* Is the key a temporary modifier ? */
+
+ if (ks[key].flags & MODIFIER_MASK) {
+ if (up)
+ modifiers &= ~ks[key].flags;
+ else
+ modifiers |= ks[key].flags;
+ key = 0;
+ continue;
+ }
+
+/* Is the key a locking modifier ? */
+
+ if (ks[key].flags & MODIFIER_LOCK_MASK) {
+ if (!up) {
+ modifiers ^= ks[key].flags;
+ kbdsetleds((modifiers >> 3) & 7);
+ }
+ key = 0;
+ continue;
+ }
+
+/* Lookup the correct key code */
+
+ if (modifiers & 0x01)
+ key = ks[key].ctrl_code;
+ else if (modifiers & 0x02)
+ key = ks[key].shift_code;
+ else if (modifiers & 0x04)
+ key = ks[key].alt_code;
+ else
+ key = ks[key].base_code;
+
+ if (modifiers & MODIFIER_CAPS) {
+ if ((key >= 'A' && key <= 'Z') || (key >= 'a' && key <= 'z'))
+ key ^= 0x20;
+ }
+
+ if (up)
+ key = 0;
+ if (!up && key >= 0x200) {
+
+#if (NVT > 0)
+ if ((key & ~0x0f) == 0x480)
+ console_switch((key & 0x0f) - 1);
+ else
+#endif
+ switch (key) {
+#if (NVT > 0)
+ case 0x201:
+ console_scrollforward();
+ break;
+ case 0x200:
+ console_scrollback();
+ break;
+#endif
+ default:
+ break;
+ }
+ key = 0;
+ }
+ }
+ } while (key == 0);
+
+ if (key == '\r')
+ key = '\n';
+
+ splx(s);
+ return(key);
+}
+
+
+/* Keyboard IRQ handler */
+
+int
+kbdintr(sc)
+ struct kbd_softc *sc;
+{
+ int key;
+
+/* Read the IOMD keyboard register and process the key */
+
+ key = PollKeyboard(ReadByte(IOMD_KBDDAT));
+
+/* If we have a raw keycode convert it to an ASCII code */
+
+ if (key != 0)
+ kbddecodekey(sc, key);
+ return(1);
+}
+
+
+/* Flags used to decode the raw keys */
+
+#define FLAG_KEYUP 0x01
+#define FLAG_E0 0x02
+#define FLAG_E1 0x04
+
+static int flags = 0;
+
+/*
+ * This function is now misnamed.
+ * It processes the raw key codes from the keyboard and generates
+ * a unique code that can be decoded with the key translation array.
+ */
+
+int
+PollKeyboard(code)
+ int code;
+{
+/* printf("%02x.", code);*/
+
+/*
+ * Set the keyup flag if this is the release code.
+ */
+
+ if (code == 0xf0) {
+ flags |= FLAG_KEYUP;
+ return(0);
+ }
+
+/* If it is a special code ignore it */
+
+ if (code == 0xff || code == 0x00) {
+ flags = 0;
+ return(0);
+ }
+
+/* If it is a resend code note it down */
+
+ if (code == 0xfe) {
+ printf("kbd:resend\n");
+ kbd_resend = 1;
+ return(0);
+ }
+
+/* If it is an ack code note it down */
+
+ if (code == 0xfa) {
+/* printf("kbd:ack\n");*/
+ kbd_ack = 1;
+ return(0);
+ }
+
+/* Flag the start of an E0 sequence. */
+
+ if (code == 0xe0) {
+ flags |= FLAG_E0;
+ return(0);
+ }
+
+/* Flag the start of an E1 sequence. */
+
+ if (code == 0xe1) {
+ flags |= FLAG_E1;
+ return(0);
+ }
+
+/* Ignore any other invalid codes */
+
+ if (code > 0x8f) {
+ flags = 0;
+ return(0);
+ }
+
+/* printf("%02x:%02x.", code, flags);*/
+
+/* Mark the code appropriately if it is part of an E0 sequence */
+
+ if (flags & FLAG_E0) {
+ flags &= ~FLAG_E0;
+ if (code == 0x12) {
+ flags &= ~FLAG_KEYUP;
+ return(0);
+ }
+ code |= 0x200;
+ }
+
+/* Mark the key if it is the upcode */
+
+ if (flags & FLAG_KEYUP) {
+ flags &= ~FLAG_KEYUP;
+ code |= 0x100;
+ }
+
+/* Mark the code appropriately if it is part of an E1 sequence */
+
+ if (flags & FLAG_E1) {
+ if ((code & 0xff) == 0x14) {
+ return(0);
+ }
+ flags &= ~FLAG_E1;
+ code |= 0x400;
+ flags &= ~FLAG_KEYUP;
+ }
+
+ return(code);
+}
+
+
+/*
+ * This routine decodes the unique keycode and generates an ASCII code
+ * if necessary.
+ */
+
+int
+kbddecodekey(sc, code)
+ struct kbd_softc *sc;
+ int code;
+{
+ key_struct *ks;
+ int up;
+ int key;
+
+ console_unblank();
+
+/* Do we have the raw kbd device open ... */
+
+ if (rawkbd_device == 1 && code != 0) {
+ struct kbd_data buffer;
+ int s;
+
+ /* Add this event to the queue. */
+
+ buffer.keycode = code;
+ microtime(&buffer.event_time);
+ s=spltty();
+ (void) b_to_q((char *)&buffer, sizeof(buffer), &sc->sc_q);
+ splx(s);
+ selwakeup(&sc->sc_rsel);
+
+ if (sc->sc_state & RAWKBD_ASLEEP) {
+ sc->sc_state &= ~RAWKBD_ASLEEP;
+ wakeup((caddr_t)sc);
+ }
+
+ psignal(sc->sc_proc, SIGIO);
+ return(1);
+ }
+
+ up = (code & 0x100);
+ key = code & 0xff;
+
+/* By default we use the main keycode lookup table */
+
+ ks = keys;
+
+/* If we have an E0 or E1 sqeuence we use the extended table */
+
+ if (code > 0x1ff)
+ ks = E0keys;
+
+/* Is the key a temporary modifier ? */
+
+ if (ks[key].flags & MODIFIER_MASK) {
+ if (up)
+ modifiers &= ~ks[key].flags;
+ else
+ modifiers |= ks[key].flags;
+ return(0);
+ }
+
+/* Is the key a locking modifier ? */
+
+ if (ks[key].flags & MODIFIER_LOCK_MASK) {
+ if (!up) {
+ modifiers ^= ks[key].flags;
+ kbdsetleds((modifiers >> 3) & 7);
+ }
+ return(0);
+ }
+
+/* Lookup the correct key code */
+
+ if (modifiers & 0x01)
+ key = ks[key].ctrl_code;
+ else if (modifiers & 0x02)
+ key = ks[key].shift_code;
+ else if (modifiers & 0x04)
+ key = ks[key].alt_code;
+ else
+ key = ks[key].base_code;
+
+ if (modifiers & MODIFIER_CAPS) {
+ if ((key >= 'A' && key <= 'Z') || (key >= 'a' && key <= 'z'))
+ key ^= 0x20;
+ }
+
+/* If no valid code the key is not yet mapped so report error */
+
+#ifdef DEBUG_TERM
+/* if (key == 0) {
+ char err[80];
+
+ sprintf(err, "\n\rUnknown keycode %04x\n\r", code);
+ dprintf(err);
+
+ }*/
+#endif
+
+/* If we have an ASCII code insert it into the keyboard buffer */
+
+ if (!up && key != 0) {
+ if (key >= 0x200) {
+
+ untimeout(autorepeatstart, &autorepeatkey);
+ untimeout(autorepeat, &autorepeatkey);
+ autorepeatkey = -1;
+#if (NVT > 0)
+ if ((key & ~0x0f) == 0x480)
+ console_switch((key & 0x0f) - 1);
+ else
+#endif
+ switch (key) {
+ case 0x22b:
+ pmap_debug(pmap_debug_level + 1);
+ break;
+ case 0x22d:
+ pmap_debug(pmap_debug_level - 1);
+ break;
+#if (NVT > 0)
+ case 0x201:
+ console_scrollforward();
+ break;
+ case 0x200:
+ console_scrollback();
+ break;
+ case 0x202:
+ console_switchdown();
+ break;
+ case 0x203:
+ console_switchup();
+ break;
+#endif
+ case 0x204:
+ --kbdautorepeat.ka_rate;
+ if (kbdautorepeat.ka_rate < 1)
+ kbdautorepeat.ka_rate = 1;
+ break;
+ case 0x205:
+ ++kbdautorepeat.ka_rate;
+ if (kbdautorepeat.ka_rate > 50)
+ kbdautorepeat.ka_rate = 50;
+ break;
+ case 0x20a:
+ ++kbdautorepeat.ka_delay;
+ if (kbdautorepeat.ka_delay > 50)
+ kbdautorepeat.ka_delay = 50;
+ break;
+ case 0x20b:
+ --kbdautorepeat.ka_delay;
+ if (kbdautorepeat.ka_delay < 1)
+ kbdautorepeat.ka_delay = 1;
+ break;
+#ifdef DDB
+ case 0x208:
+ Debugger();
+ break;
+#endif
+ case 0x21b:
+ printf("Kernel interruption\n");
+ boot(RB_HALT);
+ break;
+ case 0x209:
+ printf("Kernel interruption - nosync\n");
+ boot(RB_NOSYNC | RB_HALT);
+ break;
+
+ default:
+ printf("Special key %04x\n", key);
+ break;
+ }
+ } else {
+ if (physconkbd(key) == 0 && rawkbd_device == 0) {
+ if (autorepeatkey != key) {
+ untimeout(autorepeatstart, &autorepeatkey);
+ untimeout(autorepeat, &autorepeatkey);
+ autorepeatkey = key;
+ timeout(autorepeatstart, &autorepeatkey, hz/kbdautorepeat.ka_delay);
+ }
+ }
+
+ return(1);
+ }
+ } else {
+ untimeout(autorepeatstart, &autorepeatkey);
+ untimeout(autorepeat, &autorepeatkey);
+ autorepeatkey = -1;
+ }
+ return(0);
+}
+
+
+void
+autorepeatstart(key)
+ void *key;
+{
+ physconkbd(*((int *)key));
+ timeout(autorepeat, key, hz/kbdautorepeat.ka_rate);
+}
+
+
+void
+autorepeat(key)
+ void *key;
+{
+ physconkbd(*((int *)key));
+ timeout(autorepeat, key, hz/kbdautorepeat.ka_rate);
+}
+
+/* End of kbd.c */
diff --git a/sys/arch/arm32/mainbus/lpt.c b/sys/arch/arm32/mainbus/lpt.c
new file mode 100644
index 00000000000..35ff77c3f0d
--- /dev/null
+++ b/sys/arch/arm32/mainbus/lpt.c
@@ -0,0 +1,1314 @@
+/* $NetBSD: lpt.c,v 1.6 1996/03/28 21:52:47 mark Exp $ */
+
+/*
+ * Copyright (c) 1995 Mark Brinicombe
+ * Copyright (c) 1993, 1994 Charles Hannum.
+ * Copyright (c) 1990 William F. Jolitz, TeleMuse
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This software is a component of "386BSD" developed by
+ * William F. Jolitz, TeleMuse.
+ * 4. Neither the name of the developer nor the name "386BSD"
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS A COMPONENT OF 386BSD DEVELOPED BY WILLIAM F. JOLITZ
+ * AND IS INTENDED FOR RESEARCH AND EDUCATIONAL PURPOSES ONLY. THIS
+ * SOFTWARE SHOULD NOT BE CONSIDERED TO BE A COMMERCIAL PRODUCT.
+ * THE DEVELOPER URGES THAT USERS WHO REQUIRE A COMMERCIAL PRODUCT
+ * NOT MAKE USE OF THIS WORK.
+ *
+ * FOR USERS WHO WISH TO UNDERSTAND THE 386BSD SYSTEM DEVELOPED
+ * BY WILLIAM F. JOLITZ, WE RECOMMEND THE USER STUDY WRITTEN
+ * REFERENCES SUCH AS THE "PORTING UNIX TO THE 386" SERIES
+ * (BEGINNING JANUARY 1991 "DR. DOBBS JOURNAL", USA AND BEGINNING
+ * JUNE 1991 "UNIX MAGAZIN", GERMANY) BY WILLIAM F. JOLITZ AND
+ * LYNNE GREER JOLITZ, AS WELL AS OTHER BOOKS ON UNIX AND THE
+ * ON-LINE 386BSD USER MANUAL BEFORE USE. A BOOK DISCUSSING THE INTERNALS
+ * OF 386BSD ENTITLED "386BSD FROM THE INSIDE OUT" WILL BE AVAILABLE LATE 1992.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE DEVELOPER BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from:$NetBSD: lpt.c,v 1.6 1996/03/28 21:52:47 mark Exp $
+ */
+
+/*
+ * Device Driver for AT parallel printer port
+ */
+/*
+ * PLIP driver code added by Mark Brinicombe
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/buf.h>
+#include <sys/kernel.h>
+#include <sys/ioctl.h>
+#include <sys/uio.h>
+#include <sys/device.h>
+#include <sys/syslog.h>
+
+#if defined(INET) && defined(PLIP)
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <net/if_types.h>
+#include <net/netisr.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#include <netinet/if_ether.h>
+#include "bpfilter.h"
+#if NBPFILTER > 0
+#include <sys/time.h>
+#include <net/bpf.h>
+#endif
+#endif
+
+#include <machine/cpu.h>
+#include <machine/katelib.h>
+#include <machine/irqhandler.h>
+#include <machine/io.h>
+#include <arm32/mainbus/lptreg.h>
+#include <arm32/mainbus/mainbus.h>
+
+#define TIMEOUT hz*16 /* wait up to 16 seconds for a ready */
+#define STEP hz/4
+
+#define LPTPRI (PZERO+8)
+#define LPT_BSIZE 1024
+
+#if defined(INET) && defined(PLIP)
+#ifndef PLIPMTU /* MTU for the plip# interfaces */
+#if defined(COMPAT_PLIP10)
+#define PLIPMTU 1600
+#else
+#define PLIPMTU (ETHERMTU - ifp->if_hdrlen)
+#endif
+#endif
+
+#ifndef PLIPMXSPIN1 /* DELAY factor for the plip# interfaces */
+#define PLIPMXSPIN1 2000 /* Spinning for remote intr to happen */
+#endif
+
+#ifndef PLIPMXSPIN2 /* DELAY factor for the plip# interfaces */
+#define PLIPMXSPIN2 6000 /* Spinning for remote handshake to happen */
+#endif
+
+#ifndef PLIPMXERRS /* Max errors before !RUNNING */
+#define PLIPMXERRS 100
+#endif
+#ifndef PLIPMXRETRY
+#define PLIPMXRETRY 10 /* Max number of retransmits */
+#endif
+#ifndef PLIPRETRY
+#define PLIPRETRY hz/10 /* Time between retransmits */
+#endif
+#endif
+
+#if !defined(DEBUG) || !defined(notdef)
+#define lprintf
+#else
+#define lprintf if (lptdebug) printf
+int lptdebug = 1;
+#endif
+
+struct lpt_softc {
+ struct device sc_dev;
+ irqhandler_t sc_ih;
+
+ size_t sc_count;
+ struct buf *sc_inbuf;
+ u_char *sc_cp;
+ int sc_spinmax;
+ int sc_iobase;
+ int sc_irq;
+ u_char sc_state;
+#define LPT_OPEN 0x01 /* device is open */
+#define LPT_OBUSY 0x02 /* printer is busy doing output */
+#define LPT_INIT 0x04 /* waiting to initialize for open */
+#define LPT_PLIP 0x08 /* busy with PLIP */
+ u_char sc_flags;
+#define LPT_AUTOLF 0x20 /* automatic LF on CR */
+#define LPT_NOPRIME 0x40 /* don't prime on open */
+#define LPT_NOINTR 0x80 /* do not use interrupt */
+ u_char sc_control;
+ u_char sc_laststatus;
+#if defined(INET) && defined(PLIP)
+ struct arpcom sc_arpcom;
+ u_char *sc_ifbuf;
+ int sc_iferrs;
+ int sc_ifretry;
+#if defined(COMPAT_PLIP10)
+ u_char sc_adrcksum;
+#endif
+#endif
+};
+
+int lptprobe __P((struct device *, void *, void *));
+void lptattach __P((struct device *, struct device *, void *));
+int lptintr __P((void *));
+
+#if defined(INET) && defined(PLIP)
+/* Functions for the plip# interface */
+static void plipattach(struct lpt_softc *,int);
+static int plipioctl(struct ifnet *, u_long, caddr_t);
+static void plipstart(struct ifnet *);
+static int plipintr(struct lpt_softc *);
+#endif
+
+struct cfattach lpt_ca = {
+ sizeof(struct lpt_softc), lptprobe, lptattach
+};
+
+struct cfdriver lpt_cd = {
+ NULL, "lpt", DV_TTY
+};
+
+#define LPTUNIT(s) (minor(s) & 0x1f)
+#define LPTFLAGS(s) (minor(s) & 0xe0)
+
+#define LPS_INVERT (LPS_SELECT|LPS_NERR|LPS_NBSY|LPS_NACK)
+#define LPS_MASK (LPS_SELECT|LPS_NERR|LPS_NBSY|LPS_NACK|LPS_NOPAPER)
+#define NOT_READY() ((inb(iobase + lpt_status) ^ LPS_INVERT) & LPS_MASK)
+#define NOT_READY_ERR() not_ready(inb(iobase + lpt_status), sc)
+static int not_ready __P((u_char, struct lpt_softc *));
+
+static void lptwakeup __P((void *arg));
+static int pushbytes __P((struct lpt_softc *));
+
+/*
+ * Internal routine to lptprobe to do port tests of one byte value.
+ */
+int
+lpt_port_test(port, data, mask)
+ int port;
+ u_char data, mask;
+{
+ int timeout;
+ u_char temp;
+
+ data &= mask;
+ outb(port, data);
+ timeout = 1000;
+ do {
+ delay(10);
+ temp = inb(port) & mask;
+ } while (temp != data && --timeout);
+ lprintf("lpt: port=0x%x out=0x%x in=0x%x timeout=%d\n", port, data,
+ temp, timeout);
+ return (temp == data);
+}
+
+/*
+ * Logic:
+ * 1) You should be able to write to and read back the same value
+ * to the data port. Do an alternating zeros, alternating ones,
+ * walking zero, and walking one test to check for stuck bits.
+ *
+ * 2) You should be able to write to and read back the same value
+ * to the control port lower 5 bits, the upper 3 bits are reserved
+ * per the IBM PC technical reference manauls and different boards
+ * do different things with them. Do an alternating zeros, alternating
+ * ones, walking zero, and walking one test to check for stuck bits.
+ *
+ * Some printers drag the strobe line down when the are powered off
+ * so this bit has been masked out of the control port test.
+ *
+ * XXX Some printers may not like a fast pulse on init or strobe, I
+ * don't know at this point, if that becomes a problem these bits
+ * should be turned off in the mask byte for the control port test.
+ *
+ * 3) Set the data and control ports to a value of 0
+ */
+int
+lptprobe(parent, match, aux)
+ struct device *parent;
+ void *match, *aux;
+{
+ struct mainbus_attach_args *mb = aux;
+ int iobase = mb->mb_iobase;
+ int port;
+ u_char mask, data;
+ int i;
+
+#ifdef DEBUG
+#define ABORT do {printf("lptprobe: mask %x data %x failed\n", mask, data); \
+ return 0;} while (0)
+#else
+#define ABORT return 0
+#endif
+
+ port = iobase + lpt_data;
+ mask = 0xff;
+
+ data = 0x55; /* Alternating zeros */
+ if (!lpt_port_test(port, data, mask))
+ ABORT;
+
+ data = 0xaa; /* Alternating ones */
+ if (!lpt_port_test(port, data, mask))
+ ABORT;
+
+ for (i = 0; i < CHAR_BIT; i++) { /* Walking zero */
+ data = ~(1 << i);
+ if (!lpt_port_test(port, data, mask))
+ ABORT;
+ }
+
+ for (i = 0; i < CHAR_BIT; i++) { /* Walking one */
+ data = (1 << i);
+ if (!lpt_port_test(port, data, mask))
+ ABORT;
+ }
+
+ outb(iobase + lpt_data, 0);
+ outb(iobase + lpt_control, 0);
+
+ mb->mb_iosize = LPT_NPORTS;
+ return 1;
+}
+
+void
+lptattach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct lpt_softc *sc = (void *)self;
+ struct mainbus_attach_args *mb = aux;
+ int iobase = mb->mb_iobase;
+
+ if (mb->mb_irq != IRQUNK)
+ printf("\n");
+ else
+ printf(": polled\n");
+
+ sc->sc_iobase = iobase;
+ sc->sc_irq = mb->mb_irq;
+ sc->sc_state = 0;
+ outb(iobase + lpt_control, LPC_NINIT);
+
+ if (mb->mb_irq != IRQUNK) {
+ sc->sc_ih.ih_func = lptintr;
+ sc->sc_ih.ih_arg = sc;
+#if defined(INET) && defined(PLIP)
+ sc->sc_ih.ih_level = IPL_NET;
+ sc->sc_ih.ih_name = "lpt/plip";
+ plipattach(sc, self->dv_unit);
+#else
+ sc->sc_ih.ih_level = IPL_NONE;
+ sc->sc_ih.ih_name = "lpt";
+#endif
+ if (irq_claim(mb->mb_irq, &sc->sc_ih))
+ panic("Cannot claim IRQ %d for lpt%d\n", mb->mb_irq, sc->sc_dev.dv_unit);
+
+ }
+#if defined(INET) && defined(PLIP)
+ else {
+ printf("Warning PLIP device needs IRQ driven lpt driver\n");
+ }
+#endif
+}
+
+/*
+ * Reset the printer, then wait until it's selected and not busy.
+ */
+int
+lptopen(dev, flag)
+ dev_t dev;
+ int flag;
+{
+ int unit = LPTUNIT(dev);
+ u_char flags = LPTFLAGS(dev);
+ struct lpt_softc *sc;
+ int iobase;
+ u_char control;
+ int error;
+ int spin;
+
+ if (unit >= lpt_cd.cd_ndevs)
+ return ENXIO;
+ sc = lpt_cd.cd_devs[unit];
+ if (!sc)
+ return ENXIO;
+
+ if (sc->sc_irq == IRQUNK && (flags & LPT_NOINTR) == 0)
+ return ENXIO;
+
+#ifdef DIAGNOSTIC
+ if (sc->sc_state)
+ printf("%s: stat=0x%x not zero\n", sc->sc_dev.dv_xname,
+ sc->sc_state);
+#endif
+
+ if (sc->sc_state)
+ return EBUSY;
+
+ sc->sc_state = LPT_INIT;
+ sc->sc_flags = flags;
+ lprintf("%s: open: flags=0x%x\n", sc->sc_dev.dv_xname, flags);
+ iobase = sc->sc_iobase;
+
+ if ((flags & LPT_NOPRIME) == 0) {
+ /* assert INIT for 100 usec to start up printer */
+ outb(iobase + lpt_control, LPC_SELECT);
+ delay(100);
+ }
+
+ control = LPC_SELECT | LPC_NINIT;
+ outb(iobase + lpt_control, control);
+
+ /* wait till ready (printer running diagnostics) */
+ for (spin = 0; NOT_READY_ERR(); spin += STEP) {
+ if (spin >= TIMEOUT) {
+ sc->sc_state = 0;
+ return EBUSY;
+ }
+
+ /* wait 1/4 second, give up if we get a signal */
+ if (error = tsleep((caddr_t)sc, LPTPRI | PCATCH, "lptopen",
+ STEP) != EWOULDBLOCK) {
+ sc->sc_state = 0;
+ return error;
+ }
+ }
+
+ if ((flags & LPT_NOINTR) == 0)
+ control |= LPC_IENABLE;
+ if (flags & LPT_AUTOLF)
+ control |= LPC_AUTOLF;
+ sc->sc_control = control;
+ outb(iobase + lpt_control, control);
+
+ sc->sc_inbuf = geteblk(LPT_BSIZE);
+ sc->sc_count = 0;
+ sc->sc_state = LPT_OPEN;
+
+ if ((sc->sc_flags & LPT_NOINTR) == 0)
+ lptwakeup(sc);
+
+ lprintf("%s: opened\n", sc->sc_dev.dv_xname);
+ return 0;
+}
+
+int
+not_ready(status, sc)
+ u_char status;
+ struct lpt_softc *sc;
+{
+ u_char new;
+
+ status = (status ^ LPS_INVERT) & LPS_MASK;
+ new = status & ~sc->sc_laststatus;
+ sc->sc_laststatus = status;
+
+ if (new & LPS_SELECT)
+ log(LOG_NOTICE, "%s: offline\n", sc->sc_dev.dv_xname);
+ else if (new & LPS_NOPAPER)
+ log(LOG_NOTICE, "%s: out of paper\n", sc->sc_dev.dv_xname);
+ else if (new & LPS_NERR)
+ log(LOG_NOTICE, "%s: output error\n", sc->sc_dev.dv_xname);
+
+ return status;
+}
+
+
+void
+lptwakeup(arg)
+ void *arg;
+{
+ struct lpt_softc *sc = arg;
+ int s;
+
+ s = spltty();
+ lptintr(sc);
+ splx(s);
+
+ timeout(lptwakeup, sc, STEP);
+}
+
+/*
+ * Close the device, and free the local line buffer.
+ */
+lptclose(dev, flag)
+ dev_t dev;
+ int flag;
+{
+ int unit = LPTUNIT(dev);
+ struct lpt_softc *sc = lpt_cd.cd_devs[unit];
+ int iobase = sc->sc_iobase;
+
+ if (sc->sc_count)
+ (void) pushbytes(sc);
+
+ if ((sc->sc_flags & LPT_NOINTR) == 0)
+ untimeout(lptwakeup, sc);
+
+ outb(iobase + lpt_control, LPC_NINIT);
+ sc->sc_state = 0;
+ outb(iobase + lpt_control, LPC_NINIT);
+ brelse(sc->sc_inbuf);
+
+ lprintf("%s: closed\n", sc->sc_dev.dv_xname);
+ return 0;
+}
+
+int
+pushbytes(sc)
+ struct lpt_softc *sc;
+{
+ int iobase = sc->sc_iobase;
+ int error;
+
+ if (sc->sc_flags & LPT_NOINTR) {
+ int spin, tic;
+ u_char control = sc->sc_control;
+
+ while (sc->sc_count > 0) {
+ spin = 0;
+ while (NOT_READY()) {
+ if (++spin < sc->sc_spinmax)
+ continue;
+ tic = 0;
+ /* adapt busy-wait algorithm */
+ sc->sc_spinmax++;
+ while (NOT_READY_ERR()) {
+ /* exponential backoff */
+ tic = tic + tic + 1;
+ if (tic > TIMEOUT)
+ tic = TIMEOUT;
+ error = tsleep((caddr_t)sc,
+ LPTPRI | PCATCH, "lptpsh", tic);
+ if (error != EWOULDBLOCK)
+ return error;
+ }
+ break;
+ }
+
+ outb(iobase + lpt_data, *sc->sc_cp++);
+ outb(iobase + lpt_control, control | LPC_STROBE);
+ sc->sc_count--;
+ outb(iobase + lpt_control, control);
+
+ /* adapt busy-wait algorithm */
+ if (spin*2 + 16 < sc->sc_spinmax)
+ sc->sc_spinmax--;
+ }
+ } else {
+ int s;
+
+ while (sc->sc_count > 0) {
+ /* if the printer is ready for a char, give it one */
+ if ((sc->sc_state & LPT_OBUSY) == 0) {
+ lprintf("%s: write %d\n", sc->sc_dev.dv_xname,
+ sc->sc_count);
+ s = spltty();
+ (void) lptintr(sc);
+ splx(s);
+ }
+ if (error = tsleep((caddr_t)sc, LPTPRI | PCATCH,
+ "lptwrite2", 0))
+ return error;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Copy a line from user space to a local buffer, then call putc to get the
+ * chars moved to the output queue.
+ */
+lptwrite(dev, uio)
+ dev_t dev;
+ struct uio *uio;
+{
+ struct lpt_softc *sc = lpt_cd.cd_devs[LPTUNIT(dev)];
+ size_t n;
+ int error = 0;
+
+ while (n = min(LPT_BSIZE, uio->uio_resid)) {
+ uiomove(sc->sc_cp = sc->sc_inbuf->b_data, n, uio);
+ sc->sc_count = n;
+ error = pushbytes(sc);
+ if (error) {
+ /*
+ * Return accurate residual if interrupted or timed
+ * out.
+ */
+ uio->uio_resid += sc->sc_count;
+ sc->sc_count = 0;
+ return error;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Handle printer interrupts which occur when the printer is ready to accept
+ * another char.
+ */
+int
+lptintr(arg)
+ void *arg;
+{
+ struct lpt_softc *sc = arg;
+ int iobase = sc->sc_iobase;
+
+/*printf("lptintr:\n");*/
+
+#if defined(INET) && defined(PLIP)
+ if (sc->sc_arpcom.ac_if.if_flags & IFF_UP) {
+ return(plipintr(sc));
+ }
+#endif
+
+#if 0
+ if ((sc->sc_state & LPT_OPEN) == 0)
+ return 0;
+#endif
+
+ /* is printer online and ready for output */
+ if (NOT_READY() && NOT_READY_ERR())
+ return 0;
+
+ if (sc->sc_count) {
+ u_char control = sc->sc_control;
+ /* send char */
+ outb(iobase + lpt_data, *sc->sc_cp++);
+ outb(iobase + lpt_control, control | LPC_STROBE);
+ sc->sc_count--;
+ outb(iobase + lpt_control, control);
+ sc->sc_state |= LPT_OBUSY;
+ } else
+ sc->sc_state &= ~LPT_OBUSY;
+
+ if (sc->sc_count == 0) {
+ /* none, wake up the top half to get more */
+ wakeup((caddr_t)sc);
+ }
+
+ return(1);
+}
+
+int
+lptioctl(dev, cmd, data, flag)
+ dev_t dev;
+ u_long cmd;
+ caddr_t data;
+ int flag;
+{
+ int error = 0;
+
+ switch (cmd) {
+ default:
+ error = ENODEV;
+ }
+
+ return error;
+}
+
+
+#if defined(INET) && defined(PLIP)
+
+#define PLIP_INTR_ENABLE (LPC_NINIT | LPC_SELECT | LPC_IENABLE)
+#define PLIP_INTR_DISABLE (LPC_NINIT | LPC_SELECT)
+#define PLIP_DATA (iobase + lpt_data)
+#define PLIP_STATUS (iobase + lpt_status)
+#define PLIP_CONTROL (iobase + lpt_control)
+#define PLIP_REMOTE_TRIGGER 0x08
+#define PLIP_DELAY_UNIT 50
+#if PLIP_DELAY_UNIT > 0
+#define PLIP_DELAY DELAY(PLIP_DELAY_UNIT)
+#else
+#define PLIP_DELAY
+#endif
+#define PLIP_DEBUG_RX 0x01
+#define PLIP_DEBUG_TX 0x02
+#define PLIP_DEBUG_IF 0x04
+#define PLIP_DEBUG 0x07
+#if PLIP_DEBUG != 0
+static int plip_debug = PLIP_DEBUG;
+#endif
+
+static void
+plipattach(struct lpt_softc *sc, int unit)
+{
+ struct ifnet *ifp = &sc->sc_arpcom.ac_if;
+
+ sc->sc_ifbuf = NULL;
+ ifp->if_unit = unit;
+ ifp->if_name = "plip";
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
+ ifp->if_output = ether_output;
+ ifp->if_start = plipstart;
+ ifp->if_ioctl = plipioctl;
+ ifp->if_watchdog = 0;
+
+ ifp->if_type = IFT_ETHER;
+ ifp->if_addrlen = 6;
+ ifp->if_hdrlen = 14;
+ ifp->if_mtu = PLIPMTU;
+
+ if_attach(ifp);
+ ether_ifattach(ifp);
+
+ printf("plip%d at lpt%d: mtu=%d,%d,%d", unit, unit, (int) ifp->if_mtu,
+ ifp->if_hdrlen, ifp->if_addrlen);
+ if (sizeof(struct ether_header) != 14)
+ printf(" ethhdr super kludge mode enabled\n");
+ else
+ printf("\n");
+
+#if NBPFILTER > 0
+ bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
+#endif
+}
+
+/*
+ * Process an ioctl request.
+ */
+static int
+plipioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
+{
+ struct proc *p = curproc;
+ struct lpt_softc *sc = (struct lpt_softc *) lpt_cd.cd_devs[ifp->if_unit];
+ unsigned int iobase = sc->sc_iobase;
+ struct ifaddr *ifa = (struct ifaddr *)data;
+ struct ifreq *ifr = (struct ifreq *)data;
+ int s;
+ int error = 0;
+
+#if PLIP_DEBUG > 0
+ printf("plipioctl: cmd=%08x ifp=%08x data=%08x\n", cmd, ifp, data);
+ printf("plipioctl: ifp->flags=%08x\n", ifp->if_flags);
+#endif
+
+ switch (cmd) {
+
+ case SIOCSIFFLAGS:
+ if (((ifp->if_flags & IFF_UP) == 0) &&
+ (ifp->if_flags & IFF_RUNNING)) {
+ ifp->if_flags &= ~IFF_RUNNING;
+/* Deactive the parallel port */
+#if PLIP_DEBUG != 0
+ if (plip_debug & PLIP_DEBUG_IF)
+ printf("plip: Disabling lpt irqs\n");
+#endif
+ outb(PLIP_DATA, 0x00);
+ outb(PLIP_CONTROL, PLIP_INTR_DISABLE);
+ sc->sc_state = 0;
+
+ if (sc->sc_ifbuf)
+ free(sc->sc_ifbuf, M_DEVBUF);
+
+ sc->sc_ifbuf = NULL;
+ }
+ if (((ifp->if_flags & IFF_UP)) &&
+ ((ifp->if_flags & IFF_RUNNING) == 0)) {
+ if (sc->sc_state) {
+ error = EBUSY;
+ break;
+ }
+/* if (!(ifp->if_flags & IFF_DEBUG))
+ plip_debug = PLIP_DEBUG;
+ else
+ plip_debug = 0;*/
+ sc->sc_state = LPT_OPEN | LPT_PLIP;
+ if (!sc->sc_ifbuf)
+ sc->sc_ifbuf =
+ malloc(ifp->if_mtu + ifp->if_hdrlen,
+ M_DEVBUF, M_WAITOK);
+ ifp->if_flags |= IFF_RUNNING;
+/* This starts it running */
+/* Enable lpt interrupts */
+
+#if PLIP_DEBUG != 0
+ if (plip_debug & PLIP_DEBUG_IF)
+ printf("plip: Enabling lpt irqs\n");
+#endif
+ outb(PLIP_CONTROL, PLIP_INTR_ENABLE);
+ outb(PLIP_DATA, 0x00);
+ }
+ break;
+
+ case SIOCSIFADDR:
+ if (ifa->ifa_addr->sa_family == AF_INET) {
+ if (!sc->sc_ifbuf)
+ sc->sc_ifbuf =
+ malloc(PLIPMTU + ifp->if_hdrlen,
+ M_DEVBUF, M_WAITOK);
+
+ sc->sc_arpcom.ac_enaddr[0] = 0xfc;
+ sc->sc_arpcom.ac_enaddr[1] = 0xfc;
+ bcopy((caddr_t)&IA_SIN(ifa)->sin_addr,
+ (caddr_t)&sc->sc_arpcom.ac_enaddr[2], 4);
+ sc->sc_arpcom.ac_ipaddr = IA_SIN(ifa)->sin_addr;
+#if defined(COMPAT_PLIP10)
+ if (ifp->if_flags & IFF_LINK0) {
+ int i;
+ sc->sc_arpcom.ac_enaddr[0] = 0xfd;
+ sc->sc_arpcom.ac_enaddr[1] = 0xfd;
+ for (i = sc->sc_adrcksum = 0; i < 5; i++)
+ sc->sc_adrcksum += sc->sc_arpcom.ac_enaddr[i];
+ sc->sc_adrcksum *= 2;
+ }
+#endif
+ ifp->if_flags |= IFF_RUNNING | IFF_UP;
+#if 0
+ for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
+ struct sockaddr_dl *sdl;
+ if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) &&
+ sdl->sdl_family == AF_LINK) {
+ sdl->sdl_type = IFT_ETHER;
+ sdl->sdl_alen = ifp->if_addrlen;
+ bcopy((caddr_t)((struct arpcom *)ifp)->ac_enaddr,
+ LLADDR(sdl), ifp->if_addrlen);
+ break;
+ }
+ }
+#endif
+/* Looks the same as the start condition above */
+/* Enable lpt interrupts */
+
+#if PLIP_DEBUG != 0
+ if (plip_debug & PLIP_DEBUG_IF)
+ printf("plip: Enabling lpt irqs\n");
+#endif
+ outb(PLIP_CONTROL, PLIP_INTR_ENABLE);
+ outb(PLIP_DATA, 0x00);
+
+ arp_ifinit(&sc->sc_arpcom, ifa);
+ } else
+ error = EAFNOSUPPORT;
+ break;
+
+ case SIOCAIFADDR:
+ case SIOCDIFADDR:
+ case SIOCSIFDSTADDR:
+ if (ifa->ifa_addr->sa_family != AF_INET)
+ error = EAFNOSUPPORT;
+ break;
+
+ case SIOCSIFMTU:
+ if ((error = suser(p->p_ucred, &p->p_acflag)))
+ return(error);
+ if (ifp->if_mtu != ifr->ifr_metric) {
+ ifp->if_mtu = ifr->ifr_metric;
+ if (sc->sc_ifbuf) {
+ s = splimp();
+
+ free(sc->sc_ifbuf, M_DEVBUF);
+ sc->sc_ifbuf =
+ malloc(ifp->if_mtu + ifp->if_hdrlen,
+ M_DEVBUF, M_WAITOK);
+ splx(s);
+ }
+ }
+ break;
+
+ case SIOCGIFMTU:
+ ifr->ifr_metric = ifp->if_mtu;
+ break;
+
+ default:
+ error = EINVAL;
+ }
+ return (error);
+}
+
+static int
+plipreceive(unsigned int iobase, u_char *buf, int len)
+{
+ int i;
+ u_char cksum = 0, c;
+ u_char c0, c1;
+
+#if PLIP_DEBUG != 0
+ if (plip_debug & PLIP_DEBUG_RX)
+ printf("Rx: ");
+#endif
+
+ while (len--) {
+ i = PLIPMXSPIN2;
+/* Receive a byte */
+
+/* Wait for a steady handshake */
+ while (1) {
+ c0 = inb(PLIP_STATUS);
+ if ((c0 & LPS_NBSY) == 0) {
+ c1 = inb(PLIP_STATUS);
+ if (c0 == c1) break;
+#if PLIP_DEBUG != 0
+ if (plip_debug & PLIP_DEBUG_RX)
+ printf("rx: %02x-%02x ", c0, c1);
+#endif
+ }
+ --i;
+ if (i < 0) {
+#if PLIP_DEBUG > 0
+ printf("timeout rx lsn %02x\n", c0);
+#endif
+ return(-1);
+ }
+ PLIP_DELAY;
+ }
+ c = (c0 >> 3) & 0x0f;
+
+/* Acknowledge */
+ outb(PLIP_DATA, 0x10);
+
+/* Another handshake */
+ i = PLIPMXSPIN2;
+ while (1) {
+ c0 = inb(PLIP_STATUS);
+ if (c0 & LPS_NBSY) {
+ c1 = inb(PLIP_STATUS);
+ if (c0 == c1) break;
+#if PLIP_DEBUG != 0
+ if (plip_debug & PLIP_DEBUG_RX)
+ printf("rx: %02x-%02x ", c0, c1);
+#endif
+ }
+ --i;
+ if (i < 0) {
+#if PLIP_DEBUG > 0
+ printf("timeout rx msn %02x\n", c0);
+#endif
+ return(-1);
+ }
+ PLIP_DELAY;
+ }
+ c = c | ((c0 << 1) & 0xf0);
+/* Acknowledge */
+ outb(PLIP_DATA, 0x00);
+#if PLIP_DEBUG != 0
+ if (plip_debug & PLIP_DEBUG_RX)
+ printf("%02x ", c);
+#endif
+
+ cksum += (*buf++ = c);
+ }
+#if PLIP_DEBUG != 0
+ if (plip_debug & PLIP_DEBUG_RX)
+ printf("\n");
+#endif
+ return(cksum);
+}
+
+static int
+plipintr(struct lpt_softc *sc)
+{
+ extern struct mbuf *m_devget(char *, int, int, struct ifnet *, void (*)());
+ struct ifnet *ifp = &sc->sc_arpcom.ac_if;
+ unsigned int iobase = sc->sc_iobase;
+ struct mbuf *m;
+ struct ether_header *eh;
+ u_char *p = sc->sc_ifbuf, minibuf[4];
+ int c, s, len, cksum;
+ u_char c0;
+
+printf("plipintr:\n");
+
+/* Get the status */
+
+ c0 = inb(PLIP_STATUS);
+#if PLIP_DEBUG > 0
+ if ((c0 & 0xf8) != 0xc0) {
+ printf("st5=%02x ", c0);
+ }
+#endif
+
+/* Don't want ints while receiving */
+
+ outb(PLIP_CONTROL, PLIP_INTR_DISABLE);
+
+ outb(PLIP_DATA, 0x01); /* send ACK */ /* via NERR */
+
+#if defined(COMPAT_PLIP10)
+ if (ifp->if_flags & IFF_LINK0) {
+ if (plipreceive(iobase, minibuf, 3) < 0) goto err;
+ len = (minibuf[1] << 8) | minibuf[2];
+ if (len > (ifp->if_mtu + ifp->if_hdrlen)) goto err;
+
+ switch (minibuf[0]) {
+ case 0xfc:
+ p[0] = p[ 6] = ifp->ac_enaddr[0];
+ p[1] = p[ 7] = ifp->ac_enaddr[1];
+ p[2] = p[ 8] = ifp->ac_enaddr[2];
+ p[3] = p[ 9] = ifp->ac_enaddr[3];
+ p[4] = p[10] = ifp->ac_enaddr[4];
+ p += 5;
+ if ((cksum = plipreceive(iobase, p, 1)) < 0) goto err;
+ p += 6;
+ if ((c = plipreceive(iobase, p, len - 11)) < 0) goto err;
+ cksum += c + sc->sc_adrcksum;
+ c = p[1]; p[1] = p[2]; p[2] = c;
+ cksum &= 0xff;
+ break;
+ case 0xfd:
+ if ((cksum = plipreceive(iobase, p, len)) < 0) goto err;
+ break;
+ default:
+ goto err;
+ }
+ } else
+#endif
+ {
+ if (plipreceive(iobase, minibuf, 2) < 0) goto err;
+ len = (minibuf[1] << 8) | minibuf[0];
+ if (len > (ifp->if_mtu + ifp->if_hdrlen)) {
+ log(LOG_NOTICE, "plip%d: packet > MTU\n", ifp->if_unit);
+ goto err;
+ }
+#if PLIP_DEBUG != 0
+ if (plip_debug & PLIP_DEBUG_RX)
+ printf("len=%d ", len);
+#endif
+ if (sizeof(struct ether_header) != 14) {
+ if ((cksum = plipreceive(iobase, p, 14)) < 0) goto err;
+ if ((c = plipreceive(iobase, p+16, len-14)) < 0) goto err;
+ cksum += c;
+ len += 2;
+ }
+ else
+ if ((cksum = plipreceive(iobase, p, len)) < 0) goto err;
+ }
+
+ if (plipreceive(iobase, minibuf, 1) < 0) goto err;
+ if ((cksum & 0xff) != minibuf[0]) {
+ printf("cksum=%d, %d, %d\n", cksum, c, minibuf[0]);
+ log(LOG_NOTICE, "plip%d: checksum error\n", ifp->if_unit);
+ goto err;
+ }
+
+ outb(PLIP_DATA, 0x00); /* clear ACK */ /* via NERR */
+#if PLIP_DEBUG != 0
+ if (plip_debug & PLIP_DEBUG_RX)
+ printf("done\n");
+#endif
+ s = splimp();
+
+ eh = (struct ether_header *)sc->sc_ifbuf;
+
+ if ((m = m_devget(sc->sc_ifbuf + sizeof(struct ether_header), len - sizeof(struct ether_header), 0, ifp, NULL))) {
+ /* We assume that the header fit entirely in one mbuf. */
+/* eh = mtod(m, struct ether_header *);*/
+/* m->m_pkthdr.len -= sizeof(*eh);*/
+/* m->m_len -= sizeof(*eh);*/
+/* m->m_data += sizeof(*eh);*/
+/* printf("m->m_data=%08x ifbuf=%08x eh=%08x\n", m->m_data, sc->sc_ifbuf, eh);*/
+
+#if NBPFILTER > 0
+/*
+ * Check if there's a BPF listener on this interface.
+ * If so, hand off the raw packet to bpf.
+ */
+ if (sc->sc_arpcom.ac_if.if_bpf) {
+ bpf_mtap(sc->sc_arpcom.ac_if.if_bpf, m);
+ }
+#endif
+ ether_input(ifp, eh, m);
+ }
+ splx(s);
+ sc->sc_iferrs = 0;
+ ifp->if_ipackets++;
+
+/* Allow ints again */
+
+ outb(PLIP_CONTROL, PLIP_INTR_ENABLE);
+ return(1);
+
+err:
+ outb(PLIP_DATA, 0x00); /* clear ACK */ /* via NERR */
+
+ ifp->if_ierrors++;
+ sc->sc_iferrs++;
+ if (sc->sc_iferrs > PLIPMXERRS
+ || (sc->sc_iferrs > 5 && (inb(iobase + lpt_status) & LPS_NBSY))) {
+ /* We are not able to send receive anything for now,
+ * so stop wasting our time and leave the interrupt
+ * disabled.
+ */
+ if (sc->sc_iferrs == PLIPMXERRS + 1)
+ log(LOG_NOTICE, "plip%d: rx hard error\n", ifp->if_unit);
+/* xxx i8255->port_a |= LPA_ACTIVE;*/
+ } else
+;
+/* xxx i8255->port_a |= LPA_ACKENABLE | LPA_ACTIVE;*/
+
+/* Allow ints again */
+
+ outb(PLIP_CONTROL, PLIP_INTR_ENABLE);
+ return(1);
+}
+
+static int
+pliptransmit(unsigned int iobase, u_char *buf, int len)
+{
+ int i;
+ u_char cksum = 0, c;
+ u_char c0;
+#if PLIP_DEBUG != 0
+ if (plip_debug & PLIP_DEBUG_TX)
+ printf("tx: len=%d ", len);
+#endif
+
+ while (len--) {
+ i = PLIPMXSPIN2;
+ cksum += (c = *buf++);
+#if PLIP_DEBUG != 0
+ if (plip_debug & PLIP_DEBUG_TX)
+ printf("%02x ", c);
+#endif
+/* xxx while ((i8255->port_c & LPC_NBUSY) == 0)
+ if (i-- < 0) return -1;
+ i8255->port_b = c & 0x0f;
+ i8255->port_b = c & 0x0f | 0x10;
+ c >>= 4;
+ while ((i8255->port_c & LPC_NBUSY) != 0)
+ if (i-- < 0) return -1;
+ i8255->port_b = c | 0x10;
+ i8255->port_b = c;
+*/
+
+/* Send the nibble + handshake */
+
+ outb(PLIP_DATA, 0x00 | (c & 0x0f));
+ outb(PLIP_DATA, 0x10 | (c & 0x0f));
+
+ while (1) {
+ c0 = inb(PLIP_STATUS);
+ if ((c0 & LPS_NBSY) == 0)
+ break;
+ if (--i == 0) { /* time out */
+#if PLIP_DEBUG > 0
+ printf("timeout tx lsn %02x ", c0);
+#endif
+ return(-1);
+ }
+ PLIP_DELAY;
+ }
+
+ outb(PLIP_DATA, 0x10 | (c >> 4));
+ outb(PLIP_DATA, 0x00 | (c >> 4));
+ i = PLIPMXSPIN2;
+ while (1) {
+ c0 = inb(PLIP_STATUS);
+ if ((c0 & LPS_NBSY) != 0)
+ break;
+ if (--i == 0) { /* time out */
+#if PLIP_DEBUG > 0
+ printf("timeout tx msn %02x ", c0);
+#endif
+ return(-1);
+ }
+ PLIP_DELAY;
+ }
+ }
+#if PLIP_DEBUG != 0
+ if (plip_debug & PLIP_DEBUG_TX)
+ printf("done\n");
+#endif
+ return(cksum);
+}
+
+/*
+ * Setup output on interface.
+ */
+static void
+plipstart(struct ifnet *ifp)
+{
+ struct lpt_softc *sc = (struct lpt_softc *) lpt_cd.cd_devs[ifp->if_unit];
+ unsigned int iobase = sc->sc_iobase;
+ struct mbuf *m0, *m;
+ u_char minibuf[4], cksum;
+ int len, i, s;
+ u_char *p;
+
+#if PLIP_DEBUG != 0
+ if (plip_debug & PLIP_DEBUG_TX)
+ printf("plipstart: ");
+#endif
+ if (ifp->if_flags & IFF_OACTIVE)
+ return;
+ ifp->if_flags |= IFF_OACTIVE;
+
+ if (sc->sc_ifretry)
+ untimeout((void (*)(void *))plipstart, ifp);
+
+ for (;;) {
+ s = splimp();
+ IF_DEQUEUE(&ifp->if_snd, m0);
+ splx(s);
+ if (!m0)
+ break;
+
+ for (len = 0, m = m0; m; m = m->m_next) {
+#if PLIP_DEBUG > 0
+ if (plip_debug & PLIP_DEBUG_TX)
+ printf("len=%d %d\n", m->m_len, len);
+#endif
+ len += m->m_len;
+ }
+#if NBPFILTER > 0
+ p = sc->sc_ifbuf;
+ for (m = m0; m; m = m->m_next) {
+ if (m->m_len == 0)
+ continue;
+ bcopy(mtod(m, u_char *), p, m->m_len);
+ p += m->m_len;
+ }
+ if (sc->sc_arpcom.ac_if.if_bpf)
+ bpf_tap(sc->sc_arpcom.ac_if.if_bpf, sc->sc_ifbuf, len);
+#endif
+ if (sizeof(struct ether_header) != 14)
+ len -= 2;
+#if defined(COMPAT_PLIP10)
+ if (ifp->if_flags & IFF_LINK0) {
+ minibuf[0] = 3;
+ minibuf[1] = 0xfd;
+ minibuf[2] = len >> 8;
+ minibuf[3] = len;
+ } else
+#endif
+ {
+ minibuf[0] = 2;
+ minibuf[1] = len;
+ minibuf[2] = len >> 8;
+ }
+
+/*yyy for (i = PLIPMXSPIN1; (inb(PLIP_STATUS) & LPS_NERR) != 0; i--)
+ if (i < 0) goto retry;*/
+
+ /* Trigger remote interrupt */
+
+#if PLIP_DEBUG > 0
+ if (plip_debug & PLIP_DEBUG_TX)
+ printf("st=%02x ", inb(PLIP_STATUS));
+#endif
+ if (inb(PLIP_STATUS) & LPS_NERR) {
+ for (i = PLIPMXSPIN1; (inb(PLIP_STATUS) & LPS_NERR) != 0; i--)
+ PLIP_DELAY;
+#if PLIP_DEBUG > 0
+ if (plip_debug & PLIP_DEBUG_TX)
+ printf("st1=%02x ", inb(PLIP_STATUS));
+#endif
+ }
+
+ outb(PLIP_DATA, PLIP_REMOTE_TRIGGER);
+ for (i = PLIPMXSPIN1; (inb(PLIP_STATUS) & LPS_NERR) == 0; i--) {
+ if (i < 0 || (i > PLIPMXSPIN1/3
+ && inb(PLIP_STATUS) & LPS_NACK)) {
+#if PLIP_DEBUG > 0
+ printf("trigger ack timeout\n");
+#endif
+ goto retry;
+ }
+ PLIP_DELAY;
+ }
+#if PLIP_DEBUG > 0
+ if (plip_debug & PLIP_DEBUG_TX)
+ printf("st3=%02x ", inb(PLIP_STATUS));
+#endif
+
+/* Don't want ints while transmitting */
+
+ outb(PLIP_CONTROL, PLIP_INTR_DISABLE);
+
+ if (pliptransmit(iobase, minibuf + 1, minibuf[0]) < 0) goto retry;
+ for (cksum = 0, m = m0; m; m = m->m_next) {
+ if (sizeof(struct ether_header) != 14 && m == m0) {
+ i = pliptransmit(iobase, mtod(m, u_char *), 14);
+ if (i < 0) goto retry;
+ cksum += i;
+ i = pliptransmit(iobase, mtod(m, u_char *)+16, m->m_len-16);
+ if (i < 0) goto retry;
+ }
+ else
+ i = pliptransmit(iobase, mtod(m, u_char *), m->m_len);
+ if (i < 0) goto retry;
+ cksum += i;
+ }
+ if (pliptransmit(iobase, &cksum, 1) < 0) goto retry;
+ i = PLIPMXSPIN2;
+ while ((inb(PLIP_STATUS) & LPS_NBSY) == 0)
+ if (i-- < 0) goto retry;
+
+ outb(iobase + lpt_data, 0x00);
+/* Re-enable ints */
+
+ outb(PLIP_CONTROL, PLIP_INTR_ENABLE);
+
+ ifp->if_opackets++;
+ ifp->if_obytes += len + 4;
+ sc->sc_ifretry = 0;
+ s = splimp();
+ m_freem(m0);
+ splx(s);
+ }
+ ifp->if_flags &= ~IFF_OACTIVE;
+ return;
+
+retry:
+#if PLIP_DEBUG > 0
+ if (plip_debug & PLIP_DEBUG_TX)
+ printf("retry: %02x", inb(iobase + lpt_status));
+#endif
+ if (inb(PLIP_STATUS & LPS_NACK))
+ ifp->if_collisions++;
+ else
+ ifp->if_oerrors++;
+ if ((ifp->if_flags & (IFF_RUNNING | IFF_UP)) == (IFF_RUNNING | IFF_UP)
+ && sc->sc_ifretry < PLIPMXRETRY) {
+ sc->sc_ifretry++;
+ s = splimp();
+ IF_PREPEND(&ifp->if_snd, m0);
+ splx(s);
+ timeout((void (*)(void *))plipstart, ifp, PLIPRETRY);
+ } else {
+ if (sc->sc_ifretry == PLIPMXRETRY) {
+ sc->sc_ifretry++;
+ log(LOG_NOTICE, "plip%d: tx hard error\n", ifp->if_unit);
+ }
+ s = splimp();
+ m_freem(m0);
+ splx(s);
+ }
+ ifp->if_flags &= ~IFF_OACTIVE;
+ outb(PLIP_DATA, 0x00);
+
+/* Re-enable ints */
+
+ outb(PLIP_CONTROL, PLIP_INTR_ENABLE);
+/*xxx if (sc->sc_iferrs > PLIPMXERRS)
+ i8255->port_a |= LPA_ACTIVE;
+ else
+ i8255->port_a |= LPA_ACKENABLE | LPA_ACTIVE;*/
+ return;
+}
+
+#endif
diff --git a/sys/arch/arm32/mainbus/lptreg.h b/sys/arch/arm32/mainbus/lptreg.h
new file mode 100644
index 00000000000..f909794337d
--- /dev/null
+++ b/sys/arch/arm32/mainbus/lptreg.h
@@ -0,0 +1,64 @@
+/* $NetBSD: lptreg.h,v 1.2 1996/03/18 20:50:03 mark Exp $ */
+
+/*
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)lptreg.h 1.1 (Berkeley) 12/19/90
+ */
+
+/*
+ * AT Parallel Port (for lineprinter)
+ * Interface port and bit definitions
+ * Written by William Jolitz 12/18/90
+ * Copyright (C) William Jolitz 1990
+ */
+
+#define lpt_data 0 /* Data to/from printer (R/W) */
+
+#define lpt_status 4 /* Status of printer (R) */
+#define LPS_NERR 0x08 /* printer no error */
+#define LPS_SELECT 0x10 /* printer selected */
+#define LPS_NOPAPER 0x20 /* printer out of paper */
+#define LPS_NACK 0x40 /* printer no ack of data */
+#define LPS_NBSY 0x80 /* printer no ack of data */
+
+#define lpt_control 8 /* Control printer (R/W) */
+#define LPC_STROBE 0x01 /* strobe data to printer */
+#define LPC_AUTOLF 0x02 /* automatic linefeed */
+#define LPC_NINIT 0x04 /* initialize printer */
+#define LPC_SELECT 0x08 /* printer selected */
+#define LPC_IENABLE 0x10 /* printer out of paper */
+
+#define LPT_NPORTS 32
diff --git a/sys/arch/arm32/mainbus/mainbus.c b/sys/arch/arm32/mainbus/mainbus.c
new file mode 100644
index 00000000000..7caade580dd
--- /dev/null
+++ b/sys/arch/arm32/mainbus/mainbus.c
@@ -0,0 +1,136 @@
+/* $NetBSD: mainbus.c,v 1.3 1996/03/20 18:38:00 mark Exp $ */
+
+/*
+ * Copyright (c) 1994,1995 Mark Brinicombe.
+ * Copyright (c) 1994 Brini.
+ * 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 Brini.
+ * 4. The name of the company 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 BRINI ``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 BRINI 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.
+ *
+ * RiscBSD kernel project
+ *
+ * mainbus.c
+ *
+ * mainbus configuration
+ *
+ * Created : 15/12/94
+ * Last updated : 03/07/95
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/conf.h>
+#include <sys/malloc.h>
+#include <sys/device.h>
+
+#include <arm32/mainbus/mainbus.h>
+#include <machine/io.h>
+
+int mainbusmatch __P((struct device *, void *, void *));
+void mainbusattach __P((struct device *, struct device *, void *));
+
+struct cfattach mainbus_ca = {
+ sizeof(struct device), mainbusmatch, mainbusattach
+};
+
+struct cfdriver mainbus_cd = {
+ NULL, "mainbus", DV_DULL, 1
+};
+
+int
+mainbusmatch(parent, match, aux)
+ struct device *parent;
+ void *match;
+ void *aux;
+{
+ return (1);
+}
+
+int
+mainbusprint(aux, mainbus)
+ void *aux;
+ char *mainbus;
+{
+ struct mainbus_attach_args *mb = aux;
+
+ if (mb->mb_iobase)
+ printf(" base 0x%x", mb->mb_iobase);
+ if (mb->mb_iosize > 1)
+ printf("-0x%x", mb->mb_iobase + mb->mb_iosize - 1);
+ if (mb->mb_irq != -1)
+ printf(" irq %d", mb->mb_irq);
+ if (mb->mb_drq != -1)
+ printf(" drq 0x%08x", mb->mb_drq);
+
+/* XXXX print flags */
+ return (QUIET);
+}
+
+
+void
+mainbusscan(parent, match)
+ struct device *parent;
+ void *match;
+{
+ struct device *dev = match;
+ struct cfdata *cf = dev->dv_cfdata;
+ struct mainbus_attach_args mb;
+
+ if (cf->cf_fstate == FSTATE_STAR)
+ panic("eekkk, I'm stuffed");
+
+ if (cf->cf_loc[0] == -1) {
+ mb.mb_iobase = 0;
+ mb.mb_iosize = 0;
+ mb.mb_drq = -1;
+ mb.mb_irq = -1;
+ } else {
+ mb.mb_iobase = cf->cf_loc[0] + IO_CONF_BASE;
+ mb.mb_iosize = 0;
+ mb.mb_drq = cf->cf_loc[1];
+ mb.mb_irq = cf->cf_loc[2];
+ }
+ if ((*cf->cf_attach->ca_match)(parent, dev, &mb) > 0)
+ config_attach(parent, dev, &mb, mainbusprint);
+ else
+ free(dev, M_DEVBUF);
+}
+
+void
+mainbusattach(parent, self, aux)
+ struct device *parent;
+ struct device *self;
+ void *aux;
+{
+ printf("\n");
+
+ config_scan(mainbusscan, self);
+}
+
+/* End of mainbus.c */
diff --git a/sys/arch/arm32/mainbus/mainbus.h b/sys/arch/arm32/mainbus/mainbus.h
new file mode 100644
index 00000000000..d0ae78e8c9b
--- /dev/null
+++ b/sys/arch/arm32/mainbus/mainbus.h
@@ -0,0 +1,62 @@
+/* $NetBSD: mainbus.h,v 1.2 1996/03/18 20:50:05 mark Exp $ */
+
+/*
+ * Copyright (c) 1994,1995 Mark Brinicombe.
+ * Copyright (c) 1994 Brini.
+ * 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 Brini.
+ * 4. The name of the company 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 BRINI ``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 BRINI 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.
+ *
+ * RiscBSD kernel project
+ *
+ * mainbus.c
+ *
+ * mainbus configuration
+ *
+ * Created : 15/12/94
+ */
+
+/*
+ * mainbus driver attach arguments
+ */
+
+struct mainbus_attach_args {
+ u_int mb_iobase; /* base i/o address */
+ int mb_iosize; /* span of ports used */
+ int mb_irq; /* interrupt request */
+ int mb_drq; /* DMA request */
+ void *mb_aux; /* driver specific */
+};
+
+#define DRQUNK -1
+#define INTUNK -1
+#define IRQUNK -1
+
+/* End of mainbus.h */
+
+
diff --git a/sys/arch/arm32/mainbus/pms.c b/sys/arch/arm32/mainbus/pms.c
new file mode 100644
index 00000000000..8339e1ab8a0
--- /dev/null
+++ b/sys/arch/arm32/mainbus/pms.c
@@ -0,0 +1,612 @@
+/* $NetBSD: pms.c,v 1.1 1996/03/28 21:50:19 mark Exp $ */
+
+/*-
+ * Copyright (c) 1996 D.C. Tsen
+ * Copyright (c) 1994 Charles Hannum.
+ * Copyright (c) 1992, 1993 Erik Forsberg.
+ * 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 RiscBSD team.
+ * 4. 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 AUTHORS ``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 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.
+ *
+ * from:pms.c,v 1.24 1995/12/24 02:30:28 mycroft Exp
+ */
+
+/*
+ * Ported from 386 version of PS/2 mouse driver.
+ * D.C. Tsen
+ */
+
+#include "pms.h"
+#if NPMS > 1
+#error Only one PS/2 style mouse may be configured into your system.
+#endif
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/buf.h>
+#include <sys/malloc.h>
+#include <sys/ioctl.h>
+#include <sys/tty.h>
+#include <sys/file.h>
+#include <sys/select.h>
+#include <sys/proc.h>
+#include <sys/signalvar.h>
+#include <sys/vnode.h>
+#include <sys/device.h>
+
+#include <machine/cpu.h>
+#include <machine/katelib.h>
+#include <machine/irqhandler.h>
+#include <machine/iomd.h>
+#include <machine/mouse.h>
+#include <arm32/mainbus/mainbus.h>
+
+/* mouse commands */
+#define PMS_SET_SCALE11 0xe6 /* set scaling 1:1 */
+#define PMS_SET_SCALE21 0xe7 /* set scaling 2:1 */
+#define PMS_SET_RES 0xe8 /* set resolution */
+#define PMS_GET_SCALE 0xe9 /* get scaling factor */
+#define PMS_SET_STREAM 0xea /* set streaming mode */
+#define PMS_SET_SAMPLE 0xf3 /* set sampling rate */
+#define PMS_DEV_ENABLE 0xf4 /* mouse on */
+#define PMS_DEV_DISABLE 0xf5 /* mouse off */
+#define PMS_RESET 0xff /* reset */
+
+#define PMS_CHUNK 128 /* chunk size for read */
+#define PMS_BSIZE (20*64) /* buffer size */
+
+struct pms_softc { /* driver status information */
+ struct device sc_dev;
+ irqhandler_t sc_ih;
+
+ struct proc *proc;
+ struct clist sc_q;
+ struct selinfo sc_rsel;
+ u_int sc_state; /* mouse driver state */
+#define PMS_OPEN 0x01 /* device is open */
+#define PMS_ASLP 0x02 /* waiting for mouse data */
+ u_int sc_status; /* mouse button status */
+ int sc_x, sc_y; /* accumulated motion in the X,Y axis */
+ int boundx, boundy, bounda, boundb; /* Bounding box. x,y is bottom left */
+ int origx, origy;
+ int lastx, lasty, lastb;
+};
+
+int pmsprobe __P((struct device *, void *, void *));
+void pmsattach __P((struct device *, struct device *, void *));
+int pmsintr __P((void *));
+
+struct cfattach pms_ca = {
+ sizeof(struct pms_softc), pmsprobe, pmsattach
+};
+
+struct cfdriver pms_cd = {
+ NULL, "pms", DV_DULL
+};
+
+#define PMSUNIT(dev) (minor(dev))
+
+static inline void
+pms_flush()
+{
+ while (inb(IOMD_MSCR) & 0x20) {
+ delay(6);
+ (void) inb(IOMD_MSDATA);
+ delay(6);
+ (void) inb(IOMD_MSDATA);
+ delay(6);
+ (void) inb(IOMD_MSDATA);
+ }
+}
+
+static void
+cmd_mouse(unsigned char cmd)
+{
+ unsigned char c;
+ int i = 0;
+ int retry = 10;
+
+ for (i = 0; i < 1000; i++) {
+ if (inb(IOMD_MSCR) & 0x80)
+ break;
+ delay(2);
+ }
+ if (i == 1000)
+ printf("Mouse transmit not ready\n");
+
+resend:
+ outb(IOMD_MSDATA, cmd);
+ delay(2);
+ c = inb(IOMD_MSCR) & (unsigned char) 0xff;
+ while (!(c & (unsigned char) 0x20)) {
+ delay(1);
+ c = inb(IOMD_MSCR);
+ }
+
+ delay(10000);
+
+ c = inb(IOMD_MSDATA) & 0xff;
+ if ((c == 0xFA) || (c == 0xEE))
+ return;
+
+ if (--retry) {
+ pms_flush();
+ goto resend;
+ }
+
+ printf("Mouse cmd failed, cmd = %x, status = %x\n", cmd, c);
+ return;
+}
+
+int
+pmsprobe(parent, match, aux)
+ struct device *parent;
+ void *match, *aux;
+{
+ /*struct mainbus_attach_args *mb = aux;*/
+ int i, j;
+ int mid;
+ int id;
+
+/* Make sure we have an IOMD we understand */
+
+ id = ReadByte(IOMD_ID0) | (ReadByte(IOMD_ID1) << 8);
+
+/* So far I only know about this IOMD */
+
+ switch (id) {
+ case RPC600_IOMD_ID:
+ return(0);
+ break;
+ case RC7500_IOC_ID:
+ break;
+ default:
+ printf("pms: Unknown IOMD id=%04x", id);
+ return(0);
+ break;
+ }
+
+ outb(IOMD_MSCR, 0x08); /* enable the mouse */
+
+ i = 0;
+ while ((inb(IOMD_MSCR) & 0x03) != 0x03) {
+ if (i++ > 10) {
+ printf("Mouse not found, status = <%x>.\n", inb(IOMD_MSCR));
+ return(0);
+ }
+ pms_flush();
+ delay(2);
+ outb(IOMD_MSCR, 0x08);
+ }
+
+ pms_flush();
+
+ /*
+ * Disable, reset and enable the mouse.
+ */
+ cmd_mouse(PMS_DEV_DISABLE);
+ cmd_mouse(PMS_RESET);
+ delay(300000);
+ j = 10;
+ i = 0;
+ while ((mid = inb(IOMD_MSDATA)) != 0xAA) {
+ if (++i > 500) {
+ if (--j < 0) {
+ printf("Mouse Reset failed, status = <%x>.\n", mid);
+ return(0);
+ }
+ pms_flush();
+ cmd_mouse(PMS_RESET);
+ i = 0;
+ }
+ delay(100000);
+ }
+ mid = inb(IOMD_MSDATA);
+#if 0
+ cmd_mouse(PMS_SET_RES);
+ cmd_mouse(3); /* 8 counts/mm */
+ cmd_mouse(PMS_SET_SCALE21);
+ cmd_mouse(PMS_SET_SAMPLE);
+ cmd_mouse(100); /* 100 samples/sec */
+ cmd_mouse(PMS_SET_STREAM);
+#endif
+ cmd_mouse(PMS_DEV_ENABLE);
+ return 1;
+}
+
+void
+pmsattach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct pms_softc *sc = (void *)self;
+ struct mainbus_attach_args *mb = aux;
+
+ printf("\n");
+
+ /* Other initialization was done by pmsprobe. */
+ sc->sc_state = 0;
+ sc->origx = 0;
+ sc->origy = 0;
+ sc->boundx = -4095;
+ sc->boundy = -4095;
+ sc->bounda = 4096;
+ sc->boundb = 4096;
+
+ sc->sc_ih.ih_func = pmsintr;
+ sc->sc_ih.ih_arg = sc;
+ sc->sc_ih.ih_level = IPL_TTY;
+ sc->sc_ih.ih_name = "pms";
+ if (mb->mb_irq != IRQUNK)
+ sc->sc_ih.ih_num = mb->mb_irq;
+ else
+#ifdef RC7500
+ sc->sc_ih.ih_num = IRQ_MSDRX;
+#else
+ panic("pms: No IRQ specified for pms interrupt handler\n");
+#endif
+}
+
+int
+pmsopen(dev, flag, mode, p)
+ dev_t dev;
+ int flag;
+ int mode;
+ struct proc *p;
+{
+ int unit = PMSUNIT(dev);
+ struct pms_softc *sc;
+
+ if (unit >= pms_cd.cd_ndevs)
+ return ENXIO;
+ sc = pms_cd.cd_devs[unit];
+ if (!sc)
+ return ENXIO;
+
+ if (sc->sc_state & PMS_OPEN)
+ return EBUSY;
+
+ if (clalloc(&sc->sc_q, PMS_BSIZE, 0) == -1)
+ return ENOMEM;
+
+ sc->proc = p;
+ sc->sc_state |= PMS_OPEN;
+ sc->sc_status = 0;
+ sc->sc_x = sc->sc_y = 0;
+ sc->lastx = -1;
+ sc->lasty = -1;
+ sc->lastb = -1;
+
+ if (irq_claim(IRQ_INSTRUCT, &sc->sc_ih) == -1)
+ panic("Cannot claim MOUSE IRQ\n");
+
+ return 0;
+}
+
+int
+pmsclose(dev, flag, mode, p)
+ dev_t dev;
+ int flag;
+ int mode;
+ struct proc *p;
+{
+ struct pms_softc *sc = pms_cd.cd_devs[PMSUNIT(dev)];
+
+ if (irq_release(IRQ_INSTRUCT, &sc->sc_ih) != 0)
+ panic("Cannot release MOUSE IRQ\n");
+
+ sc->proc = NULL;
+ sc->sc_state &= ~PMS_OPEN;
+ sc->sc_x = sc->sc_y = 0;
+
+ clfree(&sc->sc_q);
+
+ return 0;
+}
+
+int
+pmsread(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ struct pms_softc *sc = pms_cd.cd_devs[PMSUNIT(dev)];
+ int s;
+ int error = 0;
+ size_t length;
+ u_char buffer[PMS_CHUNK];
+
+ /* Block until mouse activity occured. */
+
+ s = spltty();
+ while (sc->sc_q.c_cc == 0) {
+ if (flag & IO_NDELAY) {
+ splx(s);
+ return EWOULDBLOCK;
+ }
+ sc->sc_state |= PMS_ASLP;
+ if (error = tsleep((caddr_t)sc, (PZERO | PCATCH), "pmsread", 0)) {
+ sc->sc_state &= ~PMS_ASLP;
+ splx(s);
+ return error;
+ }
+ }
+
+ /* Transfer as many chunks as possible. */
+
+ while (sc->sc_q.c_cc > 0 && uio->uio_resid > 0) {
+ length = min(sc->sc_q.c_cc, uio->uio_resid);
+ if (length > sizeof(buffer))
+ length = sizeof(buffer);
+
+ /* Remove a small chunk from the input queue. */
+ (void) q_to_b(&sc->sc_q, buffer, length);
+
+ /* Copy the data to the user process. */
+ if (error = uiomove(buffer, length, uio))
+ break;
+ }
+ splx(s);
+
+ return error;
+}
+
+int
+pmsioctl(dev, cmd, addr, flag, p)
+ dev_t dev;
+ u_long cmd;
+ caddr_t addr;
+ int flag;
+ struct proc *p;
+{
+ struct pms_softc *sc = pms_cd.cd_devs[PMSUNIT(dev)];
+ struct mouseinfo info;
+ int s;
+ int error = 0;
+
+ s = spltty();
+
+ switch (cmd) {
+ case MOUSEIOC_SETSTATE:
+ printf("MOUSEIOC_SETSTATE called\n");
+ break;
+ case MOUSEIOC_WRITEX:
+ sc->sc_x = *(int *) addr;
+ break;
+ case MOUSEIOC_WRITEY:
+ sc->sc_y = *(int *) addr;
+ break;
+ case MOUSEIOC_SETBOUNDS:
+ {
+ register struct mouse_boundingbox *bo = (void *) addr;
+ sc->boundx = bo->x; sc->boundy = bo->y;
+ sc->bounda = bo->a; sc->boundb = bo->b;
+ break;
+ }
+ case MOUSEIOC_SETORIGIN:
+ {
+ register struct mouse_origin *oo = (void *) addr;
+ sc->origx = oo->x;
+ sc->origy = oo->y;
+ break;
+ }
+ case MOUSEIOC_GETBOUNDS:
+ {
+ register struct mouse_boundingbox *bo = (void *) addr;
+ bo->x = sc->boundx; bo->y = sc->boundy;
+ bo->a = sc->bounda; bo->b = sc->boundb;
+ break;
+ }
+ case MOUSEIOC_GETORIGIN:
+ {
+ register struct mouse_origin *oo = (void *) addr;
+ oo->x = sc->origx;
+ oo->y = sc->origy;
+ break;
+ }
+ case MOUSEIOC_GETSTATE:
+ printf("MOUSEIOC_GETSTATE called\n");
+ /*
+ * Fall through.
+ */
+/* case MOUSEIOCREAD:*/
+
+ info.status = sc->sc_status;
+ if (sc->sc_x || sc->sc_y)
+ info.status |= MOVEMENT;
+
+#if 1
+ info.xmotion = sc->sc_x;
+ info.ymotion = sc->sc_y;
+#else
+ if (sc->sc_x > sc->bounda)
+ info.xmotion = sc->bounda;
+ else if (sc->sc_x < sc->boundx)
+ info.xmotion = sc->boundx;
+ else
+ info.xmotion = sc->sc_x;
+
+ if (sc->sc_y > sc->boundb)
+ info.ymotion = sc->boundb;
+ else if (sc->sc_y < sc->boundy)
+ info.ymotion = sc->boundy;
+ else
+ info.ymotion = sc->sc_y;
+#endif
+
+ /* Reset historical information. */
+ sc->sc_x = sc->sc_y = 0;
+ sc->sc_status &= ~BUTCHNGMASK;
+ ndflush(&sc->sc_q, sc->sc_q.c_cc);
+
+ error = copyout(&info, addr, sizeof(struct mouseinfo));
+ break;
+
+ default:
+ error = EINVAL;
+ break;
+ }
+ splx(s);
+
+ return error;
+}
+
+/* Masks for the first byte of a packet */
+#define PS2LBUTMASK 0x01
+#define PS2RBUTMASK 0x02
+#define PS2MBUTMASK 0x04
+
+#define XNEG_MASK 0x10
+#define YNEG_MASK 0x20
+
+int
+pmsintr(arg)
+ void *arg;
+{
+ struct pms_softc *sc = arg;
+ static int state = 0;
+ static u_char buttons;
+ u_char changed;
+ static int dx, dy;
+ int dosignal = 0;
+ int s;
+ u_char b;
+ struct mousebufrec mbuffer;
+
+ if ((sc->sc_state & PMS_OPEN) == 0) {
+ /* Interrupts are not expected. Discard the byte. */
+ pms_flush();
+ return(-1);
+ }
+
+ switch (state) {
+
+ case 0:
+ buttons = inb(IOMD_MSDATA);
+ if ((buttons & 0xc0) == 0)
+ ++state;
+ break;
+
+ case 1:
+ dx = inb(IOMD_MSDATA);
+ dx = (buttons & XNEG_MASK) ? -dx : dx;
+ ++state;
+ break;
+
+ case 2:
+ dy = inb(IOMD_MSDATA);
+ dy = (buttons & YNEG_MASK) ? -dy : dy;
+ state = 0;
+
+ buttons = ((buttons & PS2LBUTMASK) << 2) |
+ ((buttons & (PS2RBUTMASK | PS2MBUTMASK)) >> 1);
+ /*
+ * Ahhh, the Xarm server interrupt button bits reversed.
+ * If bit is set to 1, it means button is not pressed which is
+ * not what PS/2 mouse button bits said. Since we are simulating
+ * the quadmouse, that's not too picky about it.
+ */
+ buttons ^= BUTSTATMASK;
+ changed = ((buttons ^ sc->sc_status) & BUTSTATMASK) << 3;
+ sc->sc_status = buttons | (sc->sc_status & ~BUTSTATMASK) | changed;
+
+ if (dx || dy || changed) {
+ if (dx < 0)
+ dx = -(256 + dx);
+ if (dy < 0)
+ dy = -(256 + dy);
+
+ /* Update accumulated movements. */
+ sc->sc_x += dx;
+ sc->sc_y += dy;
+
+ if (sc->sc_x > sc->bounda)
+ sc->sc_x = sc->bounda;
+ else if (sc->sc_x < sc->boundx)
+ sc->sc_x = sc->boundx;
+
+ if (sc->sc_y > sc->boundb)
+ sc->sc_y = sc->boundb;
+ else if (sc->sc_y < sc->boundy)
+ sc->sc_y = sc->boundy;
+
+ if (sc->sc_q.c_cc == 0) {
+ dosignal = 1;
+ }
+
+ /* Add this event to the queue. */
+ b = buttons & BUTSTATMASK;
+ mbuffer.status = b | (b ^ sc->lastb) << 3
+ | (((sc->sc_x==sc->lastx) && (sc->sc_y==sc->lasty))?0:0x40);
+ mbuffer.x = sc->sc_x * 2;
+ mbuffer.y = sc->sc_y * 2;
+ microtime(&mbuffer.event_time);
+ s = spltty();
+ (void) b_to_q((char *)&mbuffer, sizeof(mbuffer), &sc->sc_q);
+ (void) splx(s);
+ sc->lastx = sc->sc_x;
+ sc->lasty = sc->sc_y;
+ sc->lastb = b;
+
+ selwakeup(&sc->sc_rsel);
+ if (sc->sc_state & PMS_ASLP) {
+ sc->sc_state &= ~PMS_ASLP;
+ wakeup((caddr_t)sc);
+ }
+ if (dosignal)
+ psignal(sc->proc, SIGIO);
+ }
+
+ break;
+ }
+
+ return(0);
+}
+
+int
+pmsselect(dev, rw, p)
+ dev_t dev;
+ int rw;
+ struct proc *p;
+{
+ struct pms_softc *sc = pms_cd.cd_devs[PMSUNIT(dev)];
+ int s;
+ int ret;
+
+ if (rw == FWRITE)
+ return 0;
+
+ s = spltty();
+ if (!sc->sc_q.c_cc) {
+ selrecord(p, &sc->sc_rsel);
+ ret = 0;
+ } else
+ ret = 1;
+ splx(s);
+
+ return ret;
+}
diff --git a/sys/arch/arm32/mainbus/qmouse.c b/sys/arch/arm32/mainbus/qmouse.c
new file mode 100644
index 00000000000..b2a6447a073
--- /dev/null
+++ b/sys/arch/arm32/mainbus/qmouse.c
@@ -0,0 +1,440 @@
+/* $NetBSD: qmouse.c,v 1.5 1996/03/28 21:56:40 mark Exp $ */
+
+/*
+ * Copyright (c) Scott Stevens 1995 All rights reserved
+ * Copyright (c) Melvin Tang-Richardson 1995 All rights reserved
+ * Copyright (c) Mark Brinicombe 1995 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 RiscBSD team.
+ * 4. 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.
+ */
+
+/*
+ * Quadrature mouse driver
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/ioctl.h>
+#include <sys/tty.h>
+#include <sys/kernel.h>
+#include <sys/types.h>
+#include <sys/device.h>
+#include <sys/proc.h>
+#include <sys/time.h>
+#include <sys/errno.h>
+#include <dev/cons.h>
+#include <sys/fcntl.h>
+#include <sys/signalvar.h>
+#include <sys/vnode.h>
+#include <sys/time.h>
+
+#include <arm32/mainbus/mainbus.h>
+#include <machine/irqhandler.h>
+#include <machine/katelib.h>
+#include <machine/iomd.h>
+#include <machine/mouse.h>
+
+#include "quadmouse.h"
+
+#define TIMER1_COUNT 40000 /* 50Hz */
+
+#define QMOUSE_BSIZE 12*64
+
+struct quadmouse_softc {
+ struct device sc_device;
+ irqhandler_t sc_ih;
+ int sc_iobase;
+ struct selinfo sc_rsel;
+#define QMOUSE_OPEN 0x01
+#define QMOUSE_ASLEEP 0x02
+ int sc_state;
+ int boundx, boundy, bounda, boundb; /* Bounding box. x,y is bottom left */
+ int origx, origy;
+ int xmult, ymult; /* Multipliers */
+ int lastx, lasty, lastb;
+ struct proc *proc;
+ struct clist buffer;
+};
+
+int quadmouseprobe __P((struct device *, void *, void *));
+void quadmouseattach __P((struct device *, struct device *, void *));
+int quadmouseopen __P((dev_t, int, int, struct proc *));
+int quadmouseclose __P((dev_t, int, int, struct proc *));
+
+int strncmp __P((const char *, const char *, size_t));
+
+int quadmouseintr (struct quadmouse_softc *);
+
+struct cfattach quadmouse_ca = {
+ sizeof(struct quadmouse_softc), quadmouseprobe, quadmouseattach
+};
+
+struct cfdriver quadmouse_cd = {
+ NULL, "quadmouse", DV_DULL
+};
+
+
+int
+quadmouseprobe(parent, match, aux)
+ struct device *parent;
+ void *match;
+ void *aux;
+{
+/* struct mainbus_attach_args *mb = aux;*/
+ int id;
+
+/* Make sure we have an IOMD we understand */
+
+ id = ReadByte(IOMD_ID0) | (ReadByte(IOMD_ID1) << 8);
+
+/* So far I only know about this IOMD */
+
+ switch (id) {
+ case RPC600_IOMD_ID:
+ return(1);
+ break;
+ default:
+ printf("quadmouse: Unknown IOMD id=%04x", id);
+ break;
+ }
+
+ return(0);
+}
+
+
+void
+quadmouseattach(parent, self, aux)
+ struct device *parent;
+ struct device *self;
+ void *aux;
+{
+ struct quadmouse_softc *sc = (void *)self;
+ struct mainbus_attach_args *mb = aux;
+
+ sc->sc_iobase = mb->mb_iobase;
+
+/* Check for a known IOMD chip */
+
+ sc->sc_ih.ih_func = quadmouseintr;
+ sc->sc_ih.ih_arg = sc;
+ sc->sc_ih.ih_level = IPL_TTY;
+ sc->sc_ih.ih_name = "T1 quadmouse";
+
+/* Set up origin and multipliers */
+
+ sc->origx = 0;
+ sc->origy = 0;
+ sc->xmult = 2;
+ sc->ymult = 2;
+
+/* Set up bounding box */
+
+ sc->boundx = -4095;
+ sc->boundy = -4095;
+ sc->bounda = 4096;
+ sc->boundb = 4096;
+
+ sc->sc_state = 0;
+
+ WriteWord(IOMD_MOUSEX, sc->origx);
+ WriteWord(IOMD_MOUSEY, sc->origy);
+
+ printf("\n");
+}
+
+
+int
+quadmouseopen(dev, flag, mode, p)
+ dev_t dev;
+ int flag;
+ int mode;
+ struct proc *p;
+{
+ struct quadmouse_softc *sc;
+ int unit = minor(dev);
+
+ if (unit >= quadmouse_cd.cd_ndevs)
+ return(ENXIO);
+
+ sc = quadmouse_cd.cd_devs[unit];
+
+ if (!sc) return(ENXIO);
+
+ if (sc->sc_state & QMOUSE_OPEN) return(EBUSY);
+
+ sc->proc = p;
+
+ sc->lastx = -1;
+ sc->lasty = -1;
+ sc->lastb = -1;
+
+ /* initialise buffer */
+ if (clalloc(&sc->buffer, QMOUSE_BSIZE, 0) == -1)
+ return(ENOMEM);
+
+ sc->sc_state |= QMOUSE_OPEN;
+
+ WriteByte(IOMD_T1LOW, (TIMER1_COUNT >> 0) & 0xff);
+ WriteByte(IOMD_T1HIGH, (TIMER1_COUNT >> 8) & 0xff);
+ WriteByte(IOMD_T1GO, 0);
+
+ if (irq_claim(IRQ_TIMER1, &sc->sc_ih))
+ panic("Cannot claim TIMER1 IRQ for quadmouse%d\n", sc->sc_device.dv_unit);
+
+ return(0);
+}
+
+
+int
+quadmouseclose(dev, flag, mode, p)
+ dev_t dev;
+ int flag;
+ int mode;
+ struct proc *p;
+{
+ int unit = minor (dev);
+ struct quadmouse_softc *sc = quadmouse_cd.cd_devs[unit];
+
+ if (irq_release(IRQ_TIMER1, &sc->sc_ih) != 0)
+ panic("Cannot release IRA\n");
+
+ sc->proc = NULL;
+ sc->sc_state = 0;
+
+ clfree(&sc->buffer);
+
+ return(0);
+}
+
+int
+quadmouseread(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ int unit = minor(dev);
+ struct quadmouse_softc *sc = quadmouse_cd.cd_devs[unit];
+ int error;
+ int s;
+ int length;
+ u_char buffer[128];
+
+ s=spltty();
+ while(sc->buffer.c_cc==0) {
+ if(flag & IO_NDELAY) {
+ (void)splx(s);
+ return(EWOULDBLOCK);
+ }
+ sc->sc_state |= QMOUSE_ASLEEP;
+ if((error = tsleep((caddr_t)sc, PZERO | PCATCH, "quadmouseread", 0))) {
+ sc->sc_state &= ~QMOUSE_ASLEEP;
+ (void)splx(s);
+ return(error);
+ }
+ }
+
+ while(sc->buffer.c_cc>0 && uio->uio_resid>0) {
+ length=min(sc->buffer.c_cc, uio->uio_resid);
+ if(length>sizeof(buffer))
+ length=sizeof(buffer);
+
+ (void) q_to_b(&sc->buffer, buffer, length);
+
+ if(error = (uiomove(buffer, length, uio)))
+ break;
+ }
+ (void)splx(s);
+ return(error);
+}
+
+
+#define FMT_START int x = ReadWord(IOMD_MOUSEX)&0xffff; \
+ int y = ReadWord(IOMD_MOUSEY)&0xffff; \
+ int b = ReadByte(IO_MOUSE_BUTTONS)&0x70; \
+ if(x&0x8000) x|=0xffff0000; \
+ if(y&0x8000) y|=0xffff0000; \
+ x = (x - sc->origx); \
+ y = (y - sc->origy); \
+ if (x<(sc->boundx)) x = sc->boundx; \
+ WriteWord(IOMD_MOUSEX, x + sc->origx); \
+ if (x>(sc->bounda)) x = sc->bounda; \
+ WriteWord(IOMD_MOUSEX, x + sc->origx); \
+ if (y<(sc->boundy)) y = sc->boundy; \
+ WriteWord(IOMD_MOUSEY, y + sc->origy); \
+ if (y>(sc->boundb)) y = sc->boundb; \
+ WriteWord(IOMD_MOUSEY, y + sc->origy); \
+ x=x*sc->xmult; \
+ y=y*sc->ymult;
+
+#define FMT_END
+
+
+int
+quadmouseioctl(dev, cmd, data, flag, p)
+ dev_t dev;
+ int cmd;
+ caddr_t data;
+ int flag;
+ struct proc *p;
+{
+ struct quadmouse_softc *sc = quadmouse_cd.cd_devs[minor(dev)];
+
+ switch (cmd) {
+ case MOUSEIOC_WRITEX:
+ WriteWord(IOMD_MOUSEX, *(int *)data+sc->origx);
+ return 0;
+ case MOUSEIOC_WRITEY:
+ WriteWord(IOMD_MOUSEY, *(int *)data+sc->origy);
+ return 0;
+ case MOUSEIOC_SETSTATE:
+ {
+ register struct mouse_state *co = (void *)data;
+ WriteWord(IOMD_MOUSEX, co->x);
+ WriteWord(IOMD_MOUSEY, co->y);
+
+ /* Silly, but here for completeness, just incase */
+ /* the hardware supports it *giggle* */
+
+/* This is not writable -- mark -- technically this should fault */
+
+/* WriteWord ( IO_MOUSE_BUTTONS, co->buttons );*/
+ return 0;
+ }
+ case MOUSEIOC_SETBOUNDS:
+ {
+ register struct mouse_boundingbox *bo = (void *)data;
+ sc->boundx = bo->x; sc->boundy = bo->y;
+ sc->bounda = bo->a; sc->boundb = bo->b;
+ return 0;
+ }
+ case MOUSEIOC_SETORIGIN:
+ {
+ register struct mouse_origin *oo = (void *)data;
+/* int oldx, oldy;*/
+ /* Need to fix up! */
+ sc->origx = oo->x;
+ sc->origy = oo->y;
+ return 0;
+ }
+ case MOUSEIOC_GETSTATE:
+ {
+ register struct mouse_state *co = (void *)data;
+ FMT_START
+ co->x = x;
+ co->y = y;
+ co->buttons = b ^ 0x70;
+ FMT_END
+ return 0;
+ }
+ case MOUSEIOC_GETBOUNDS:
+ {
+ register struct mouse_boundingbox *bo = (void *)data;
+ bo->x = sc->boundx; bo->y = sc->boundy;
+ bo->a = sc->bounda; bo->b = sc->boundb;
+ return 0;
+ }
+ case MOUSEIOC_GETORIGIN:
+ {
+ register struct mouse_origin *oo = (void *)data;
+ oo->x = sc->origx;
+ oo->y = sc->origy;
+ return 0;
+ }
+ }
+
+ return (EINVAL);
+}
+
+
+int
+quadmouseintr(sc)
+ struct quadmouse_softc *sc;
+{
+ int s;
+ struct mousebufrec buffer;
+ int dosignal=0;
+
+ FMT_START
+
+ b &= 0x70;
+ b >>= 4;
+ if (x != sc->lastx || y != sc->lasty || b != sc->lastb) {
+ /* Mouse state changed */
+ buffer.status = b | ( b ^ sc->lastb) << 3 | (((x==sc->lastx) && (y==sc->lasty))?0:0x40);
+ buffer.x = x;
+ buffer.y = y;
+ microtime(&buffer.event_time);
+
+ if(sc->buffer.c_cc==0)
+ dosignal=1;
+
+ s=spltty();
+ (void) b_to_q((char *)&buffer, sizeof(buffer), &sc->buffer);
+ (void)splx(s);
+ selwakeup(&sc->sc_rsel);
+
+ if(sc->sc_state & QMOUSE_ASLEEP) {
+ sc->sc_state &= ~QMOUSE_ASLEEP;
+ wakeup((caddr_t)sc);
+ }
+
+ if(dosignal)
+ psignal(sc->proc, SIGIO);
+
+ sc->lastx = x;
+ sc->lasty = y;
+ sc->lastb = b;
+ }
+
+ FMT_END
+ return(0);
+}
+
+int
+quadmouseselect(dev, rw, p)
+ dev_t dev;
+ int rw;
+ struct proc *p;
+{
+ int unit = minor(dev);
+ struct quadmouse_softc *sc = quadmouse_cd.cd_devs[unit];
+ int s;
+
+ if(rw == FWRITE)
+ return 0;
+
+ s=spltty();
+ if(sc->buffer.c_cc > 0) {
+ selrecord(p, &sc->sc_rsel);
+ (void)splx(s);
+ return 0;
+ }
+ (void)splx(s);
+ return 1;
+}
+
+/* End of quadmouse.c */
diff --git a/sys/arch/arm32/mainbus/rtc.c b/sys/arch/arm32/mainbus/rtc.c
new file mode 100644
index 00000000000..d759294324c
--- /dev/null
+++ b/sys/arch/arm32/mainbus/rtc.c
@@ -0,0 +1,384 @@
+/* $NetBSD: rtc.c,v 1.1 1996/04/19 19:49:06 mark Exp $ */
+
+/*
+ * Copyright (c) 1994-1996 Mark Brinicombe.
+ * Copyright (c) 1994 Brini.
+ * All rights reserved.
+ *
+ * This code is derived from software written for Brini by Mark Brinicombe
+ *
+ * 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 Brini.
+ * 4. The name of the company 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 BRINI ``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 BRINI 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.
+ *
+ * RiscBSD kernel project
+ *
+ * rtc.c
+ *
+ * Routines to read and write the RTC and CMOS RAM
+ *
+ * Created : 13/10/94
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/conf.h>
+#include <sys/malloc.h>
+#include <sys/device.h>
+#include <machine/iic.h>
+#include <machine/rtc.h>
+
+struct rtc_softc {
+ struct device sc_dev;
+ int sc_flags;
+#define RTC_BROKEN 1
+#define RTC_OPEN 2
+};
+
+void rtcattach __P((struct device *parent, struct device *self, void *aux));
+int rtcmatch __P((struct device *parent, void *match, void *aux));
+
+/* Read a byte from CMOS RAM */
+
+int
+cmos_read(location)
+ int location;
+{
+ u_char buff;
+
+/*
+ * This commented code dates from when I was translating CMOS address
+ * from the RISCOS addresses. Now all addresses are specifed as
+ * actual addresses in the CMOS RAM
+ */
+
+/*
+ if (location > 0xF0)
+ return(-1);
+
+ if (location < 0xC0)
+ buff = location + 0x40;
+ else
+ buff = location - 0xB0;
+*/
+ buff = location;
+
+ if (iic_control(RTC_Write, &buff, 1))
+ return(-1);
+ if (iic_control(RTC_Read, &buff, 1))
+ return(-1);
+
+ return(buff);
+}
+
+
+/* Write a byte to CMOS RAM */
+
+int
+cmos_write(location, value)
+ int location;
+ int value;
+{
+ u_char buff[2];
+
+/*
+ * This commented code dates from when I was translating CMOS address
+ * from the RISCOS addresses. Now all addresses are specifed as
+ * actual addresses in the CMOS RAM
+ */
+
+/* if (location > 0xF0)
+ return(-1);
+
+ if (location < 0xC0)
+ buff = location + 0x40;
+ else
+ buff = location - 0xB0;
+*/
+ buff[0] = location;
+ buff[1] = value;
+
+ if (iic_control(RTC_Write, buff, 2))
+ return(-1);
+
+ return(0);
+}
+
+
+/* Hex to BCD and BCD to hex conversion routines */
+
+static inline int
+hexdectodec(n)
+ u_char n;
+{
+ return(((n >> 4) & 0x0F) * 10 + (n & 0x0F));
+}
+
+static inline int
+dectohexdec(n)
+ u_char n;
+{
+ return(((n / 10) << 4) + (n % 10));
+}
+
+
+/* Write the RTC data from an 8 byte buffer */
+
+int
+rtc_write(rtc)
+ rtc_t *rtc;
+{
+ u_char buff[8];
+
+ buff[0] = 1;
+
+ buff[1] = dectohexdec(rtc->rtc_centi);
+ buff[2] = dectohexdec(rtc->rtc_sec);
+ buff[3] = dectohexdec(rtc->rtc_min);
+ buff[4] = dectohexdec(rtc->rtc_hour) & 0x3f;
+ buff[5] = dectohexdec(rtc->rtc_day);
+ buff[6] = dectohexdec(rtc->rtc_mon);
+
+ if (iic_control(RTC_Write, buff, 7))
+ return(0);
+
+ cmos_write(RTC_ADDR_YEAR, rtc->rtc_year);
+ cmos_write(RTC_ADDR_CENT, rtc->rtc_cen);
+
+ return(1);
+}
+
+
+/* Read the RTC data into a 8 byte buffer */
+
+int
+rtc_read(rtc)
+ rtc_t *rtc;
+{
+ u_char buff[8];
+ int byte;
+
+ buff[0] = 0;
+
+ if (iic_control(RTC_Write, buff, 1))
+ return(0);
+
+ if (iic_control(RTC_Read, buff, 8))
+ return(0);
+
+ rtc->rtc_micro = 0;
+ rtc->rtc_centi = hexdectodec(buff[1] & 0xff);
+ rtc->rtc_sec = hexdectodec(buff[2] & 0x7f);
+ rtc->rtc_min = hexdectodec(buff[3] & 0x7f);
+ rtc->rtc_hour = hexdectodec(buff[4] & 0x3f);
+
+ /* If in 12 hour mode need to look at the AM/PM flag */
+
+ if (buff[4] & 0x80)
+ rtc->rtc_hour += (buff[4] & 0x40) ? 12 : 0;
+
+ rtc->rtc_day = hexdectodec(buff[5] & 0x3f);
+ rtc->rtc_mon = hexdectodec(buff[6] & 0x1f);
+
+ byte = cmos_read(RTC_ADDR_YEAR);
+ if (byte == -1)
+ return(0);
+ rtc->rtc_year = byte;
+
+ byte = cmos_read(RTC_ADDR_CENT);
+ if (byte == -1)
+ return(0);
+ rtc->rtc_cen = byte;
+
+ return(1);
+}
+
+
+struct cfattach rtc_ca = {
+ sizeof(struct rtc_softc), rtcmatch, rtcattach
+};
+
+struct cfdriver rtc_cd = {
+ NULL, "rtc", DV_DULL, 0
+};
+
+int
+rtcmatch(parent, match, aux)
+ struct device *parent;
+ void *match;
+ void *aux;
+{
+/* struct iicbus_attach_args *ib = aux;*/
+
+ return(1);
+}
+
+
+void
+rtcattach(parent, self, aux)
+ struct device *parent;
+ struct device *self;
+ void *aux;
+{
+ struct rtc_softc *sc = (struct rtc_softc *)self;
+ struct iicbus_attach_args *ib = aux;
+ u_char buff[1];
+
+ sc->sc_flags |= RTC_BROKEN;
+ if ((ib->ib_addr & IIC_PCF8583_MASK) == IIC_PCF8583_ADDR) {
+ printf(": PCF8583");
+
+ buff[0] = 0;
+
+ if (iic_control(RTC_Write, buff, 1))
+ return;
+
+ if (iic_control(RTC_Read, buff, 1))
+ return;
+
+ printf(" clock base ");
+ switch (buff[0] & 0x30) {
+ case 0x00:
+ printf("32.768KHz");
+ break;
+ case 0x10:
+ printf("50Hz");
+ break;
+ case 0x20:
+ printf("event");
+ break;
+ case 0x30:
+ printf("test mode");
+ break;
+ }
+
+ if (buff[0] & 0x80)
+ printf(" stopped");
+ if (buff[0] & 0x04)
+ printf(" alarm enabled");
+ sc->sc_flags &= ~RTC_BROKEN;
+ }
+
+
+/*
+ * Initialise the time of day register.
+ * This is normally left to the filing system to do but not all
+ * filing systems call it e.g. cd9660
+ */
+
+ inittodr(0);
+
+ printf("\n");
+}
+
+
+int
+rtcopen(dev, flag, mode, p)
+ dev_t dev;
+ int flag;
+ int mode;
+ struct proc *p;
+{
+ struct rtc_softc *sc;
+ int unit = minor(dev);
+
+ if (unit >= rtc_cd.cd_ndevs)
+ return(ENXIO);
+
+ sc = rtc_cd.cd_devs[unit];
+
+ if (!sc) return(ENXIO);
+
+ if (sc->sc_flags & RTC_OPEN) return(EBUSY);
+
+ sc->sc_flags |= RTC_OPEN;
+
+ return(0);
+}
+
+
+int
+rtcclose(dev, flag, mode, p)
+ dev_t dev;
+ int flag;
+ int mode;
+ struct proc *p;
+{
+ int unit = minor(dev);
+ struct rtc_softc *sc = rtc_cd.cd_devs[unit];
+
+ sc->sc_flags &= ~RTC_OPEN;
+
+ return(0);
+}
+
+
+int
+rtcread(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ int unit = minor(dev);
+ struct rtc_softc *sc = rtc_cd.cd_devs[unit];
+
+ return(ENXIO);
+}
+
+
+int
+rtcwrite(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ int unit = minor(dev);
+ struct rtc_softc *sc = rtc_cd.cd_devs[unit];
+
+ return(ENXIO);
+}
+
+
+int
+rtcioctl(dev, cmd, data, flag, p)
+ dev_t dev;
+ int cmd;
+ caddr_t data;
+ int flag;
+ struct proc *p;
+{
+ struct rtc_softc *sc = rtc_cd.cd_devs[minor(dev)];
+
+/* switch (cmd) {
+ case RTCIOC_READ:
+ return(0);
+ } */
+
+ return(EINVAL);
+}
+
+/* End of rtc.c */
diff --git a/sys/arch/arm32/mainbus/vidcaudio.c b/sys/arch/arm32/mainbus/vidcaudio.c
new file mode 100644
index 00000000000..0529519a9b4
--- /dev/null
+++ b/sys/arch/arm32/mainbus/vidcaudio.c
@@ -0,0 +1,870 @@
+/* $NetBSD: vidcaudio.c,v 1.3 1996/03/17 01:24:37 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1995 Melvin Tang-Richardson
+ *
+ * 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 RiscBSD team.
+ * 4. 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.
+ */
+
+/*
+ * Yikes just had a look at this and realised that it does not conform
+ * to Kernel Normal Form at all. I have fixed the first few functions
+ * but there are a lot more still to do - mark
+ */
+
+/*
+ * vidcaudio driver for RiscBSD by Melvin Tang-Richardson (c) 1995
+ *
+ * Interfaces with the NetBSD generic audio driver to provide SUN
+ * /dev/audio (partial) compatibility.
+ *
+ * Do not include me in conf.c. My interface is done by the generic
+ * audio driver. Put me in config file and files.arm32. Do not put
+ * the audio.c generic driver in them. I do the autoconfig for it.
+ *
+ * The following files need to be altered
+ *
+ * [files.arm32]
+ * device vidcaudio at mainbus :audio
+ * file arch/arm32/mainbus/vidcaudio.c vidcaudio needs-flag
+ * major { audio=36 }
+ *
+ * [conf.c]
+ * #include "audio.h"
+ * cdev_decl(audio)
+ *
+ * cdev_audio_init(NAUDIO,audio) /* 36: generic audio I/O */
+ *
+ * [GENERIC]
+ * vidcaudio0 at mainbus? base 0x00000000
+ *
+ */
+
+#include <sys/param.h> /* proc.h */
+#include <sys/types.h> /* dunno */
+#include <sys/conf.h> /* autoconfig functions */
+#include <sys/device.h> /* device calls */
+#include <sys/proc.h> /* device calls */
+#include <sys/audioio.h>
+#include <sys/errno.h>
+#include <sys/systm.h>
+
+#include <vm/vm.h>
+#include <vm/vm_kern.h>
+
+#include <dev/audio_if.h>
+
+#include <machine/irqhandler.h>
+#include <machine/iomd.h>
+#include <machine/vidc.h>
+#include <machine/katelib.h> /* ReadByte etc. */
+
+#include <arm32/mainbus/mainbus.h>
+#include "waveform.h"
+#include "vidcaudio.h"
+
+#undef DEBUG
+
+struct audio_general {
+ int in_sr;
+ int out_sr;
+ vm_offset_t silence;
+ irqhandler_t ih;
+
+ void (*intr) ();
+ void *arg;
+
+ vm_offset_t next_cur;
+ vm_offset_t next_end;
+ void (*next_intr) ();
+ void *next_arg;
+
+ int buffer;
+ int in_progress;
+
+ int open;
+} ag;
+
+struct vidcaudio_softc {
+ struct device device;
+ int iobase;
+
+ int open;
+
+ u_int encoding;
+ int inport;
+ int outport;
+};
+
+int vidcaudio_probe __P((struct device *parent, struct device *match, void *aux));
+void vidcaudio_attach __P((struct device *parent, struct device *self, void *aux));
+int vidcaudio_open __P((dev_t dev, int flags));
+void vidcaudio_close __P((void *addr));
+
+int vidcaudio_intr __P((void *arg));
+int vidcaudio_dma_program __P((vm_offset_t cur, vm_offset_t end, void (*intr)(), void *arg));
+void vidcaudio_dummy_routine __P((void *arg));
+int vidcaudio_stereo __P((int channel, int position));
+int vidcaudio_rate __P((int rate));
+void vidcaudio_shutdown __P((void));
+int vidcaudio_hw_attach __P((struct vidcaudio_softc *sc));
+
+struct cfattach vidcaudio_ca = {
+ sizeof(struct vidcaudio_softc), vidcaudio_probe, vidcaudio_attach
+};
+
+struct cfdriver vidcaudio_cd = {
+ NULL, "vidcaudio", DV_DULL
+};
+
+
+void
+vidcaudio_beep_generate()
+{
+ vidcaudio_dma_program ( ag.silence, ag.silence+sizeof(beep_waveform)-16,
+ vidcaudio_dummy_routine, NULL );
+}
+
+
+int
+vidcaudio_probe(parent, match, aux)
+ struct device *parent;
+ struct device *match;
+ void *aux;
+{
+ int id;
+
+ id = ReadByte(IOMD_ID0) | ReadByte(IOMD_ID1) << 8;
+
+/* So far I only know about this IOMD */
+
+ switch (id) {
+ case RPC600_IOMD_ID:
+ return(1);
+ break;
+ default:
+ printf("vidcaudio: Unknown IOMD id=%04x", id);
+ break;
+ }
+
+ return (0);
+}
+
+
+void
+vidcaudio_attach(parent, self, aux)
+ struct device *parent;
+ struct device *self;
+ void *aux;
+{
+ struct mainbus_attach_args *mb = aux;
+ struct vidcaudio_softc *sc = (void *)self;
+
+ sc->iobase = mb->mb_iobase;
+
+ sc->open = 0;
+ sc->encoding = 0;
+ sc->inport = 0;
+ sc->outport = 0;
+ ag.in_sr = 24*1024;
+ ag.out_sr = 24*1024;
+ ag.in_progress = 0;
+
+ ag.next_cur = 0;
+ ag.next_end = 0;
+ ag.next_intr = NULL;
+ ag.next_arg = NULL;
+
+ vidcaudio_rate(32);
+
+/* Program the silence buffer and reset the DMA channel */
+
+ ag.silence = kmem_alloc(kernel_map, NBPG);
+ if (ag.silence == NULL)
+ panic("vidcaudio: Cannot allocate memory\n");
+
+ bzero((char *)ag.silence, NBPG);
+ bcopy((char *)beep_waveform, (char *)ag.silence, sizeof(beep_waveform));
+
+ ag.buffer = 0;
+
+ /* Install the irq handler for the DMA interrupt */
+ ag.ih.ih_func = vidcaudio_intr;
+ ag.ih.ih_arg = NULL;
+ ag.ih.ih_level = IPL_NONE;
+
+ ag.intr = NULL;
+ ag.nextintr = NULL;
+
+ disable_irq(IRQ_DMASCH0);
+
+ if (irq_claim(IRQ_DMASCH0, &(ag.ih)))
+ panic("vidcaudio: couldn't claim IRQ_DMASCH0");
+
+ disable_irq(IRQ_DMASCH0);
+
+ vidcaudio_dma_program(ag.silence, ag.silence+NBPG-16,
+ vidcaudio_dummy_routine, NULL);
+
+ vidcaudio_hw_attach(sc);
+
+#ifdef DEBUG
+ printf(" UNDER DEVELOPMENT (nuts)\n");
+#endif
+}
+
+int
+vidcaudio_open(dev, flags)
+ dev_t dev;
+ int flags;
+{
+ struct vidcaudio_softc *sc;
+ int unit = AUDIOUNIT (dev);
+ int s;
+
+#ifdef DEBUG
+ printf("DEBUG: vidcaudio_open called\n");
+#endif
+
+ if (unit >= vidcaudio_cd.cd_ndevs)
+ return ENODEV;
+
+ sc = vidcaudio_cd.cd_devs[unit];
+
+ if (!sc)
+ return ENXIO;
+
+ s = splhigh();
+
+ if (sc->open != 0) {
+ (void)splx(s);
+ return EBUSY;
+ }
+
+ sc->open=1;
+ ag.open=1;
+
+ (void)splx(s);
+ return 0;
+}
+
+void
+vidcaudio_close(addr)
+ void *addr;
+{
+ struct vidcaudio_softc *sc = addr;
+
+ vidcaudio_shutdown ();
+
+#ifdef DEBUG
+ printf("DEBUG: vidcaudio_close called\n");
+#endif
+
+ sc->open = 0;
+ ag.open = 0;
+}
+
+/* ************************************************************************* *
+ | Interface to the generic audio driver |
+ * ************************************************************************* */
+
+int vidcaudio_set_in_sr __P((void *, u_long));
+u_long vidcaudio_get_in_sr __P((void *));
+int vidcaudio_set_out_sr __P((void *, u_long));
+u_long vidcaudio_get_out_sr __P((void *));
+int vidcaudio_query_encoding __P((void *, struct audio_encoding *));
+int vidcaudio_set_encoding __P((void *, u_int));
+int vidcaudio_get_encoding __P((void *));
+int vidcaudio_set_precision __P((void *, u_int));
+int vidcaudio_getprecision __P((void *));
+int vidcaudio_set_channels __P((void *, int));
+int vidcaudio_get_channels __P((void *));
+int vidcaudio_round_blocksize __P((void *, int));
+int vidcaudio_set_out_port __P((void *, int));
+int vidcaudio_get_out_port __P((void *));
+int vidcaudio_set_in_port __P((void *, int));
+int vidcaudio_get_in_port __P((void *));
+int vidcaudio_commit_settings __P((void *));
+u_int vidcaudio_get_silence __P((int));
+void vidcaudio_sw_encode __P((int, u_char *, int));
+void vidcaudio_sw_decode __P((int, u_char *, int));
+int vidcaudio_start_output __P((void *, void *, int, void (*)(), void *));
+int vidcaudio_start_input __P((void *, void *, int, void (*)(), void *));
+int vidcaudio_halt_output __P((void *));
+int vidcaudio_halt_input __P((void *));
+int vidcaudio_cont_output __P((void *));
+int vidcaudio_cont_input __P((void *));
+int vidcaudio_speaker_ctl __P((void *, int));
+int vidcaudio_getdev __P((void *, struct audio_device *));
+int vidcaudio_setfd __P((void *, int));
+int vidcaudio_set_port __P((void *, mixer_ctrl_t *));
+int vidcaudio_get_port __P((void *, mixer_ctrl_t *));
+int vidcaudio_query_devinfo __P((void *, mixer_devinfo_t *));
+
+struct audio_device vidcaudio_device = {
+ "VidcAudio 8-bit",
+ "x",
+ "vidcaudio"
+};
+
+int
+vidcaudio_set_in_sr(addr, sr)
+ void *addr;
+ u_long sr;
+{
+ ag.in_sr = sr;
+ return 0;
+}
+
+u_long
+vidcaudio_get_in_sr(addr)
+ void *addr;
+{
+ return ag.in_sr;
+}
+
+int
+vidcaudio_set_out_sr(addr, sr)
+ void *addr;
+ u_long sr;
+{
+ ag.out_sr = sr;
+ return 0;
+}
+
+u_long
+vidcaudio_get_out_sr(addr)
+ void *addr;
+{
+ return(ag.out_sr);
+}
+
+int vidcaudio_query_encoding ( void *addr, struct audio_encoding *fp )
+{
+ switch ( fp->index )
+ {
+ case 0:
+ strcpy (fp->name, "vidc" );
+ fp->format_id = AUDIO_ENCODING_ULAW;
+ break;
+
+ default:
+ return (EINVAL);
+ }
+ return 0;
+}
+
+int vidcaudio_set_encoding ( void *addr, u_int enc )
+{
+ struct vidcaudio_softc *sc = addr;
+
+ switch (enc)
+ {
+ case AUDIO_ENCODING_ULAW:
+#ifdef DEBUG
+ printf ( "DEBUG: Set ulaw encoding\n" );
+#endif
+ sc->encoding = enc;
+ break;
+
+ default:
+ return (EINVAL);
+ }
+ return 0;
+}
+
+int vidcaudio_get_encoding ( void *addr )
+{
+ struct vidcaudio_softc *sc = addr;
+ return sc->encoding;
+}
+
+int vidcaudio_set_precision ( void *addr, u_int prec )
+{
+ if (prec != 8)
+ return EINVAL;
+ return 0;
+}
+
+int vidcaudio_get_precision ( void *addr )
+{
+ return (8);
+}
+
+int vidcaudio_set_channels ( void *addr, int chans )
+{
+ if ( chans!=1 )
+ return EINVAL;
+
+ return 0;
+}
+
+int vidcaudio_get_channels ( void *addr )
+{
+ return 1;
+}
+
+int vidcaudio_round_blocksize ( void *addr, int blk )
+{
+ if (blk>NBPG) blk=NBPG;
+ return blk;
+}
+
+int vidcaudio_set_out_port ( void *addr, int port )
+{
+ struct vidcaudio_softc *sc = addr;
+ sc->outport = port;
+ return 0;
+}
+
+int vidcaudio_get_out_port ( void *addr )
+{
+ struct vidcaudio_softc *sc = addr;
+ return sc->outport;
+}
+
+int vidcaudio_set_in_port ( void *addr, int port )
+{
+ struct vidcaudio_softc *sc = addr;
+ sc->inport = port;
+ return 0;
+}
+
+int vidcaudio_get_in_port ( void *addr )
+{
+ struct vidcaudio_softc *sc = addr;
+ return sc->inport;
+}
+
+int vidcaudio_commit_settings ( void *addr )
+{
+#ifdef DEBUG
+printf ( "DEBUG: committ_settings\n" );
+#endif
+ return 0;
+}
+
+u_int vidcaudio_get_silence ( int enc )
+{
+ switch (enc)
+ {
+ case AUDIO_ENCODING_ULAW:
+ return 0x7f;
+
+ default:
+ return 0;
+ }
+ return 0;
+}
+
+void vidcaudio_sw_encode ( int e, u_char *p, int cc )
+{
+#ifdef DEBUG
+ printf ( "DEBUG: sw_encode\n" );
+#endif
+ return;
+}
+
+void vidcaudio_sw_decode ( int e, u_char *p, int cc )
+{
+#ifdef DEBUG
+ printf ( "DEBUG: sw_decode\n" );
+#endif
+}
+
+#define ROUND(s) ( ((int)s) & (~(NBPG-1)) )
+
+int vidcaudio_start_output ( void *addr, void *p, int cc,
+ void (*intr)(), void *arg )
+{
+ /* I can only DMA inside 1 page */
+
+#ifdef DEBUG
+ printf ( "vidcaudio_start_output (%d) %08x %08x\n", cc, intr, arg );
+#endif
+
+ if ( ROUND(p) != ROUND(p+cc) )
+ {
+ /* If it's over a page I can fix it up by copying it into my buffer */
+
+#ifdef DEBUG
+ printf ( "vidcaudio: DMA over page boundary requested. Fixing up\n" );
+#endif
+ bcopy ( (char *)ag.silence, p, cc>NBPG ? NBPG : cc );
+ p=(void *)ag.silence;
+
+ /* I can't DMA any more than that, but it is possible to fix it up */
+ /* by handling multiple buffers and only interrupting the audio */
+ /* driver after sending out all the stuff it gave me. That it more */
+ /* than I can be bothered to do right now and it probablly wont */
+ /* happen so I'll just truncate the buffer and tell the user */
+
+ if ( cc>NBPG )
+ {
+ printf ( "vidcaudio: DMA buffer truncated. I could fix this up\n" );
+ cc=NBPG;
+ }
+ }
+ vidcaudio_dma_program ( (vm_offset_t)p, (vm_offset_t)(p+cc), intr, arg );
+ return 0;
+}
+
+int vidcaudio_start_input ( void *addr, void *p, int cc,
+ void (*intr)(), void *arg )
+{
+ return EIO;
+}
+
+int vidcaudio_halt_output ( void *addr )
+{
+#ifdef DEBUG
+ printf ( "DEBUG: vidcaudio_halt_output\n" );
+#endif
+ return EIO;
+}
+
+int vidcaudio_halt_input ( void *addr )
+{
+#ifdef DEBUG
+ printf ( "DEBUG: vidcaudio_halt_output\n" );
+#endif
+ return EIO;
+}
+
+int vidcaudio_cont_output ( void *addr )
+{
+#ifdef DEBUG
+ printf ( "DEBUG: vidcaudio_halt_output\n" );
+#endif
+ return EIO;
+}
+
+int vidcaudio_cont_input ( void *addr )
+{
+#ifdef DEBUG
+ printf ( "DEBUG: vidcaudio_halt_output\n" );
+#endif
+ return EIO;
+}
+
+int vidcaudio_speaker_ctl ( void *addr, int newstate )
+{
+#ifdef DEBUG
+ printf ( "DEBUG: vidcaudio_speaker_ctl\n" );
+#endif
+ return 0;
+}
+
+int vidcaudio_getdev ( void *addr, struct audio_device *retp )
+{
+ *retp = vidcaudio_device;
+ return 0;
+}
+
+
+int vidcaudio_setfd ( void *addr, int flag )
+{
+ return ENOTTY;
+}
+
+int vidcaudio_set_port ( void *addr, mixer_ctrl_t *cp )
+{
+ return EINVAL;
+}
+
+int vidcaudio_get_port ( void *addr, mixer_ctrl_t *cp )
+{
+ return EINVAL;
+}
+
+int vidcaudio_query_devinfo ( void *addr, mixer_devinfo_t *dip )
+{
+ return 0;
+}
+
+struct audio_hw_if vidcaudio_hw_if = {
+ vidcaudio_open,
+ vidcaudio_close,
+ NULL,
+ vidcaudio_set_in_sr,
+ vidcaudio_get_in_sr,
+ vidcaudio_set_out_sr,
+ vidcaudio_get_out_sr,
+ vidcaudio_query_encoding,
+ vidcaudio_set_encoding,
+ vidcaudio_get_encoding,
+ vidcaudio_set_precision,
+ vidcaudio_get_precision,
+ vidcaudio_set_channels,
+ vidcaudio_get_channels,
+ vidcaudio_round_blocksize,
+ vidcaudio_set_out_port,
+ vidcaudio_get_out_port,
+ vidcaudio_set_in_port,
+ vidcaudio_get_in_port,
+ vidcaudio_commit_settings,
+ vidcaudio_get_silence,
+ vidcaudio_sw_encode,
+ vidcaudio_sw_decode,
+ vidcaudio_start_output,
+ vidcaudio_start_input,
+ vidcaudio_halt_output,
+ vidcaudio_halt_input,
+ vidcaudio_cont_output,
+ vidcaudio_cont_input,
+ vidcaudio_speaker_ctl,
+ vidcaudio_getdev,
+ vidcaudio_setfd,
+ vidcaudio_set_port,
+ vidcaudio_get_port,
+ vidcaudio_query_devinfo,
+ 0, /* not full duplex */
+ 0
+};
+
+void vidcaudio_dummy_routine ( void *arg )
+{
+#ifdef DEBUG
+ printf ( "vidcaudio_dummy_routine\n" );
+#endif
+}
+
+int vidcaudio_hw_attach ( struct vidcaudio_softc *sc )
+{
+ return ( audio_hardware_attach ( &vidcaudio_hw_if, sc ) );
+}
+
+int vidcaudio_rate ( int rate )
+{
+ WriteWord ( VIDC_BASE, VIDC_SFR | rate );
+ return 0;
+}
+
+int vidcaudio_stereo ( int channel, int position )
+{
+ if ( channel<0 ) return EINVAL;
+ if ( channel>7 ) return EINVAL;
+ channel = channel<<24 | VIDC_SIR0;
+ WriteWord ( VIDC_BASE, channel|position );
+ return 0;
+}
+
+#define PHYS(x) (pmap_extract( kernel_pmap, ((x)&PG_FRAME) ))
+
+/*
+ * Program the next buffer to be used
+ * This function must be re-entrant, maximum re-entrancy of 2
+ */
+
+#define FLAGS (0)
+
+int vidcaudio_dma_program ( vm_offset_t cur, vm_offset_t end,
+ void (*intr)(), void *arg )
+{
+ /* If there isn't a transfer in progress then start a new one */
+ if ( ag.in_progress==0 )
+ {
+ ag.buffer = 0;
+ WriteWord ( IOMD_SD0CR, 0x90 ); /* Reset State Machine */
+ WriteWord ( IOMD_SD0CR, 0x30 ); /* Reset State Machine */
+
+ WriteWord ( IOMD_SD0CURB, PHYS(cur) );
+ WriteWord ( IOMD_SD0ENDB, PHYS(end-16)|FLAGS );
+ WriteWord ( IOMD_SD0CURA, PHYS(cur) );
+ WriteWord ( IOMD_SD0ENDA, PHYS(end-16)|FLAGS );
+
+ ag.in_progress = 1;
+
+ ag.next_cur = ag.next_end = 0;
+ ag.next_intr = ag.next_arg = 0;
+
+ ag.intr = intr;
+ ag.arg = arg;
+
+ /* The driver 'clicks' between buffer swaps, leading me to think */
+ /* that the fifo is much small than on other sound cards. So */
+ /* so I'm going to have to do some tricks here */
+
+ (*ag.intr)(ag.arg); /* Schedule the next buffer */
+ ag.intr = vidcaudio_dummy_routine; /* Already done this */
+ ag.arg = NULL;
+
+#ifdef PRINT
+printf ( "vidcaudio: start output\n" );
+#endif
+#ifdef DEBUG
+ printf ( "SE" );
+#endif
+ enable_irq ( IRQ_DMASCH0 );
+ }
+ else
+ {
+ /* Otherwise schedule the next one */
+ if ( ag.next_cur!=0 )
+ {
+ /* If there's one scheduled then complain */
+ printf ( "vidcaudio: Buffer already Q'ed\n" );
+ return EIO;
+ }
+ else
+ {
+ /* We're OK to schedule it now */
+ ag.buffer = (++ag.buffer) & 1;
+ ag.next_cur = PHYS(cur);
+ ag.next_end = PHYS(end-16);
+ ag.next_intr = intr;
+ ag.next_arg = arg;
+#ifdef DEBUG
+printf ( "s" );
+#endif
+ }
+ }
+ return 0;
+}
+
+void vidcaudio_shutdown ( void )
+{
+ /* Shut down the channel */
+ ag.intr = NULL;
+ ag.in_progress = 0;
+#ifdef PRINT
+printf ( "vidcaudio: stop output\n" );
+#endif
+ WriteWord ( IOMD_SD0CURB, ag.silence );
+ WriteWord ( IOMD_SD0ENDB, (ag.silence + NBPG - 16) | (1<<30) );
+ disable_irq ( IRQ_DMASCH0 );
+}
+
+int vidcaudio_intr ( void *arg )
+{
+ int status = ReadByte(IOMD_SD0ST);
+ void (*nintr)();
+ void *narg;
+ void (*xintr)();
+ void *xarg;
+ int xcur, xend;
+ WriteWord ( IOMD_DMARQ, 0x10 );
+
+#ifdef PRINT
+ printf ( "I" );
+#endif
+
+ if ( ag.open==0 )
+ {
+ vidcaudio_shutdown ();
+ return 0;
+ }
+
+ /* Have I got the generic audio device attached */
+
+#ifdef DEBUG
+ printf ( "[B%01x]", status );
+#endif
+
+ nintr=ag.intr;
+ narg=ag.arg;
+ ag.intr = NULL;
+
+ xintr=ag.next_intr;
+ xarg=ag.next_arg;
+ xcur=ag.next_cur;
+ xend=ag.next_end;
+ ag.next_cur = 0;
+ ag.intr = xintr;
+ ag.arg = xarg;
+
+ if ( nintr )
+ {
+#ifdef DEBUG
+ printf ( "i" );
+#endif
+ (*nintr)(narg);
+ }
+
+ if ( xcur==0 )
+ {
+ vidcaudio_shutdown ();
+ }
+ else
+ {
+#define OVERRUN (0x04)
+#define INTERRUPT (0x02)
+#define BANK_A (0x00)
+#define BANK_B (0x01)
+ switch ( status&0x7 )
+ {
+ case (INTERRUPT|BANK_A):
+#ifdef PRINT
+printf( "B" );
+#endif
+ WriteWord ( IOMD_SD0CURB, xcur );
+ WriteWord ( IOMD_SD0ENDB, xend|FLAGS );
+ break;
+
+ case (INTERRUPT|BANK_B):
+#ifdef PRINT
+printf( "A" );
+#endif
+ WriteWord ( IOMD_SD0CURA, xcur );
+ WriteWord ( IOMD_SD0ENDA, xend|FLAGS );
+ break;
+
+ case (OVERRUN|INTERRUPT|BANK_A):
+#ifdef PRINT
+printf( "A" );
+#endif
+ WriteWord ( IOMD_SD0CURA, xcur );
+ WriteWord ( IOMD_SD0ENDA, xend|FLAGS );
+ break;
+
+ case (OVERRUN|INTERRUPT|BANK_B):
+#ifdef PRINT
+printf( "B" );
+#endif
+ WriteWord ( IOMD_SD0CURB, xcur );
+ WriteWord ( IOMD_SD0ENDB, xend|FLAGS );
+ break;
+ }
+/*
+ ag.next_cur = 0;
+ ag.intr = xintr;
+ ag.arg = xarg;
+*/
+ }
+#ifdef PRINT
+printf ( "i" );
+#endif
+
+ if ( ag.next_cur==0 )
+ {
+ (*ag.intr)(ag.arg); /* Schedule the next buffer */
+ ag.intr = vidcaudio_dummy_routine; /* Already done this */
+ ag.arg = NULL;
+ }
+ return 0;
+}
+
+
diff --git a/sys/arch/arm32/mainbus/waveform.h b/sys/arch/arm32/mainbus/waveform.h
new file mode 100644
index 00000000000..1508a71d2e3
--- /dev/null
+++ b/sys/arch/arm32/mainbus/waveform.h
@@ -0,0 +1,551 @@
+/* $NetBSD: waveform.h,v 1.2 1996/03/18 20:50:06 mark Exp $ */
+
+/*
+ * Copyright (c) 1994,1995 Mark Brinicombe.
+ * Copyright (c) 1994 Brini.
+ * 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 Brini.
+ * 4. The name of the company 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 BRINI ``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 BRINI 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.
+ */
+
+static unsigned char beep_waveform[] = {
+ 0x00, 0x06, 0x18, 0x2a, 0x3e, 0x4a, 0x54, 0x60,
+ 0x64, 0x68, 0x6a, 0x6a, 0x66, 0x62, 0x54, 0x3e,
+ 0x00, 0x45, 0x61, 0x6f, 0x7f, 0x87, 0x8d, 0x91,
+ 0x93, 0x95, 0x93, 0x91, 0x8b, 0x85, 0x73, 0x59,
+ 0x00, 0x5c, 0x78, 0x8a, 0x96, 0xa0, 0xa6, 0xa8,
+ 0xaa, 0xaa, 0xa8, 0xa6, 0xa2, 0x94, 0x86, 0x6a,
+ 0x00, 0x6b, 0x8b, 0x9d, 0xa7, 0xaf, 0xb5, 0xb9,
+ 0xbb, 0xbb, 0xb9, 0xb3, 0xad, 0xa5, 0x93, 0x77,
+ 0x00, 0x78, 0x96, 0xa8, 0xb2, 0xbc, 0xc2, 0xc4,
+ 0xc6, 0xc6, 0xc4, 0xc0, 0xb8, 0xac, 0x9e, 0x82,
+ 0x00, 0x83, 0xa3, 0xb1, 0xbf, 0xc5, 0xcb, 0xcd,
+ 0xcf, 0xcf, 0xcd, 0xc9, 0xc3, 0xb7, 0xa7, 0x89,
+ 0x00, 0x88, 0xa8, 0xb8, 0xc4, 0xcc, 0xd0, 0xd4,
+ 0xd6, 0xd4, 0xd2, 0xce, 0xc8, 0xbe, 0xac, 0x8e,
+ 0x00, 0x8f, 0xaf, 0xc3, 0xcb, 0xd3, 0xd9, 0xdd,
+ 0xdf, 0xdd, 0xdb, 0xd5, 0xcf, 0xc5, 0xb3, 0x95,
+ 0x00, 0x96, 0xb4, 0xc6, 0xd0, 0xd8, 0xe0, 0xe2,
+ 0xe4, 0xe2, 0xe2, 0xdc, 0xd2, 0xc8, 0xb8, 0x9a,
+ 0x00, 0x9d, 0xbb, 0xcb, 0xd7, 0xe1, 0xe5, 0xe7,
+ 0xe9, 0xe7, 0xe5, 0xe3, 0xd9, 0xcf, 0xbf, 0xa1,
+ 0x00, 0xa2, 0xc0, 0xce, 0xdc, 0xe4, 0xe8, 0xea,
+ 0xec, 0xea, 0xe8, 0xe4, 0xde, 0xd2, 0xc2, 0xa4,
+ 0x00, 0xa5, 0xc5, 0xd5, 0xe3, 0xe7, 0xed, 0xef,
+ 0xf1, 0xef, 0xed, 0xe9, 0xe3, 0xd7, 0xc7, 0xa9,
+ 0x00, 0xa8, 0xc6, 0xd8, 0xe4, 0xea, 0xee, 0xf2,
+ 0xf4, 0xf2, 0xf0, 0xec, 0xe6, 0xda, 0xc8, 0xaa,
+ 0x00, 0xab, 0xcb, 0xdd, 0xe7, 0xef, 0xf3, 0xf7,
+ 0xf9, 0xf7, 0xf5, 0xef, 0xe9, 0xdf, 0xcd, 0xaf,
+ 0x00, 0xae, 0xcc, 0xe0, 0xea, 0xf0, 0xf6, 0xfa,
+ 0xfc, 0xfa, 0xf8, 0xf2, 0xea, 0xe2, 0xd0, 0xb0,
+ 0x00, 0xb1, 0xd1, 0xe3, 0xed, 0xf5, 0xfb, 0xff,
+ 0xff, 0xff, 0xfb, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb4,
+ 0x00, 0xb5, 0xd3, 0xe5, 0xef, 0xf7, 0xfd, 0xff,
+ 0xff, 0xff, 0xfd, 0xf7, 0xef, 0xe5, 0xd3, 0xb5,
+ 0x00, 0xb4, 0xd2, 0xe4, 0xee, 0xf6, 0xfc, 0xfe,
+ 0xfe, 0xfe, 0xfc, 0xf6, 0xee, 0xe4, 0xd2, 0xb2,
+ 0x00, 0xb3, 0xd3, 0xe5, 0xef, 0xf7, 0xfb, 0xff,
+ 0xff, 0xff, 0xfb, 0xf5, 0xef, 0xe5, 0xd1, 0xb3,
+ 0x00, 0xb2, 0xd0, 0xe4, 0xec, 0xf4, 0xfa, 0xfe,
+ 0xfe, 0xfe, 0xfa, 0xf4, 0xec, 0xe4, 0xd0, 0xb2,
+ 0x00, 0xb3, 0xd1, 0xe5, 0xed, 0xf5, 0xfb, 0xff,
+ 0xff, 0xff, 0xfb, 0xf5, 0xed, 0xe5, 0xd1, 0xb3,
+ 0x00, 0xb2, 0xd0, 0xe4, 0xec, 0xf4, 0xfa, 0xfc,
+ 0xfe, 0xfc, 0xfa, 0xf4, 0xec, 0xe2, 0xd0, 0xb2,
+ 0x00, 0xb3, 0xd1, 0xe3, 0xed, 0xf5, 0xf9, 0xfd,
+ 0xff, 0xfd, 0xf9, 0xf5, 0xed, 0xe3, 0xd1, 0xb1,
+ 0x00, 0xb0, 0xd0, 0xe2, 0xec, 0xf2, 0xf8, 0xfc,
+ 0xfc, 0xfc, 0xf8, 0xf2, 0xec, 0xe2, 0xd0, 0xb0,
+ 0x00, 0xb1, 0xcf, 0xe3, 0xed, 0xf3, 0xf9, 0xfd,
+ 0xfd, 0xfd, 0xf9, 0xf3, 0xed, 0xe3, 0xcf, 0xb1,
+ 0x00, 0xb0, 0xce, 0xe2, 0xea, 0xf2, 0xf8, 0xfa,
+ 0xfc, 0xfa, 0xf8, 0xf2, 0xea, 0xe2, 0xce, 0xb0,
+ 0x00, 0xb1, 0xcf, 0xe3, 0xeb, 0xf3, 0xf9, 0xfb,
+ 0xfd, 0xfb, 0xf7, 0xf3, 0xeb, 0xe3, 0xcf, 0xb1,
+ 0x00, 0xb0, 0xce, 0xe2, 0xea, 0xf2, 0xf6, 0xfa,
+ 0xfa, 0xfa, 0xf6, 0xf2, 0xea, 0xe2, 0xce, 0xae,
+ 0x00, 0xaf, 0xcf, 0xe3, 0xeb, 0xf1, 0xf7, 0xfb,
+ 0xfb, 0xfb, 0xf7, 0xf1, 0xeb, 0xe1, 0xcf, 0xaf,
+ 0x00, 0xae, 0xce, 0xe0, 0xea, 0xf0, 0xf6, 0xf8,
+ 0xfa, 0xf8, 0xf6, 0xf0, 0xea, 0xe0, 0xcc, 0xae,
+ 0x00, 0xaf, 0xcd, 0xe1, 0xeb, 0xf1, 0xf7, 0xf9,
+ 0xfb, 0xf9, 0xf7, 0xf1, 0xe9, 0xe1, 0xcd, 0xaf,
+ 0x00, 0xae, 0xcc, 0xe0, 0xe8, 0xf0, 0xf4, 0xf8,
+ 0xf8, 0xf8, 0xf4, 0xf0, 0xe8, 0xe0, 0xcc, 0xae,
+ 0x00, 0xaf, 0xcd, 0xe1, 0xe9, 0xf1, 0xf5, 0xf9,
+ 0xf9, 0xf9, 0xf5, 0xf1, 0xe9, 0xdf, 0xcd, 0xad,
+ 0x00, 0xac, 0xcc, 0xde, 0xe8, 0xee, 0xf4, 0xf6,
+ 0xf8, 0xf6, 0xf4, 0xee, 0xe8, 0xde, 0xcc, 0xac,
+ 0x00, 0xad, 0xcd, 0xdf, 0xe9, 0xef, 0xf5, 0xf7,
+ 0xf9, 0xf7, 0xf5, 0xef, 0xe9, 0xdf, 0xcb, 0xad,
+ 0x00, 0xac, 0xca, 0xde, 0xe8, 0xee, 0xf2, 0xf6,
+ 0xf6, 0xf6, 0xf2, 0xee, 0xe8, 0xde, 0xca, 0xac,
+ 0x00, 0xad, 0xcb, 0xdd, 0xe7, 0xef, 0xf3, 0xf7,
+ 0xf7, 0xf7, 0xf3, 0xef, 0xe7, 0xdd, 0xcb, 0xad,
+ 0x00, 0xac, 0xca, 0xdc, 0xe6, 0xee, 0xf2, 0xf4,
+ 0xf6, 0xf4, 0xf2, 0xee, 0xe6, 0xdc, 0xca, 0xaa,
+ 0x00, 0xab, 0xcb, 0xdd, 0xe7, 0xed, 0xf3, 0xf5,
+ 0xf7, 0xf5, 0xf3, 0xed, 0xe7, 0xdd, 0xcb, 0xab,
+ 0x00, 0xaa, 0xca, 0xdc, 0xe6, 0xec, 0xf2, 0xf4,
+ 0xf4, 0xf4, 0xf0, 0xec, 0xe6, 0xda, 0xc8, 0xaa,
+ 0x00, 0xab, 0xc9, 0xdb, 0xe7, 0xed, 0xf1, 0xf5,
+ 0xf5, 0xf5, 0xf1, 0xed, 0xe7, 0xdb, 0xc9, 0xab,
+ 0x00, 0xaa, 0xc8, 0xda, 0xe6, 0xec, 0xf0, 0xf4,
+ 0xf4, 0xf2, 0xf0, 0xec, 0xe6, 0xda, 0xc8, 0xaa,
+ 0x00, 0xab, 0xc9, 0xdb, 0xe5, 0xed, 0xf1, 0xf3,
+ 0xf5, 0xf3, 0xf1, 0xeb, 0xe5, 0xdb, 0xc9, 0xa9,
+ 0x00, 0xa8, 0xc8, 0xd8, 0xe4, 0xea, 0xf0, 0xf2,
+ 0xf2, 0xf2, 0xf0, 0xea, 0xe4, 0xd8, 0xc8, 0xa8,
+ 0x00, 0xa9, 0xc9, 0xd9, 0xe5, 0xeb, 0xef, 0xf3,
+ 0xf3, 0xf3, 0xef, 0xeb, 0xe5, 0xd9, 0xc9, 0xa9,
+ 0x00, 0xa8, 0xc6, 0xd8, 0xe4, 0xea, 0xee, 0xf2,
+ 0xf2, 0xf2, 0xee, 0xea, 0xe4, 0xd8, 0xc6, 0xa8,
+ 0x00, 0xa9, 0xc7, 0xd9, 0xe5, 0xeb, 0xef, 0xf1,
+ 0xf3, 0xf1, 0xef, 0xeb, 0xe5, 0xd7, 0xc7, 0xa9,
+ 0x00, 0xa8, 0xc6, 0xd6, 0xe4, 0xea, 0xee, 0xf0,
+ 0xf0, 0xf0, 0xee, 0xe8, 0xe2, 0xd6, 0xc6, 0xa8,
+ 0x00, 0xa7, 0xc7, 0xd7, 0xe3, 0xe9, 0xed, 0xf1,
+ 0xf1, 0xf1, 0xed, 0xe9, 0xe3, 0xd7, 0xc7, 0xa7,
+ 0x00, 0xa6, 0xc6, 0xd6, 0xe2, 0xe8, 0xec, 0xf0,
+ 0xf0, 0xf0, 0xec, 0xe8, 0xe2, 0xd6, 0xc6, 0xa6,
+ 0x00, 0xa7, 0xc5, 0xd7, 0xe3, 0xe9, 0xed, 0xef,
+ 0xf1, 0xef, 0xed, 0xe9, 0xe3, 0xd5, 0xc5, 0xa7,
+ 0x00, 0xa6, 0xc4, 0xd4, 0xe2, 0xe8, 0xec, 0xee,
+ 0xee, 0xee, 0xec, 0xe8, 0xe2, 0xd4, 0xc4, 0xa6,
+ 0x00, 0xa7, 0xc5, 0xd5, 0xe3, 0xe7, 0xed, 0xef,
+ 0xef, 0xef, 0xeb, 0xe7, 0xe3, 0xd5, 0xc5, 0xa7,
+ 0x00, 0xa6, 0xc4, 0xd4, 0xe0, 0xe6, 0xea, 0xee,
+ 0xee, 0xee, 0xea, 0xe6, 0xe0, 0xd4, 0xc4, 0xa4,
+ 0x00, 0xa5, 0xc5, 0xd3, 0xe1, 0xe7, 0xeb, 0xed,
+ 0xef, 0xed, 0xeb, 0xe7, 0xe1, 0xd3, 0xc5, 0xa5,
+ 0x00, 0xa4, 0xc4, 0xd2, 0xe0, 0xe6, 0xea, 0xec,
+ 0xec, 0xec, 0xea, 0xe6, 0xe0, 0xd2, 0xc2, 0xa4,
+ 0x00, 0xa5, 0xc3, 0xd3, 0xdf, 0xe7, 0xeb, 0xed,
+ 0xed, 0xed, 0xeb, 0xe7, 0xdf, 0xd3, 0xc3, 0xa5,
+ 0x00, 0xa4, 0xc2, 0xd2, 0xde, 0xe4, 0xe8, 0xec,
+ 0xec, 0xec, 0xe8, 0xe4, 0xde, 0xd0, 0xc2, 0xa4,
+ 0x00, 0xa5, 0xc3, 0xd1, 0xdf, 0xe5, 0xe9, 0xeb,
+ 0xed, 0xeb, 0xe9, 0xe5, 0xdf, 0xd1, 0xc3, 0xa3,
+ 0x00, 0xa2, 0xc2, 0xd0, 0xdc, 0xe4, 0xe8, 0xea,
+ 0xea, 0xea, 0xe8, 0xe4, 0xdc, 0xd0, 0xc2, 0xa2,
+ 0x00, 0xa3, 0xc3, 0xd1, 0xdd, 0xe5, 0xe9, 0xeb,
+ 0xeb, 0xeb, 0xe9, 0xe5, 0xdd, 0xd1, 0xc1, 0xa3,
+ 0x00, 0xa2, 0xc0, 0xce, 0xdc, 0xe4, 0xe6, 0xea,
+ 0xea, 0xea, 0xe6, 0xe4, 0xda, 0xce, 0xc0, 0xa2,
+ 0x00, 0xa3, 0xc1, 0xcf, 0xdb, 0xe3, 0xe7, 0xe9,
+ 0xeb, 0xe9, 0xe7, 0xe3, 0xdb, 0xcf, 0xc1, 0xa3,
+ 0x00, 0xa2, 0xc0, 0xce, 0xda, 0xe2, 0xe6, 0xe8,
+ 0xe8, 0xe8, 0xe6, 0xe2, 0xda, 0xce, 0xbe, 0xa0,
+ 0x00, 0xa1, 0xbf, 0xcf, 0xdb, 0xe3, 0xe7, 0xe9,
+ 0xe9, 0xe9, 0xe7, 0xe3, 0xd9, 0xcd, 0xbf, 0xa1,
+ 0x00, 0xa0, 0xbe, 0xcc, 0xd8, 0xe2, 0xe6, 0xe8,
+ 0xe8, 0xe8, 0xe4, 0xe2, 0xd8, 0xcc, 0xbc, 0x9e,
+ 0x00, 0x9f, 0xbd, 0xcd, 0xd9, 0xe3, 0xe5, 0xe7,
+ 0xe9, 0xe7, 0xe5, 0xe1, 0xd9, 0xcd, 0xbd, 0x9f,
+ 0x00, 0x9e, 0xbc, 0xcc, 0xd8, 0xe0, 0xe4, 0xe6,
+ 0xe6, 0xe6, 0xe4, 0xe0, 0xd6, 0xcc, 0xbc, 0x9e,
+ 0x00, 0x9f, 0xbd, 0xcd, 0xd7, 0xe1, 0xe5, 0xe7,
+ 0xe7, 0xe7, 0xe5, 0xe1, 0xd7, 0xcb, 0xbb, 0x9d,
+ 0x00, 0x9c, 0xba, 0xca, 0xd6, 0xde, 0xe4, 0xe6,
+ 0xe6, 0xe6, 0xe4, 0xde, 0xd6, 0xca, 0xba, 0x9c,
+ 0x00, 0x9d, 0xbb, 0xcb, 0xd5, 0xdf, 0xe3, 0xe5,
+ 0xe7, 0xe5, 0xe3, 0xdf, 0xd5, 0xcb, 0xbb, 0x9d,
+ 0x00, 0x9a, 0xb8, 0xca, 0xd4, 0xde, 0xe2, 0xe4,
+ 0xe4, 0xe4, 0xe2, 0xdc, 0xd4, 0xca, 0xb8, 0x9a,
+ 0x00, 0x9b, 0xb9, 0xc9, 0xd5, 0xdd, 0xe3, 0xe5,
+ 0xe5, 0xe5, 0xe3, 0xdd, 0xd5, 0xc9, 0xb9, 0x9b,
+ 0x00, 0x9a, 0xb8, 0xc8, 0xd2, 0xdc, 0xe2, 0xe4,
+ 0xe4, 0xe4, 0xe2, 0xdc, 0xd2, 0xc8, 0xb6, 0x98,
+ 0x00, 0x99, 0xb7, 0xc9, 0xd3, 0xdb, 0xe1, 0xe3,
+ 0xe5, 0xe3, 0xe1, 0xdb, 0xd3, 0xc9, 0xb7, 0x99,
+ 0x00, 0x98, 0xb6, 0xc8, 0xd2, 0xda, 0xe0, 0xe2,
+ 0xe2, 0xe2, 0xe0, 0xda, 0xd2, 0xc6, 0xb6, 0x98,
+ 0x00, 0x99, 0xb7, 0xc7, 0xd1, 0xd9, 0xdf, 0xe3,
+ 0xe3, 0xe3, 0xdf, 0xd9, 0xd1, 0xc7, 0xb5, 0x97,
+ 0x00, 0x96, 0xb4, 0xc6, 0xd0, 0xd8, 0xde, 0xe2,
+ 0xe2, 0xe2, 0xde, 0xd8, 0xd0, 0xc6, 0xb4, 0x96,
+ 0x00, 0x97, 0xb5, 0xc7, 0xd1, 0xd9, 0xdf, 0xe1,
+ 0xe3, 0xe1, 0xdd, 0xd7, 0xcf, 0xc7, 0xb3, 0x95,
+ 0x00, 0x94, 0xb2, 0xc4, 0xce, 0xd6, 0xdc, 0xe0,
+ 0xe0, 0xe0, 0xdc, 0xd6, 0xce, 0xc4, 0xb2, 0x94,
+ 0x00, 0x95, 0xb3, 0xc5, 0xcf, 0xd7, 0xdd, 0xdf,
+ 0xe1, 0xdf, 0xdd, 0xd7, 0xcf, 0xc5, 0xb3, 0x95,
+ 0x00, 0x94, 0xb2, 0xc4, 0xce, 0xd4, 0xda, 0xde,
+ 0xde, 0xde, 0xda, 0xd4, 0xcc, 0xc4, 0xb0, 0x92,
+ 0x00, 0x93, 0xb1, 0xc5, 0xcd, 0xd5, 0xdb, 0xdd,
+ 0xdf, 0xdd, 0xdb, 0xd5, 0xcd, 0xc3, 0xb1, 0x93,
+ 0x00, 0x92, 0xb0, 0xc2, 0xcc, 0xd4, 0xd8, 0xdc,
+ 0xdc, 0xdc, 0xd8, 0xd2, 0xcc, 0xc2, 0xb0, 0x90,
+ 0x00, 0x91, 0xaf, 0xc3, 0xcb, 0xd3, 0xd9, 0xdb,
+ 0xdd, 0xdb, 0xd9, 0xd3, 0xcb, 0xc3, 0xaf, 0x91,
+ 0x00, 0x90, 0xae, 0xc2, 0xca, 0xd2, 0xd6, 0xda,
+ 0xda, 0xda, 0xd6, 0xd2, 0xca, 0xc2, 0xae, 0x90,
+ 0x00, 0x91, 0xaf, 0xc3, 0xcb, 0xd1, 0xd7, 0xd9,
+ 0xdb, 0xd9, 0xd7, 0xd1, 0xcb, 0xc1, 0xad, 0x8f,
+ 0x00, 0x8e, 0xac, 0xc0, 0xc8, 0xd0, 0xd4, 0xd8,
+ 0xd8, 0xd8, 0xd4, 0xd0, 0xc8, 0xc0, 0xac, 0x8e,
+ 0x00, 0x8f, 0xad, 0xbf, 0xc9, 0xcf, 0xd5, 0xd7,
+ 0xd9, 0xd7, 0xd5, 0xcf, 0xc9, 0xbf, 0xad, 0x8f,
+ 0x00, 0x8c, 0xac, 0xbe, 0xc8, 0xce, 0xd2, 0xd6,
+ 0xd6, 0xd6, 0xd2, 0xce, 0xc8, 0xbe, 0xaa, 0x8c,
+ 0x00, 0x8d, 0xab, 0xbd, 0xc7, 0xcf, 0xd3, 0xd5,
+ 0xd7, 0xd5, 0xd3, 0xcd, 0xc7, 0xbd, 0xab, 0x8d,
+ 0x00, 0x8c, 0xaa, 0xbc, 0xc6, 0xcc, 0xd2, 0xd4,
+ 0xd4, 0xd4, 0xd0, 0xcc, 0xc6, 0xba, 0xaa, 0x8a,
+ 0x00, 0x8b, 0xa9, 0xbb, 0xc7, 0xcd, 0xd1, 0xd5,
+ 0xd5, 0xd3, 0xd1, 0xcd, 0xc5, 0xbb, 0xa9, 0x8b,
+ 0x00, 0x8a, 0xa8, 0xba, 0xc4, 0xca, 0xd0, 0xd2,
+ 0xd2, 0xd2, 0xd0, 0xca, 0xc4, 0xb8, 0xa8, 0x8a,
+ 0x00, 0x8b, 0xa9, 0xb9, 0xc5, 0xcb, 0xcf, 0xd3,
+ 0xd3, 0xd1, 0xcf, 0xcb, 0xc5, 0xb9, 0xa7, 0x89,
+ 0x00, 0x88, 0xa6, 0xb8, 0xc4, 0xca, 0xce, 0xd0,
+ 0xd0, 0xd0, 0xce, 0xc8, 0xc2, 0xb6, 0xa6, 0x88,
+ 0x00, 0x89, 0xa7, 0xb7, 0xc3, 0xc9, 0xcd, 0xd1,
+ 0xd1, 0xcf, 0xcd, 0xc9, 0xc3, 0xb7, 0xa7, 0x87,
+ 0x00, 0x86, 0xa6, 0xb4, 0xc2, 0xc8, 0xcc, 0xce,
+ 0xce, 0xce, 0xcc, 0xc8, 0xc2, 0xb4, 0xa4, 0x86,
+ 0x00, 0x87, 0xa5, 0xb5, 0xc3, 0xc7, 0xcb, 0xcf,
+ 0xcf, 0xcf, 0xcb, 0xc7, 0xc1, 0xb5, 0xa5, 0x87,
+ 0x00, 0x86, 0xa4, 0xb2, 0xc0, 0xc6, 0xca, 0xcc,
+ 0xcc, 0xcc, 0xca, 0xc6, 0xc0, 0xb2, 0xa2, 0x84,
+ 0x00, 0x85, 0xa3, 0xb3, 0xbf, 0xc5, 0xc9, 0xcd,
+ 0xcd, 0xcd, 0xc9, 0xc5, 0xbf, 0xb1, 0xa3, 0x85,
+ 0x00, 0x84, 0xa2, 0xb0, 0xbc, 0xc4, 0xc8, 0xca,
+ 0xca, 0xca, 0xc8, 0xc4, 0xbc, 0xb0, 0xa2, 0x82,
+ 0x00, 0x83, 0xa3, 0xb1, 0xbd, 0xc5, 0xc7, 0xcb,
+ 0xcb, 0xcb, 0xc7, 0xc3, 0xbb, 0xaf, 0xa1, 0x83,
+ 0x00, 0x82, 0xa0, 0xae, 0xba, 0xc2, 0xc6, 0xc8,
+ 0xc8, 0xc8, 0xc6, 0xc2, 0xba, 0xae, 0x9e, 0x82,
+ 0x00, 0x83, 0x9f, 0xaf, 0xb9, 0xc3, 0xc7, 0xc9,
+ 0xc9, 0xc9, 0xc5, 0xc3, 0xb9, 0xad, 0x9f, 0x81,
+ 0x00, 0x80, 0x9c, 0xac, 0xb8, 0xc0, 0xc4, 0xc6,
+ 0xc6, 0xc6, 0xc4, 0xc0, 0xb6, 0xac, 0x9c, 0x7e,
+ 0x00, 0x7f, 0x9d, 0xab, 0xb7, 0xbf, 0xc5, 0xc7,
+ 0xc7, 0xc7, 0xc5, 0xbf, 0xb7, 0xab, 0x9b, 0x7d,
+ 0x00, 0x7c, 0x9a, 0xaa, 0xb4, 0xbe, 0xc2, 0xc4,
+ 0xc4, 0xc4, 0xc2, 0xbc, 0xb4, 0xaa, 0x98, 0x7c,
+ 0x00, 0x7d, 0x99, 0xa9, 0xb5, 0xbd, 0xc3, 0xc5,
+ 0xc5, 0xc5, 0xc3, 0xbb, 0xb3, 0xa9, 0x99, 0x7b,
+ 0x00, 0x7a, 0x96, 0xa8, 0xb2, 0xba, 0xc0, 0xc2,
+ 0xc2, 0xc2, 0xc0, 0xba, 0xb0, 0xa6, 0x96, 0x78,
+ 0x00, 0x79, 0x97, 0xa7, 0xb1, 0xb9, 0xbf, 0xc3,
+ 0xc3, 0xc3, 0xbf, 0xb9, 0xb1, 0xa7, 0x95, 0x77,
+ 0x00, 0x76, 0x94, 0xa6, 0xae, 0xb6, 0xbc, 0xc0,
+ 0xc0, 0xc0, 0xbc, 0xb6, 0xae, 0xa4, 0x92, 0x76,
+ 0x00, 0x75, 0x93, 0xa5, 0xaf, 0xb5, 0xbb, 0xbf,
+ 0xbf, 0xbf, 0xbb, 0xb5, 0xad, 0xa5, 0x91, 0x75,
+ 0x00, 0x74, 0x90, 0xa4, 0xac, 0xb4, 0xb8, 0xbc,
+ 0xbc, 0xbc, 0xb8, 0xb2, 0xac, 0xa2, 0x90, 0x72,
+ 0x00, 0x73, 0x91, 0xa3, 0xab, 0xb3, 0xb7, 0xbb,
+ 0xbb, 0xbb, 0xb7, 0xb1, 0xab, 0xa3, 0x8f, 0x71,
+ 0x00, 0x70, 0x8e, 0xa0, 0xaa, 0xb0, 0xb4, 0xb8,
+ 0xb8, 0xb8, 0xb4, 0xb0, 0xa8, 0xa0, 0x8c, 0x6e,
+ 0x00, 0x6f, 0x8d, 0x9f, 0xa9, 0xaf, 0xb5, 0xb7,
+ 0xb7, 0xb7, 0xb3, 0xaf, 0xa9, 0x9f, 0x8b, 0x6f,
+ 0x00, 0x6e, 0x8a, 0x9c, 0xa6, 0xac, 0xb2, 0xb4,
+ 0xb4, 0xb4, 0xb0, 0xac, 0xa6, 0x9a, 0x8a, 0x6c,
+ 0x00, 0x6d, 0x89, 0x9b, 0xa5, 0xab, 0xb1, 0xb3,
+ 0xb3, 0xb3, 0xaf, 0xab, 0xa5, 0x99, 0x89, 0x6b,
+ 0x00, 0x6a, 0x88, 0x98, 0xa4, 0xaa, 0xae, 0xb0,
+ 0xb0, 0xb0, 0xae, 0xa8, 0xa2, 0x96, 0x86, 0x68,
+ 0x00, 0x69, 0x87, 0x97, 0xa3, 0xa9, 0xad, 0xaf,
+ 0xaf, 0xaf, 0xad, 0xa7, 0xa3, 0x95, 0x85, 0x69,
+ 0x00, 0x66, 0x84, 0x94, 0xa0, 0xa6, 0xaa, 0xac,
+ 0xac, 0xac, 0xaa, 0xa6, 0x9e, 0x92, 0x84, 0x66,
+ 0x00, 0x67, 0x83, 0x93, 0x9f, 0xa5, 0xa9, 0xab,
+ 0xab, 0xab, 0xa9, 0xa5, 0x9d, 0x91, 0x83, 0x65,
+ 0x00, 0x64, 0x82, 0x8e, 0x9a, 0xa2, 0xa6, 0xa8,
+ 0xa8, 0xa8, 0xa6, 0xa2, 0x9a, 0x8e, 0x80, 0x62,
+ 0x00, 0x63, 0x7f, 0x8d, 0x99, 0xa1, 0xa5, 0xa7,
+ 0xa7, 0xa7, 0xa5, 0xa1, 0x97, 0x8d, 0x7d, 0x61,
+ 0x00, 0x60, 0x7c, 0x8a, 0x94, 0x9e, 0xa2, 0xa4,
+ 0xa4, 0xa4, 0xa2, 0x9c, 0x94, 0x8a, 0x7a, 0x5e,
+ 0x00, 0x5f, 0x79, 0x89, 0x93, 0x9b, 0xa1, 0xa3,
+ 0xa3, 0xa3, 0xa1, 0x9b, 0x91, 0x87, 0x77, 0x5b,
+ 0x00, 0x5a, 0x76, 0x86, 0x90, 0x96, 0x9c, 0xa0,
+ 0xa0, 0xa0, 0x9c, 0x96, 0x8e, 0x84, 0x72, 0x58,
+ 0x00, 0x59, 0x73, 0x85, 0x8d, 0x95, 0x99, 0x9d,
+ 0x9d, 0x9d, 0x99, 0x93, 0x8d, 0x83, 0x71, 0x55,
+ 0x00, 0x54, 0x70, 0x82, 0x8a, 0x90, 0x96, 0x98,
+ 0x98, 0x98, 0x94, 0x90, 0x88, 0x80, 0x6c, 0x52,
+ 0x00, 0x51, 0x6d, 0x7f, 0x87, 0x8d, 0x93, 0x95,
+ 0x95, 0x95, 0x91, 0x8d, 0x87, 0x7b, 0x6b, 0x4f,
+ 0x00, 0x4e, 0x6a, 0x7a, 0x84, 0x8a, 0x8e, 0x90,
+ 0x90, 0x90, 0x8c, 0x88, 0x82, 0x76, 0x66, 0x4a,
+ 0x00, 0x4b, 0x67, 0x75, 0x83, 0x87, 0x8b, 0x8d,
+ 0x8d, 0x8d, 0x8b, 0x87, 0x7f, 0x73, 0x65, 0x49,
+ 0x00, 0x48, 0x62, 0x70, 0x7c, 0x82, 0x86, 0x88,
+ 0x88, 0x88, 0x86, 0x82, 0x78, 0x6e, 0x60, 0x44,
+ 0x00, 0x45, 0x5f, 0x6d, 0x77, 0x7f, 0x83, 0x85,
+ 0x85, 0x85, 0x83, 0x7d, 0x75, 0x6b, 0x5b, 0x43,
+ 0x00, 0x42, 0x58, 0x68, 0x70, 0x78, 0x7c, 0x80,
+ 0x80, 0x7e, 0x7c, 0x76, 0x6e, 0x64, 0x54, 0x3c,
+ 0x00, 0x3d, 0x53, 0x63, 0x6b, 0x73, 0x77, 0x79,
+ 0x79, 0x79, 0x75, 0x6f, 0x69, 0x61, 0x4f, 0x37,
+ 0x00, 0x34, 0x4c, 0x5c, 0x66, 0x6a, 0x6e, 0x70,
+ 0x70, 0x70, 0x6c, 0x68, 0x62, 0x56, 0x48, 0x30,
+ 0x00, 0x2f, 0x47, 0x55, 0x5f, 0x65, 0x67, 0x69,
+ 0x69, 0x69, 0x65, 0x63, 0x59, 0x4f, 0x43, 0x2b,
+ 0x00, 0x28, 0x40, 0x4a, 0x52, 0x5a, 0x5e, 0x60,
+ 0x60, 0x5e, 0x5a, 0x54, 0x4c, 0x44, 0x36, 0x22,
+ 0x00, 0x23, 0x33, 0x43, 0x49, 0x4d, 0x4f, 0x51,
+ 0x51, 0x4f, 0x4d, 0x47, 0x43, 0x37, 0x2b, 0x19,
+ 0x00, 0x16, 0x26, 0x30, 0x36, 0x3c, 0x40, 0x40,
+ 0x40, 0x3c, 0x38, 0x32, 0x2c, 0x24, 0x1a, 0x0c,
+ 0x00, 0x0b, 0x15, 0x1b, 0x21, 0x23, 0x23, 0x21,
+ 0x1f, 0x19, 0x15, 0x0f, 0x09, 0x05, 0x03, 0x00,
+};
+
+/* End of waveform.h */
diff --git a/sys/arch/arm32/mainbus/wd.c b/sys/arch/arm32/mainbus/wd.c
new file mode 100644
index 00000000000..e54e2e2a127
--- /dev/null
+++ b/sys/arch/arm32/mainbus/wd.c
@@ -0,0 +1,1764 @@
+/* $NetBSD: wd.c,v 1.6 1996/03/28 21:52:52 mark Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Charles M. Hannum. All rights reserved.
+ *
+ * DMA and multi-sector PIO handling are derived from code contributed by
+ * Onno van der Linden.
+ *
+ * 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 Charles M. Hannum.
+ * 4. 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.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/conf.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/buf.h>
+#include <sys/uio.h>
+#include <sys/malloc.h>
+#include <sys/device.h>
+#include <sys/disklabel.h>
+#include <sys/disk.h>
+#include <sys/syslog.h>
+
+#include <vm/vm.h>
+
+#include <machine/cpu.h>
+
+#include <arm32/mainbus/wdreg.h>
+#include <arm32/mainbus/mainbus.h>
+#include <machine/irqhandler.h>
+#include <machine/io.h>
+#include <machine/katelib.h>
+
+extern int wdresethack;
+
+#define WAITTIME (4 * hz) /* time to wait for a completion */
+#define RECOVERYTIME (hz / 2) /* time to recover from an error */
+
+#define WDCDELAY 100
+#define WDCNDELAY 100000 /* delay = 100us; so 10s for a controller state change */
+#if 0
+/* If you enable this, it will report any delays more than 100us * N long. */
+#define WDCNDELAY_DEBUG 10
+#endif
+
+#define WDIORETRIES 5 /* number of retries before giving up */
+
+#define WDUNIT(dev) DISKUNIT(dev)
+#define WDPART(dev) DISKPART(dev)
+#define MAKEWDDEV(maj, unit, part) MAKEDISKDEV(maj, unit, part)
+
+#define WDLABELDEV(dev) (MAKEWDDEV(major(dev), WDUNIT(dev), RAW_PART))
+
+struct wd_softc {
+ struct device sc_dev;
+ struct disk sc_dk;
+
+ /* Information about the current transfer: */
+ daddr_t sc_blkno; /* starting block number */
+ int sc_bcount; /* byte count left */
+ int sc_skip; /* bytes already transferred */
+ int sc_nblks; /* number of blocks currently transferring */
+ int sc_nbytes; /* number of bytes currently transferring */
+
+ /* Long-term state: */
+ int sc_drive; /* physical unit number */
+ int sc_state; /* control state */
+#define RECAL 0 /* recalibrate */
+#define RECAL_WAIT 1 /* done recalibrating */
+#define GEOMETRY 2 /* upload geometry */
+#define GEOMETRY_WAIT 3 /* done uploading geometry */
+#define MULTIMODE 4 /* set multiple mode */
+#define MULTIMODE_WAIT 5 /* done setting multiple mode */
+#define OPEN 6 /* done with open */
+ int sc_mode; /* transfer mode */
+#define WDM_PIOSINGLE 0 /* single-sector PIO */
+#define WDM_PIOMULTI 1 /* multi-sector PIO */
+#define WDM_DMA 2 /* DMA */
+ int sc_multiple; /* multiple for WDM_PIOMULTI */
+ int sc_flags; /* drive characteistics found */
+#define WDF_LOCKED 0x01
+#define WDF_WANTED 0x02
+#define WDF_WLABEL 0x04 /* label is writable */
+#define WDF_LABELLING 0x08 /* writing label */
+/* XXX Nothing resets this yet, but disk change sensing will when ATAPI is
+ implemented. */
+#define WDF_LOADED 0x10 /* parameters loaded */
+#define WDF_32BIT 0x20 /* can do 32-bit transfer */
+
+ struct wdparams sc_params; /* ESDI/ATA drive parameters */
+ daddr_t sc_badsect[127]; /* 126 plus trailing -1 marker */
+
+ TAILQ_ENTRY(wd_softc) sc_drivechain;
+ struct buf sc_q;
+};
+
+struct wdc_softc {
+ struct device sc_dev;
+ irqhandler_t sc_ih;
+
+ int sc_iobase; /* I/O port base */
+ int sc_drq; /* DMA channel */
+
+ TAILQ_HEAD(drivehead, wd_softc) sc_drives;
+ int sc_flags;
+#define WDCF_ACTIVE 0x01 /* controller is active */
+#define WDCF_SINGLE 0x02 /* sector at a time mode */
+#define WDCF_ERROR 0x04 /* processing a disk error */
+#define WDCF_WANTED 0x08 /* XXX locking for wd_get_parms() */
+ int sc_errors; /* errors during current transfer */
+ u_char sc_status; /* copy of status register */
+ u_char sc_error; /* copy of error register */
+};
+
+int wdcprobe __P((struct device *, void *, void *));
+void wdcattach __P((struct device *, struct device *, void *));
+
+struct cfattach wdc_ca = {
+ sizeof(struct wdc_softc), wdcprobe, wdcattach
+};
+
+struct cfdriver wdc_cd = {
+ NULL, "wdc", DV_DULL
+};
+
+int wdprobe __P((struct device *, void *, void *));
+void wdattach __P((struct device *, struct device *, void *));
+
+struct cfattach wd_ca = {
+ sizeof(struct wd_softc), wdprobe, wdattach
+};
+
+struct cfdriver wd_cd = {
+ NULL, "wd", DV_DISK
+};
+
+void wdgetdisklabel __P((struct wd_softc *));
+int wd_get_parms __P((struct wd_softc *));
+void wdstrategy __P((struct buf *));
+void wdstart __P((struct wd_softc *));
+
+struct dkdriver wddkdriver = { wdstrategy };
+
+void wdfinish __P((struct wd_softc *, struct buf *));
+int wdcintr __P((void *));
+void wdcstart __P((struct wdc_softc *));
+int wdcommand __P((struct wd_softc *, int, int, int, int, int));
+int wdcommandshort __P((struct wdc_softc *, int, int));
+int wdcontrol __P((struct wd_softc *));
+int wdsetctlr __P((struct wd_softc *));
+static void bad144intern __P((struct wd_softc *));
+int wdcreset __P((struct wdc_softc *));
+void wdcrestart __P((void *arg));
+void wdcunwedge __P((struct wdc_softc *));
+void wdctimeout __P((void *arg));
+void wderror __P((void *, struct buf *, char *));
+int wdcwait __P((struct wdc_softc *, int));
+/* ST506 spec says that if READY or SEEKCMPLT go off, then the read or write
+ command is aborted. */
+#define wait_for_drq(d) wdcwait(d, WDCS_DRDY | WDCS_DSC | WDCS_DRQ)
+#define wait_for_ready(d) wdcwait(d, WDCS_DRDY | WDCS_DSC)
+#define wait_for_unbusy(d) wdcwait(d, 0)
+
+int
+wdcprobe(parent, match, aux)
+ struct device *parent;
+ void *match, *aux;
+{
+ struct wdc_softc *wdc = match;
+ struct mainbus_attach_args *mb = aux;
+ int iobase;
+
+ wdc->sc_iobase = iobase = mb->mb_iobase;
+
+ /* Check if we have registers that work. */
+ outb(iobase+wd_error, 0x5a); /* Error register not writable, */
+ outb(iobase+wd_cyl_lo, 0xa5); /* but all of cyllo are. */
+ if (inb(iobase+wd_error) == 0x5a || inb(iobase+wd_cyl_lo) != 0xa5)
+ return 0;
+
+ if (wdcreset(wdc) != 0) {
+ delay(500000);
+ if (wdcreset(wdc) != 0)
+ return 0;
+ }
+
+ /* Select drive 0. */
+ outb(iobase+wd_sdh, WDSD_IBM | 0);
+
+ /* Wait for controller to become ready. */
+ if (wait_for_unbusy(wdc) < 0)
+ return 0;
+
+ /* Start drive diagnostics. */
+ outb(iobase+wd_command, WDCC_DIAGNOSE);
+
+ /* Wait for command to complete. */
+ if (wait_for_unbusy(wdc) < 0)
+ return 0;
+
+ mb->mb_iosize = 32;
+ return 1;
+}
+
+struct wdc_attach_args {
+ int wa_drive;
+};
+
+int
+wdprint(aux, wdc)
+ void *aux;
+ char *wdc;
+{
+ struct wdc_attach_args *wa = aux;
+
+ if (!wdc)
+ printf(" drive %d", wa->wa_drive);
+ return QUIET;
+}
+
+void
+wdcattach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct wdc_softc *wdc = (void *)self;
+ struct mainbus_attach_args *mb = aux;
+ struct wdc_attach_args wa;
+
+ TAILQ_INIT(&wdc->sc_drives);
+ wdc->sc_drq = mb->mb_drq;
+
+ printf("\n");
+
+ wdc->sc_ih.ih_func = wdcintr;
+ wdc->sc_ih.ih_arg = wdc;
+ wdc->sc_ih.ih_level = IPL_BIO;
+ wdc->sc_ih.ih_name = "wdc";
+ if (irq_claim(mb->mb_irq, &wdc->sc_ih))
+ panic("Cannot claim IRQ %d for wdc%d\n", mb->mb_irq, parent->dv_unit);
+
+ for (wa.wa_drive = 0; wa.wa_drive < 2; wa.wa_drive++)
+ (void)config_found(self, (void *)&wa, wdprint);
+}
+
+int
+wdprobe(parent, match, aux)
+ struct device *parent;
+ void *match, *aux;
+{
+ struct wdc_softc *wdc = (void *)parent;
+ struct cfdata *cf = match;
+ struct wdc_attach_args *wa = aux;
+ int drive = wa->wa_drive;
+
+ if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != drive)
+ return 0;
+
+ if (wdcommandshort(wdc, drive, WDCC_RECAL) != 0 ||
+ wait_for_ready(wdc) != 0)
+ return 0;
+
+ return 1;
+}
+
+void
+wdattach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct wd_softc *wd = (void *)self;
+ struct wdc_softc *wdc = (void *)parent;
+ struct wdc_attach_args *wa = aux;
+ int i, blank;
+ char buf[41], c, *p, *q;
+
+ wd->sc_drive = wa->wa_drive;
+
+ /*
+ * Initialize and attach the disk structure.
+ */
+ wd->sc_dk.dk_driver = &wddkdriver;
+ wd->sc_dk.dk_name = wd->sc_dev.dv_xname;
+ disk_attach(&wd->sc_dk);
+
+ wd_get_parms(wd);
+ for (blank = 0, p = wd->sc_params.wdp_model, q = buf, i = 0;
+ i < sizeof(wd->sc_params.wdp_model); i++) {
+ c = *p++;
+ if (c == '\0')
+ break;
+ if (c != ' ') {
+ if (blank) {
+ *q++ = ' ';
+ blank = 0;
+ }
+ *q++ = c;
+ } else
+ blank = 1;
+ }
+ *q++ = '\0';
+
+ printf(": %dMB, %d cyl, %d head, %d sec, %d bytes/sec <%s>\n",
+ wd->sc_params.wdp_cylinders *
+ (wd->sc_params.wdp_heads * wd->sc_params.wdp_sectors) /
+ (1048576 / DEV_BSIZE),
+ wd->sc_params.wdp_cylinders,
+ wd->sc_params.wdp_heads,
+ wd->sc_params.wdp_sectors,
+ DEV_BSIZE,
+ buf);
+
+ if ((wd->sc_params.wdp_capabilities & WD_CAP_DMA) != 0 &&
+ wdc->sc_drq != DRQUNK) {
+ wd->sc_mode = WDM_DMA;
+ } else if (wd->sc_params.wdp_maxmulti > 1) {
+ wd->sc_mode = WDM_PIOMULTI;
+ wd->sc_multiple = min(wd->sc_params.wdp_maxmulti, 16);
+ } else {
+ wd->sc_mode = WDM_PIOSINGLE;
+ wd->sc_multiple = 1;
+ }
+
+ printf("%s: using", wd->sc_dev.dv_xname);
+ if (wd->sc_mode == WDM_DMA)
+ printf(" dma transfers,");
+ else
+ printf(" %d-sector %d-bit pio transfers,",
+ wd->sc_multiple, (wd->sc_flags & WDF_32BIT) == 0 ? 16 : 32);
+ if ((wd->sc_params.wdp_capabilities & WD_CAP_LBA) != 0)
+ printf(" lba addressing\n");
+ else
+ printf(" chs addressing\n");
+}
+
+/*
+ * Read/write routine for a buffer. Validates the arguments and schedules the
+ * transfer. Does not wait for the transfer to complete.
+ */
+void
+wdstrategy(bp)
+ struct buf *bp;
+{
+ struct wd_softc *wd = wd_cd.cd_devs[WDUNIT(bp->b_dev)];
+ int s;
+
+ /* Valid request? */
+ if (bp->b_blkno < 0 ||
+ (bp->b_bcount % wd->sc_dk.dk_label->d_secsize) != 0 ||
+ (bp->b_bcount / wd->sc_dk.dk_label->d_secsize) >= (1 << NBBY)) {
+ bp->b_error = EINVAL;
+ goto bad;
+ }
+
+ /* If device invalidated (e.g. media change, door open), error. */
+ if ((wd->sc_flags & WDF_LOADED) == 0) {
+ bp->b_error = EIO;
+ goto bad;
+ }
+
+ /* If it's a null transfer, return immediately. */
+ if (bp->b_bcount == 0)
+ goto done;
+
+ /*
+ * Do bounds checking, adjust transfer. if error, process.
+ * If end of partition, just return.
+ */
+ if (WDPART(bp->b_dev) != RAW_PART &&
+ bounds_check_with_label(bp, wd->sc_dk.dk_label,
+ (wd->sc_flags & (WDF_WLABEL|WDF_LABELLING)) != 0) <= 0)
+ goto done;
+
+ /* Queue transfer on drive, activate drive and controller if idle. */
+ s = splbio();
+ disksort(&wd->sc_q, bp);
+ if (!wd->sc_q.b_active)
+ wdstart(wd);
+#if 0
+ else {
+ struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent;
+ if ((wdc->sc_flags & (WDCF_ACTIVE|WDCF_ERROR)) == 0) {
+ printf("wdstrategy: controller inactive\n");
+ wdcstart(wdc);
+ }
+ }
+#endif
+ splx(s);
+ return;
+
+bad:
+ bp->b_flags |= B_ERROR;
+done:
+ /* Toss transfer; we're done early. */
+ bp->b_resid = bp->b_bcount;
+ biodone(bp);
+}
+
+/*
+ * Queue a drive for I/O.
+ */
+void
+wdstart(wd)
+ struct wd_softc *wd;
+{
+ struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent;
+ int active = wdc->sc_drives.tqh_first != 0;
+
+ /* Link onto controller queue. */
+ wd->sc_q.b_active = 1;
+ TAILQ_INSERT_TAIL(&wdc->sc_drives, wd, sc_drivechain);
+
+ disk_busy(&wd->sc_dk);
+
+ /* If controller not already active, start it. */
+ if (!active)
+ wdcstart(wdc);
+}
+
+/*
+ * Finish an I/O operation. Clean up the drive and controller state, set the
+ * residual count, and inform the upper layers that the operation is complete.
+ */
+void
+wdfinish(wd, bp)
+ struct wd_softc *wd;
+ struct buf *bp;
+{
+ struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent;
+
+ wdc->sc_flags &= ~(WDCF_SINGLE | WDCF_ERROR);
+ wdc->sc_errors = 0;
+ /*
+ * Move this drive to the end of the queue to give others a `fair'
+ * chance.
+ */
+ if (wd->sc_drivechain.tqe_next) {
+ TAILQ_REMOVE(&wdc->sc_drives, wd, sc_drivechain);
+ if (bp->b_actf) {
+ TAILQ_INSERT_TAIL(&wdc->sc_drives, wd, sc_drivechain);
+ } else
+ wd->sc_q.b_active = 0;
+ }
+ bp->b_resid = wd->sc_bcount;
+ wd->sc_skip = 0;
+ wd->sc_q.b_actf = bp->b_actf;
+
+ disk_unbusy(&wd->sc_dk, (bp->b_bcount - bp->b_resid));
+
+ if (!wd->sc_q.b_actf) {
+ TAILQ_REMOVE(&wdc->sc_drives, wd, sc_drivechain);
+ wd->sc_q.b_active = 0;
+ } else
+ disk_busy(&wd->sc_dk);
+
+ biodone(bp);
+}
+
+int
+wdread(dev, uio)
+ dev_t dev;
+ struct uio *uio;
+{
+
+ return (physio(wdstrategy, NULL, dev, B_READ, minphys, uio));
+}
+
+int
+wdwrite(dev, uio)
+ dev_t dev;
+ struct uio *uio;
+{
+
+ return (physio(wdstrategy, NULL, dev, B_WRITE, minphys, uio));
+}
+
+/*
+ * Start I/O on a controller. This does the calculation, and starts a read or
+ * write operation. Called to from wdstart() to start a transfer, from
+ * wdcintr() to continue a multi-sector transfer or start the next transfer, or
+ * wdcrestart() after recovering from an error.
+ */
+void
+wdcstart(wdc)
+ struct wdc_softc *wdc;
+{
+ struct wd_softc *wd;
+ struct buf *bp;
+ struct disklabel *lp;
+ int nblks;
+
+#ifdef DIAGNOSTIC
+ if ((wdc->sc_flags & WDCF_ACTIVE) != 0)
+ panic("wdcstart: controller still active");
+#endif
+
+ /*
+ * XXX
+ * This is a kluge. See comments in wd_get_parms().
+ */
+ if ((wdc->sc_flags & WDCF_WANTED) != 0) {
+ wdc->sc_flags &= ~WDCF_WANTED;
+ wakeup(wdc);
+ return;
+ }
+
+loop:
+ /* Is there a drive for the controller to do a transfer with? */
+ wd = wdc->sc_drives.tqh_first;
+ if (wd == NULL)
+ return;
+
+ /* Is there a transfer to this drive? If not, deactivate drive. */
+ bp = wd->sc_q.b_actf;
+
+ if (wdc->sc_errors >= WDIORETRIES) {
+ wderror(wd, bp, "hard error");
+ bp->b_error = EIO;
+ bp->b_flags |= B_ERROR;
+ wdfinish(wd, bp);
+ goto loop;
+ }
+
+ /* Do control operations specially. */
+ if (wd->sc_state < OPEN) {
+ /*
+ * Actually, we want to be careful not to mess with the control
+ * state if the device is currently busy, but we can assume
+ * that we never get to this point if that's the case.
+ */
+ if (wdcontrol(wd) == 0) {
+ /* The drive is busy. Wait. */
+ return;
+ }
+ }
+
+ /*
+ * WDCF_ERROR is set by wdcunwedge() and wdcintr() when an error is
+ * encountered. If we are in multi-sector mode, then we switch to
+ * single-sector mode and retry the operation from the start.
+ */
+ if (wdc->sc_flags & WDCF_ERROR) {
+ wdc->sc_flags &= ~WDCF_ERROR;
+ if ((wdc->sc_flags & WDCF_SINGLE) == 0) {
+ wdc->sc_flags |= WDCF_SINGLE;
+ wd->sc_skip = 0;
+ }
+ }
+
+ lp = wd->sc_dk.dk_label;
+
+ /* When starting a transfer... */
+ if (wd->sc_skip == 0) {
+ int part = WDPART(bp->b_dev);
+ daddr_t blkno;
+
+#ifdef WDDEBUG
+ printf("\n%s: wdcstart %s %d@%d; map ", wd->sc_dev.dv_xname,
+ (bp->b_flags & B_READ) ? "read" : "write", bp->b_bcount,
+ bp->b_blkno);
+#endif
+ wd->sc_bcount = bp->b_bcount;
+ blkno = bp->b_blkno;
+ if (part != RAW_PART)
+ blkno += lp->d_partitions[part].p_offset;
+ wd->sc_blkno = blkno / (lp->d_secsize / DEV_BSIZE);
+ } else {
+#ifdef WDDEBUG
+ printf(" %d)%x", wd->sc_skip, inb(wd->sc_iobase+wd_altsts));
+#endif
+ }
+
+ /* When starting a multi-sector transfer, or doing single-sector
+ transfers... */
+ if (wd->sc_skip == 0 || (wdc->sc_flags & WDCF_SINGLE) != 0 ||
+ wd->sc_mode == WDM_DMA) {
+ daddr_t blkno = wd->sc_blkno;
+ long cylin, head, sector;
+ int command;
+
+ if ((wdc->sc_flags & WDCF_SINGLE) != 0)
+ nblks = 1;
+ else if (wd->sc_mode != WDM_DMA)
+ nblks = wd->sc_bcount / lp->d_secsize;
+ else
+ nblks = min(wd->sc_bcount / lp->d_secsize, 8);
+
+ /* Check for bad sectors and adjust transfer, if necessary. */
+ if ((lp->d_flags & D_BADSECT) != 0
+#ifdef B_FORMAT
+ && (bp->b_flags & B_FORMAT) == 0
+#endif
+ ) {
+ long blkdiff;
+ int i;
+
+ for (i = 0; (blkdiff = wd->sc_badsect[i]) != -1; i++) {
+ blkdiff -= blkno;
+ if (blkdiff < 0)
+ continue;
+ if (blkdiff == 0) {
+ /* Replace current block of transfer. */
+ blkno =
+ lp->d_secperunit - lp->d_nsectors - i - 1;
+ }
+ if (blkdiff < nblks) {
+ /* Bad block inside transfer. */
+ wdc->sc_flags |= WDCF_SINGLE;
+ nblks = 1;
+ }
+ break;
+ }
+ /* Tranfer is okay now. */
+ }
+
+ if ((wd->sc_params.wdp_capabilities & WD_CAP_LBA) != 0) {
+ sector = (blkno >> 0) & 0xff;
+ cylin = (blkno >> 8) & 0xffff;
+ head = (blkno >> 24) & 0xf;
+ head |= WDSD_LBA;
+ } else {
+ sector = blkno % lp->d_nsectors;
+ sector++; /* Sectors begin with 1, not 0. */
+ blkno /= lp->d_nsectors;
+ head = blkno % lp->d_ntracks;
+ blkno /= lp->d_ntracks;
+ cylin = blkno;
+ head |= WDSD_CHS;
+ }
+
+ if (wd->sc_mode == WDM_PIOSINGLE ||
+ (wdc->sc_flags & WDCF_SINGLE) != 0)
+ wd->sc_nblks = 1;
+ else if (wd->sc_mode == WDM_PIOMULTI)
+ wd->sc_nblks = min(nblks, wd->sc_multiple);
+ else
+ wd->sc_nblks = nblks;
+ wd->sc_nbytes = wd->sc_nblks * lp->d_secsize;
+
+#ifdef B_FORMAT
+ if (bp->b_flags & B_FORMAT) {
+ sector = lp->d_gap3;
+ nblks = lp->d_nsectors;
+ command = WDCC_FORMAT;
+ } else
+#endif
+ switch (wd->sc_mode) {
+ case WDM_DMA:
+ command = (bp->b_flags & B_READ) ?
+ WDCC_READDMA : WDCC_WRITEDMA;
+ /* Start the DMA channel and bounce the buffer if
+ necessary. */
+/* isa_dmastart(bp->b_flags & B_READ,
+ bp->b_data + wd->sc_skip,
+ wd->sc_nbytes, wdc->sc_drq);*/
+ panic("wd cannot do DMA yet\n");
+ break;
+ case WDM_PIOMULTI:
+ command = (bp->b_flags & B_READ) ?
+ WDCC_READMULTI : WDCC_WRITEMULTI;
+ break;
+ case WDM_PIOSINGLE:
+ command = (bp->b_flags & B_READ) ?
+ WDCC_READ : WDCC_WRITE;
+ break;
+ }
+
+ /* Initiate command! */
+ if (wdcommand(wd, command, cylin, head, sector, nblks) != 0) {
+ wderror(wd, NULL,
+ "wdcstart: timeout waiting for unbusy");
+ wdcunwedge(wdc);
+ return;
+ }
+
+#ifdef WDDEBUG
+ printf("sector %d cylin %d head %d addr %x sts %x\n", sector,
+ cylin, head, bp->b_data, 0/*inb(wd->sc_iobase+wd_altsts)*/);
+#endif
+ } else if (wd->sc_nblks > 1) {
+ /* The number of blocks in the last stretch may be smaller. */
+ nblks = wd->sc_bcount / lp->d_secsize;
+ if (wd->sc_nblks > nblks) {
+ wd->sc_nblks = nblks;
+ wd->sc_nbytes = wd->sc_bcount;
+ }
+ }
+
+ /* If this was a write and not using DMA, push the data. */
+ if (wd->sc_mode != WDM_DMA &&
+ (bp->b_flags & (B_READ|B_WRITE)) == B_WRITE) {
+ if (wait_for_drq(wdc) < 0) {
+ wderror(wd, NULL, "wdcstart: timeout waiting for drq");
+ wdcunwedge(wdc);
+ return;
+ }
+
+ /* Push out data. */
+ if ((wd->sc_flags & WDF_32BIT) == 0)
+ outsw(wdc->sc_iobase+wd_data, (u_int) bp->b_data + wd->sc_skip,
+ wd->sc_nbytes >> 1);
+ else
+ panic("wd cannot do 32 bit transfers\n");
+/* outsl(wdc->sc_iobase+wd_data, bp->b_data + wd->sc_skip,
+ wd->sc_nbytes >> 2);*/
+ }
+
+ wdc->sc_flags |= WDCF_ACTIVE;
+ timeout(wdctimeout, wdc, WAITTIME);
+}
+
+/*
+ * Interrupt routine for the controller. Acknowledge the interrupt, check for
+ * errors on the current operation, mark it done if necessary, and start the
+ * next request. Also check for a partially done transfer, and continue with
+ * the next chunk if so.
+ */
+int
+wdcintr(arg)
+ void *arg;
+{
+ struct wdc_softc *wdc = arg;
+ struct wd_softc *wd;
+ struct buf *bp;
+
+ if ((wdc->sc_flags & WDCF_ACTIVE) == 0) {
+ /* Clear the pending interrupt and abort. */
+ (void) inb(wdc->sc_iobase+wd_status);
+ return 0;
+ }
+
+ wdc->sc_flags &= ~WDCF_ACTIVE;
+ untimeout(wdctimeout, wdc);
+
+ wd = wdc->sc_drives.tqh_first;
+ bp = wd->sc_q.b_actf;
+
+#ifdef WDDEBUG
+ printf("I%d ", ctrlr);
+#endif
+
+ if (wait_for_unbusy(wdc) < 0) {
+ wderror(wd, NULL, "wdcintr: timeout waiting for unbusy");
+ wdc->sc_status |= WDCS_ERR; /* XXX */
+ }
+
+ /* Is it not a transfer, but a control operation? */
+ if (wd->sc_state < OPEN) {
+ if (wdcontrol(wd) == 0) {
+ /* The drive is busy. Wait. */
+ return 1;
+ }
+ wdcstart(wdc);
+ return 1;
+ }
+
+ /* Turn off the DMA channel and unbounce the buffer. */
+ if (wd->sc_mode == WDM_DMA)
+ panic("wd cannot do DMA\n");
+/* isa_dmadone(bp->b_flags & B_READ, bp->b_data + wd->sc_skip,
+ wd->sc_nbytes, wdc->sc_drq);*/
+
+ /* Have we an error? */
+ if (wdc->sc_status & WDCS_ERR) {
+ lose:
+#ifdef WDDEBUG
+ wderror(wd, NULL, "wdcintr");
+#endif
+ if ((wdc->sc_flags & WDCF_SINGLE) == 0) {
+ wdc->sc_flags |= WDCF_ERROR;
+ goto restart;
+ }
+
+#ifdef B_FORMAT
+ if (bp->b_flags & B_FORMAT)
+ goto bad;
+#endif
+
+ if (++wdc->sc_errors < WDIORETRIES)
+ goto restart;
+ wderror(wd, bp, "hard error");
+
+ bad:
+ bp->b_error = EIO;
+ bp->b_flags |= B_ERROR;
+ goto done;
+ }
+
+ /* If this was a read and not using DMA, fetch the data. */
+ if (wd->sc_mode != WDM_DMA &&
+ (bp->b_flags & (B_READ|B_WRITE)) == B_READ) {
+ if ((wdc->sc_status & (WDCS_DRDY | WDCS_DSC | WDCS_DRQ))
+ != (WDCS_DRDY | WDCS_DSC | WDCS_DRQ)) {
+ wderror(wd, NULL, "wdcintr: read intr before drq");
+ wdcunwedge(wdc);
+ return 1;
+ }
+
+ /* Pull in data. */
+ if ((wd->sc_flags & WDF_32BIT) == 0)
+ insw(wdc->sc_iobase+wd_data, (u_int) bp->b_data + wd->sc_skip,
+ wd->sc_nbytes >> 1);
+ else
+ panic("wd cannot do 32 bit transfers\n");
+/* insl(wdc->sc_iobase+wd_data, bp->b_data + wd->sc_skip,
+ wd->sc_nbytes >> 2);*/
+ }
+
+ /* If we encountered any abnormalities, flag it as a soft error. */
+ if (wdc->sc_errors > 0 ||
+ (wdc->sc_status & WDCS_CORR) != 0) {
+ wderror(wd, bp, "soft error (corrected)");
+ wdc->sc_errors = 0;
+ }
+
+ /* Adjust pointers for the next block, if any. */
+ wd->sc_blkno += wd->sc_nblks;
+ wd->sc_skip += wd->sc_nbytes;
+ wd->sc_bcount -= wd->sc_nbytes;
+
+ /* See if this transfer is complete. */
+ if (wd->sc_bcount > 0)
+ goto restart;
+
+done:
+ /* Done with this transfer, with or without error. */
+ wdfinish(wd, bp);
+
+restart:
+ /* Start the next operation, if any. */
+ wdcstart(wdc);
+
+ return 1;
+}
+
+/*
+ * Wait interruptibly for an exclusive lock.
+ *
+ * XXX
+ * Several drivers do this; it should be abstracted and made MP-safe.
+ */
+int
+wdlock(wd)
+ struct wd_softc *wd;
+{
+ int error;
+
+ while ((wd->sc_flags & WDF_LOCKED) != 0) {
+ wd->sc_flags |= WDF_WANTED;
+ if ((error = tsleep(wd, PRIBIO | PCATCH, "wdlck", 0)) != 0)
+ return error;
+ }
+ wd->sc_flags |= WDF_LOCKED;
+ return 0;
+}
+
+/*
+ * Unlock and wake up any waiters.
+ */
+void
+wdunlock(wd)
+ struct wd_softc *wd;
+{
+
+ wd->sc_flags &= ~WDF_LOCKED;
+ if ((wd->sc_flags & WDF_WANTED) != 0) {
+ wd->sc_flags &= ~WDF_WANTED;
+ wakeup(wd);
+ }
+}
+
+int
+wdopen(dev, flag, fmt)
+ dev_t dev;
+ int flag, fmt;
+{
+ struct wd_softc *wd;
+ int unit, part;
+ int error;
+
+ unit = WDUNIT(dev);
+ if (unit >= wd_cd.cd_ndevs)
+ return ENXIO;
+ wd = wd_cd.cd_devs[unit];
+ if (wd == 0)
+ return ENXIO;
+
+ if (error = wdlock(wd))
+ return error;
+
+ if (wd->sc_dk.dk_openmask != 0) {
+ /*
+ * If any partition is open, but the disk has been invalidated,
+ * disallow further opens.
+ */
+ if ((wd->sc_flags & WDF_LOADED) == 0) {
+ error = EIO;
+ goto bad3;
+ }
+ } else {
+ if ((wd->sc_flags & WDF_LOADED) == 0) {
+ wd->sc_flags |= WDF_LOADED;
+
+ /* Load the physical device parameters. */
+ if (wd_get_parms(wd) != 0) {
+ error = ENXIO;
+ goto bad2;
+ }
+
+ /* Load the partition info if not already loaded. */
+ wdgetdisklabel(wd);
+ }
+ }
+
+ part = WDPART(dev);
+
+ /* Check that the partition exists. */
+ if (part != RAW_PART &&
+ (part >= wd->sc_dk.dk_label->d_npartitions ||
+ wd->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED)) {
+ error = ENXIO;
+ goto bad;
+ }
+
+ /* Insure only one open at a time. */
+ switch (fmt) {
+ case S_IFCHR:
+ wd->sc_dk.dk_copenmask |= (1 << part);
+ break;
+ case S_IFBLK:
+ wd->sc_dk.dk_bopenmask |= (1 << part);
+ break;
+ }
+ wd->sc_dk.dk_openmask = wd->sc_dk.dk_copenmask | wd->sc_dk.dk_bopenmask;
+
+ wdunlock(wd);
+ return 0;
+
+bad2:
+ wd->sc_flags &= ~WDF_LOADED;
+
+bad:
+ if (wd->sc_dk.dk_openmask == 0) {
+ }
+
+bad3:
+ wdunlock(wd);
+ return error;
+}
+
+int
+wdclose(dev, flag, fmt)
+ dev_t dev;
+ int flag, fmt;
+{
+ struct wd_softc *wd = wd_cd.cd_devs[WDUNIT(dev)];
+ int part = WDPART(dev);
+ int error;
+
+ if (error = wdlock(wd))
+ return error;
+
+ switch (fmt) {
+ case S_IFCHR:
+ wd->sc_dk.dk_copenmask &= ~(1 << part);
+ break;
+ case S_IFBLK:
+ wd->sc_dk.dk_bopenmask &= ~(1 << part);
+ break;
+ }
+ wd->sc_dk.dk_openmask = wd->sc_dk.dk_copenmask | wd->sc_dk.dk_bopenmask;
+
+ if (wd->sc_dk.dk_openmask == 0) {
+ /* XXXX Must wait for I/O to complete! */
+ }
+
+ wdunlock(wd);
+ return 0;
+}
+
+/*
+ * Fabricate a default disk label, and try to read the correct one.
+ */
+void
+wdgetdisklabel(wd)
+ struct wd_softc *wd;
+{
+ struct disklabel *lp = wd->sc_dk.dk_label;
+ char *errstring;
+
+ bzero(lp, sizeof(struct disklabel));
+ bzero(wd->sc_dk.dk_cpulabel, sizeof(struct cpu_disklabel));
+
+ lp->d_secsize = DEV_BSIZE;
+ lp->d_ntracks = wd->sc_params.wdp_heads;
+ lp->d_nsectors = wd->sc_params.wdp_sectors;
+ lp->d_ncylinders = wd->sc_params.wdp_cylinders;
+ lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
+
+#if 0
+ strncpy(lp->d_typename, "ST506 disk", 16);
+ lp->d_type = DTYPE_ST506;
+#endif
+ strncpy(lp->d_packname, wd->sc_params.wdp_model, 16);
+ lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders;
+ lp->d_rpm = 3600;
+ lp->d_interleave = 1;
+ lp->d_flags = 0;
+
+ lp->d_partitions[RAW_PART].p_offset = 0;
+ lp->d_partitions[RAW_PART].p_size =
+ lp->d_secperunit * (lp->d_secsize / DEV_BSIZE);
+ lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
+ lp->d_npartitions = RAW_PART + 1;
+
+ lp->d_magic = DISKMAGIC;
+ lp->d_magic2 = DISKMAGIC;
+ lp->d_checksum = dkcksum(lp);
+
+ wd->sc_badsect[0] = -1;
+
+ if (wd->sc_state > RECAL)
+ wd->sc_state = RECAL;
+ errstring = readdisklabel(MAKEWDDEV(0, wd->sc_dev.dv_unit, RAW_PART),
+ wdstrategy, lp, wd->sc_dk.dk_cpulabel);
+ if (errstring) {
+ /*
+ * This probably happened because the drive's default
+ * geometry doesn't match the DOS geometry. We
+ * assume the DOS geometry is now in the label and try
+ * again. XXX This is a kluge.
+ */
+ if (wd->sc_state > GEOMETRY)
+ wd->sc_state = GEOMETRY;
+ errstring = readdisklabel(MAKEWDDEV(0, wd->sc_dev.dv_unit, RAW_PART),
+ wdstrategy, lp, wd->sc_dk.dk_cpulabel);
+ }
+ if (errstring) {
+ printf("%s: %s\n", wd->sc_dev.dv_xname, errstring);
+ return;
+ }
+
+ if (wd->sc_state > GEOMETRY)
+ wd->sc_state = GEOMETRY;
+ if ((lp->d_flags & D_BADSECT) != 0)
+ bad144intern(wd);
+}
+
+/*
+ * Implement operations needed before read/write.
+ * Returns 0 if operation still in progress, 1 if completed.
+ */
+int
+wdcontrol(wd)
+ struct wd_softc *wd;
+{
+ struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent;
+
+ switch (wd->sc_state) {
+ case RECAL: /* Set SDH, step rate, do recal. */
+ if (wdcommandshort(wdc, wd->sc_drive, WDCC_RECAL) != 0) {
+ wderror(wd, NULL, "wdcontrol: recal failed (1)");
+ goto bad;
+ }
+ wd->sc_state = RECAL_WAIT;
+ break;
+
+ case RECAL_WAIT:
+ if (wdc->sc_status & WDCS_ERR) {
+ wderror(wd, NULL, "wdcontrol: recal failed (2)");
+ goto bad;
+ }
+ /* fall through */
+ case GEOMETRY:
+ if ((wd->sc_params.wdp_capabilities & WD_CAP_LBA) != 0)
+ goto multimode;
+ if (wdsetctlr(wd) != 0) {
+ /* Already printed a message. */
+ goto bad;
+ }
+ wd->sc_state = GEOMETRY_WAIT;
+ break;
+
+ case GEOMETRY_WAIT:
+ if (wdc->sc_status & WDCS_ERR) {
+ wderror(wd, NULL, "wdcontrol: geometry failed");
+ goto bad;
+ }
+ /* fall through */
+ case MULTIMODE:
+ multimode:
+ if (wd->sc_mode != WDM_PIOMULTI)
+ goto open;
+ outb(wdc->sc_iobase+wd_seccnt, wd->sc_multiple);
+ if (wdcommandshort(wdc, wd->sc_drive, WDCC_SETMULTI) != 0) {
+ wderror(wd, NULL, "wdcontrol: setmulti failed (1)");
+ goto bad;
+ }
+ wd->sc_state = MULTIMODE_WAIT;
+ break;
+
+ case MULTIMODE_WAIT:
+ if (wdc->sc_status & WDCS_ERR) {
+ wderror(wd, NULL, "wdcontrol: setmulti failed (2)");
+ goto bad;
+ }
+ /* fall through */
+ case OPEN:
+ open:
+ wdc->sc_errors = 0;
+ wd->sc_state = OPEN;
+ /*
+ * The rest of the initialization can be done by normal means.
+ */
+ return 1;
+
+ bad:
+ wdcunwedge(wdc);
+ return 0;
+ }
+
+ wdc->sc_flags |= WDCF_ACTIVE;
+ timeout(wdctimeout, wdc, WAITTIME);
+ return 0;
+}
+
+/*
+ * Wait for the drive to become ready and send a command.
+ * Return -1 if busy for too long or 0 otherwise.
+ * Assumes interrupts are blocked.
+ */
+int
+wdcommand(wd, command, cylin, head, sector, count)
+ struct wd_softc *wd;
+ int command;
+ int cylin, head, sector, count;
+{
+ struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent;
+ int iobase = wdc->sc_iobase;
+ int stat;
+
+ /* Select drive, head, and addressing mode. */
+ outb(iobase+wd_sdh, WDSD_IBM | (wd->sc_drive << 4) | head);
+
+ /* Wait for it to become ready to accept a command. */
+ if (command == WDCC_IDP)
+ stat = wait_for_unbusy(wdc);
+ else
+ stat = wdcwait(wdc, WDCS_DRDY);
+ if (stat < 0)
+ return -1;
+
+ /* Load parameters. */
+ if (wd->sc_dk.dk_label->d_type == DTYPE_ST506)
+ outb(iobase+wd_precomp, wd->sc_dk.dk_label->d_precompcyl / 4);
+ else
+ outb(iobase+wd_features, 0);
+ outb(iobase+wd_cyl_lo, cylin);
+ outb(iobase+wd_cyl_hi, cylin >> 8);
+ outb(iobase+wd_sector, sector);
+ outb(iobase+wd_seccnt, count);
+
+ /* Send command. */
+ outb(iobase+wd_command, command);
+
+ return 0;
+}
+
+/*
+ * Simplified version of wdcommand().
+ */
+int
+wdcommandshort(wdc, drive, command)
+ struct wdc_softc *wdc;
+ int drive;
+ int command;
+{
+ int iobase = wdc->sc_iobase;
+
+ /* Select drive. */
+ outb(iobase+wd_sdh, WDSD_IBM | (drive << 4));
+
+ if (wdcwait(wdc, WDCS_DRDY) < 0)
+ return -1;
+
+ outb(iobase+wd_command, command);
+
+ return 0;
+}
+
+/*
+ * Tell the drive what geometry to use.
+ */
+int
+wdsetctlr(wd)
+ struct wd_softc *wd;
+{
+ struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent;
+
+#ifdef WDDEBUG
+ printf("wd(%d,%d) C%dH%dS%d\n", wd->sc_dev.dv_unit, wd->sc_drive,
+ wd->sc_dk.dk_label->d_ncylinders, wd->sc_dk.dk_label->d_ntracks,
+ wd->sc_dk.dk_label->d_nsectors);
+#endif
+
+ if (wdcommand(wd, WDCC_IDP, wd->sc_dk.dk_label->d_ncylinders,
+ wd->sc_dk.dk_label->d_ntracks - 1, 0,
+ wd->sc_dk.dk_label->d_nsectors) != 0) {
+ wderror(wd, NULL, "wdsetctlr: geometry upload failed");
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Get the drive parameters, if ESDI or ATA, or create fake ones for ST506.
+ */
+int
+wd_get_parms(wd)
+ struct wd_softc *wd;
+{
+ struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent;
+ int i;
+ char tb[DEV_BSIZE];
+ int s, error;
+
+ /*
+ * XXX
+ * The locking done here, and the length of time this may keep the rest
+ * of the system suspended, is a kluge. This should be rewritten to
+ * set up a transfer and queue it through wdstart(), but it's called
+ * infrequently enough that this isn't a pressing matter.
+ */
+
+ s = splbio();
+
+ while ((wdc->sc_flags & WDCF_ACTIVE) != 0) {
+ wdc->sc_flags |= WDCF_WANTED;
+ if ((error = tsleep(wdc, PRIBIO | PCATCH, "wdprm", 0)) != 0) {
+ splx(s);
+ return error;
+ }
+ }
+
+ if (wdcommandshort(wdc, wd->sc_drive, WDCC_IDENTIFY) != 0 ||
+ wait_for_drq(wdc) != 0) {
+ /*
+ * We `know' there's a drive here; just assume it's old.
+ * This geometry is only used to read the MBR and print a
+ * (false) attach message.
+ */
+ strncpy(wd->sc_dk.dk_label->d_typename, "ST506",
+ sizeof wd->sc_dk.dk_label->d_typename);
+ wd->sc_dk.dk_label->d_type = DTYPE_ST506;
+
+ strncpy(wd->sc_params.wdp_model, "unknown",
+ sizeof wd->sc_params.wdp_model);
+ wd->sc_params.wdp_config = WD_CFG_FIXED;
+ wd->sc_params.wdp_cylinders = 1024;
+ wd->sc_params.wdp_heads = 8;
+ wd->sc_params.wdp_sectors = 17;
+ wd->sc_params.wdp_maxmulti = 0;
+ wd->sc_params.wdp_usedmovsd = 0;
+ wd->sc_params.wdp_capabilities = 0;
+ } else {
+ strncpy(wd->sc_dk.dk_label->d_typename, "ESDI/IDE",
+ sizeof wd->sc_dk.dk_label->d_typename);
+ wd->sc_dk.dk_label->d_type = DTYPE_ESDI;
+
+ /* Read in parameter block. */
+ insw(wdc->sc_iobase+wd_data, (u_int)tb, sizeof(tb) / sizeof(short));
+ bcopy(tb, &wd->sc_params, sizeof(struct wdparams));
+
+ /* Shuffle string byte order. */
+ for (i = 0; i < sizeof(wd->sc_params.wdp_model); i += 2) {
+ u_short *p;
+ p = (u_short *)(wd->sc_params.wdp_model + i);
+ *p = ntohs(*p);
+ }
+ }
+
+ /* Clear any leftover interrupt. */
+ (void) inb(wdc->sc_iobase+wd_status);
+
+ /* Restart the queue. */
+ wdcstart(wdc);
+
+ splx(s);
+ return 0;
+}
+
+int
+wdioctl(dev, cmd, addr, flag, p)
+ dev_t dev;
+ u_long cmd;
+ caddr_t addr;
+ int flag;
+ struct proc *p;
+{
+ struct wd_softc *wd = wd_cd.cd_devs[WDUNIT(dev)];
+ int error;
+
+ if ((wd->sc_flags & WDF_LOADED) == 0)
+ return EIO;
+
+ switch (cmd) {
+ case DIOCSBAD:
+ if ((flag & FWRITE) == 0)
+ return EBADF;
+ wd->sc_dk.dk_cpulabel->bad = *(struct dkbad *)addr;
+ wd->sc_dk.dk_label->d_flags |= D_BADSECT;
+ bad144intern(wd);
+ return 0;
+
+ case DIOCGDINFO:
+ *(struct disklabel *)addr = *(wd->sc_dk.dk_label);
+ return 0;
+
+ case DIOCGPART:
+ ((struct partinfo *)addr)->disklab = wd->sc_dk.dk_label;
+ ((struct partinfo *)addr)->part =
+ &wd->sc_dk.dk_label->d_partitions[WDPART(dev)];
+ return 0;
+
+ case DIOCWDINFO:
+ case DIOCSDINFO:
+ if ((flag & FWRITE) == 0)
+ return EBADF;
+
+ if (error = wdlock(wd))
+ return error;
+ wd->sc_flags |= WDF_LABELLING;
+
+ error = setdisklabel(wd->sc_dk.dk_label,
+ (struct disklabel *)addr, /*wd->sc_dk.dk_openmask : */0,
+ wd->sc_dk.dk_cpulabel);
+ if (error == 0) {
+ if (wd->sc_state > GEOMETRY)
+ wd->sc_state = GEOMETRY;
+ if (cmd == DIOCWDINFO)
+ error = writedisklabel(WDLABELDEV(dev),
+ wdstrategy, wd->sc_dk.dk_label,
+ wd->sc_dk.dk_cpulabel);
+ }
+
+ wd->sc_flags &= ~WDF_LABELLING;
+ wdunlock(wd);
+ return error;
+
+ case DIOCWLABEL:
+ if ((flag & FWRITE) == 0)
+ return EBADF;
+ if (*(int *)addr)
+ wd->sc_flags |= WDF_WLABEL;
+ else
+ wd->sc_flags &= ~WDF_WLABEL;
+ return 0;
+
+#ifdef notyet
+ case DIOCWFORMAT:
+ if ((flag & FWRITE) == 0)
+ return EBADF;
+ {
+ register struct format_op *fop;
+ struct iovec aiov;
+ struct uio auio;
+
+ fop = (struct format_op *)addr;
+ aiov.iov_base = fop->df_buf;
+ aiov.iov_len = fop->df_count;
+ auio.uio_iov = &aiov;
+ auio.uio_iovcnt = 1;
+ auio.uio_resid = fop->df_count;
+ auio.uio_segflg = 0;
+ auio.uio_offset =
+ fop->df_startblk * wd->sc_dk.dk_label->d_secsize;
+ auio.uio_procp = p;
+ error = physio(wdformat, NULL, dev, B_WRITE, minphys,
+ &auio);
+ fop->df_count -= auio.uio_resid;
+ fop->df_reg[0] = wdc->sc_status;
+ fop->df_reg[1] = wdc->sc_error;
+ return error;
+ }
+#endif
+
+ default:
+ return ENOTTY;
+ }
+
+#ifdef DIAGNOSTIC
+ panic("wdioctl: impossible");
+#endif
+}
+
+#ifdef B_FORMAT
+int
+wdformat(struct buf *bp)
+{
+
+ bp->b_flags |= B_FORMAT;
+ return wdstrategy(bp);
+}
+#endif
+
+int
+wdsize(dev)
+ dev_t dev;
+{
+ struct wd_softc *wd;
+ int part;
+ int size;
+
+ if (wdopen(dev, 0, S_IFBLK) != 0)
+ return -1;
+ wd = wd_cd.cd_devs[WDUNIT(dev)];
+ part = WDPART(dev);
+ if (wd->sc_dk.dk_label->d_partitions[part].p_fstype != FS_SWAP)
+ size = -1;
+ else
+ size = wd->sc_dk.dk_label->d_partitions[part].p_size;
+ if (wdclose(dev, 0, S_IFBLK) != 0)
+ return -1;
+ return size;
+}
+
+
+#ifndef __BDEVSW_DUMP_OLD_TYPE
+/* #define WD_DUMP_NOT_TRUSTED if you just want to watch */
+static int wddoingadump;
+static int wddumprecalibrated;
+
+/*
+ * Dump core after a system crash.
+ */
+int
+wddump(dev, blkno, va, size)
+ dev_t dev;
+ daddr_t blkno;
+ caddr_t va;
+ size_t size;
+{
+ struct wd_softc *wd; /* disk unit to do the I/O */
+ struct wdc_softc *wdc; /* disk controller to do the I/O */
+ struct disklabel *lp; /* disk's disklabel */
+ int unit, part;
+ int nblks; /* total number of sectors left to write */
+
+ /* Check if recursive dump; if so, punt. */
+ if (wddoingadump)
+ return EFAULT;
+ wddoingadump = 1;
+
+ unit = WDUNIT(dev);
+ if (unit >= wd_cd.cd_ndevs)
+ return ENXIO;
+ wd = wd_cd.cd_devs[unit];
+ if (wd == 0)
+ return ENXIO;
+
+ part = WDPART(dev);
+
+ /* Make sure it was initialized. */
+ if (wd->sc_state < OPEN)
+ return ENXIO;
+
+ wdc = (void *)wd->sc_dev.dv_parent;
+
+ /* Convert to disk sectors. Request must be a multiple of size. */
+ lp = wd->sc_dk.dk_label;
+ if ((size % lp->d_secsize) != 0)
+ return EFAULT;
+ nblks = size / lp->d_secsize;
+ blkno = blkno / (lp->d_secsize / DEV_BSIZE);
+
+ /* Check transfer bounds against partition size. */
+ if ((blkno < 0) || ((blkno + nblks) > lp->d_partitions[part].p_size))
+ return EINVAL;
+
+ /* Offset block number to start of partition. */
+ blkno += lp->d_partitions[part].p_offset;
+
+ /* Recalibrate, if first dump transfer. */
+ if (wddumprecalibrated == 0) {
+ wddumprecalibrated = 1;
+ if (wdcommandshort(wdc, wd->sc_drive, WDCC_RECAL) != 0 ||
+ wait_for_ready(wdc) != 0 || wdsetctlr(wd) != 0 ||
+ wait_for_ready(wdc) != 0) {
+ wderror(wd, NULL, "wddump: recal failed");
+ return EIO;
+ }
+ }
+
+ while (nblks > 0) {
+ daddr_t xlt_blkno = blkno;
+ long cylin, head, sector;
+
+ if ((lp->d_flags & D_BADSECT) != 0) {
+ long blkdiff;
+ int i;
+
+ for (i = 0; (blkdiff = wd->sc_badsect[i]) != -1; i++) {
+ blkdiff -= xlt_blkno;
+ if (blkdiff < 0)
+ continue;
+ if (blkdiff == 0) {
+ /* Replace current block of transfer. */
+ xlt_blkno = lp->d_secperunit -
+ lp->d_nsectors - i - 1;
+ }
+ break;
+ }
+ /* Tranfer is okay now. */
+ }
+
+ if ((wd->sc_params.wdp_capabilities & WD_CAP_LBA) != 0) {
+ sector = (xlt_blkno >> 0) & 0xff;
+ cylin = (xlt_blkno >> 8) & 0xffff;
+ head = (xlt_blkno >> 24) & 0xf;
+ head |= WDSD_LBA;
+ } else {
+ sector = xlt_blkno % lp->d_nsectors;
+ sector++; /* Sectors begin with 1, not 0. */
+ xlt_blkno /= lp->d_nsectors;
+ head = xlt_blkno % lp->d_ntracks;
+ xlt_blkno /= lp->d_ntracks;
+ cylin = xlt_blkno;
+ head |= WDSD_CHS;
+ }
+
+#ifndef WD_DUMP_NOT_TRUSTED
+ if (wdcommand(wd, WDCC_WRITE, cylin, head, sector, 1) != 0 ||
+ wait_for_drq(wdc) != 0) {
+ wderror(wd, NULL, "wddump: write failed");
+ return EIO;
+ }
+
+ outsw(wdc->sc_iobase+wd_data, (u_int)va, lp->d_secsize >> 1);
+
+ /* Check data request (should be done). */
+ if (wait_for_ready(wdc) != 0) {
+ wderror(wd, NULL, "wddump: timeout waiting for ready");
+ return EIO;
+ }
+#else /* WD_DUMP_NOT_TRUSTED */
+ /* Let's just talk about this first... */
+ printf("wd%d: dump addr 0x%x, cylin %d, head %d, sector %d\n",
+ unit, va, cylin, head, sector);
+ delay(500 * 1000); /* half a second */
+#endif
+
+ /* update block count */
+ nblks -= 1;
+ blkno += 1;
+ va += lp->d_secsize;
+ }
+
+ wddoingadump = 0;
+ return 0;
+}
+#else /* __BDEVSW_DUMP_NEW_TYPE */
+int
+wddump(dev, blkno, va, size)
+ dev_t dev;
+ daddr_t blkno;
+ caddr_t va;
+ size_t size;
+{
+
+ /* Not implemented. */
+ return ENXIO;
+}
+#endif /* __BDEVSW_DUMP_NEW_TYPE */
+
+/*
+ * Internalize the bad sector table.
+ */
+void
+bad144intern(wd)
+ struct wd_softc *wd;
+{
+ struct dkbad *bt = &wd->sc_dk.dk_cpulabel->bad;
+ struct disklabel *lp = wd->sc_dk.dk_label;
+ int i = 0;
+
+ for (; i < 126; i++) {
+ if (bt->bt_bad[i].bt_cyl == 0xffff)
+ break;
+ wd->sc_badsect[i] =
+ bt->bt_bad[i].bt_cyl * lp->d_secpercyl +
+ (bt->bt_bad[i].bt_trksec >> 8) * lp->d_nsectors +
+ (bt->bt_bad[i].bt_trksec & 0xff);
+ }
+ for (; i < 127; i++)
+ wd->sc_badsect[i] = -1;
+}
+
+int
+wdcreset(wdc)
+ struct wdc_softc *wdc;
+{
+ int iobase = wdc->sc_iobase;
+
+ /* Reset the device. */
+ if (wdresethack) {
+ outb(iobase+wd_ctlr, WDCTL_RST | WDCTL_IDS);
+ delay(1000);
+ outb(iobase+wd_ctlr, WDCTL_IDS);
+ delay(1000);
+ (void) inb(iobase+wd_error);
+ outb(iobase+wd_ctlr, WDCTL_4BIT);
+ }
+
+ if (wait_for_unbusy(wdc) < 0) {
+ printf("%s: reset failed\n", wdc->sc_dev.dv_xname);
+ return 1;
+ }
+
+ return 0;
+}
+
+void
+wdcrestart(arg)
+ void *arg;
+{
+ struct wdc_softc *wdc = arg;
+ int s;
+
+ s = splbio();
+ wdcstart(wdc);
+ splx(s);
+}
+
+/*
+ * Unwedge the controller after an unexpected error. We do this by resetting
+ * it, marking all drives for recalibration, and stalling the queue for a short
+ * period to give the reset time to finish.
+ * NOTE: We use a timeout here, so this routine must not be called during
+ * autoconfig or dump.
+ */
+void
+wdcunwedge(wdc)
+ struct wdc_softc *wdc;
+{
+ int unit;
+
+ untimeout(wdctimeout, wdc);
+ (void) wdcreset(wdc);
+
+ /* Schedule recalibrate for all drives on this controller. */
+ for (unit = 0; unit < wd_cd.cd_ndevs; unit++) {
+ struct wd_softc *wd = wd_cd.cd_devs[unit];
+ if (!wd || (void *)wd->sc_dev.dv_parent != wdc)
+ continue;
+ if (wd->sc_state > RECAL)
+ wd->sc_state = RECAL;
+ }
+
+ wdc->sc_flags |= WDCF_ERROR;
+ ++wdc->sc_errors;
+
+ /* Wake up in a little bit and restart the operation. */
+ timeout(wdcrestart, wdc, RECOVERYTIME);
+}
+
+int
+wdcwait(wdc, mask)
+ struct wdc_softc *wdc;
+ int mask;
+{
+ int iobase = wdc->sc_iobase;
+ int timeout = 0;
+ u_char status;
+ extern int cold;
+
+ for (;;) {
+ wdc->sc_status = status = inb(iobase+wd_status);
+ if ((status & WDCS_BSY) == 0 && (status & mask) == mask)
+ break;
+ if (++timeout > WDCNDELAY)
+ return -1;
+ delay(WDCDELAY);
+ }
+ if (status & WDCS_ERR) {
+ wdc->sc_error = inb(iobase+wd_error);
+ return WDCS_ERR;
+ }
+#ifdef WDCNDELAY_DEBUG
+ /* After autoconfig, there should be no long delays. */
+ if (!cold && timeout > WDCNDELAY_DEBUG)
+ printf("%s: warning: busy-wait took %dus\n",
+ wdc->sc_dev.dv_xname, WDCDELAY * timeout);
+#endif
+ return 0;
+}
+
+void
+wdctimeout(arg)
+ void *arg;
+{
+ struct wdc_softc *wdc = (struct wdc_softc *)arg;
+ int s;
+
+ s = splbio();
+ if ((wdc->sc_flags & WDCF_ACTIVE) != 0) {
+ struct wd_softc *wd = wdc->sc_drives.tqh_first;
+ struct buf *bp = wd->sc_q.b_actf;
+
+ wdc->sc_flags &= ~WDCF_ACTIVE;
+ wderror(wdc, NULL, "lost interrupt");
+ printf("%s: lost interrupt: %sing %d@%s:%d\n",
+ wdc->sc_dev.dv_xname,
+ (bp->b_flags & B_READ) ? "read" : "writ",
+ wd->sc_nblks, wd->sc_dev.dv_xname, wd->sc_blkno);
+ wdcunwedge(wdc);
+ } else
+ wderror(wdc, NULL, "missing untimeout");
+ splx(s);
+}
+
+void
+wderror(dev, bp, msg)
+ void *dev;
+ struct buf *bp;
+ char *msg;
+{
+ struct wd_softc *wd = dev;
+ struct wdc_softc *wdc = dev;
+
+ if (bp) {
+ diskerr(bp, "wd", msg, LOG_PRINTF, wd->sc_skip / DEV_BSIZE,
+ wd->sc_dk.dk_label);
+ printf("\n");
+ } else
+ printf("%s: %s: status %b error %b\n", wdc->sc_dev.dv_xname,
+ msg, wdc->sc_status, WDCS_BITS, wdc->sc_error, WDERR_BITS);
+}
diff --git a/sys/arch/arm32/mainbus/wdreg.h b/sys/arch/arm32/mainbus/wdreg.h
new file mode 100644
index 00000000000..12311b76e60
--- /dev/null
+++ b/sys/arch/arm32/mainbus/wdreg.h
@@ -0,0 +1,161 @@
+/* $NetBSD: wdreg.h,v 1.1 1996/01/31 23:25:18 mark Exp $ */
+
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)wdreg.h 7.1 (Berkeley) 5/9/91
+ */
+
+/*
+ * Disk Controller register definitions.
+ */
+#define wd_data 0x000 /* data register (R/W - 16 bits) */
+#define wd_error 0x004 /* error register (R) */
+#define wd_precomp 0x004 /* write precompensation (W) */
+#define wd_features 0x004 /* features (W) */
+#define wd_seccnt 0x008 /* sector count (R/W) */
+#define wd_sector 0x00c /* first sector number (R/W) */
+#define wd_cyl_lo 0x010 /* cylinder address, low byte (R/W) */
+#define wd_cyl_hi 0x014 /* cylinder address, high byte (R/W) */
+#define wd_sdh 0x018 /* sector size/drive/head (R/W) */
+#define wd_command 0x01c /* command register (W) */
+#define wd_status 0x01c /* immediate status (R) */
+
+#define wd_altsts 0x818 /* alternate fixed disk status (via 1015) (R) */
+#define wd_ctlr 0x818 /* fixed disk controller control (via 1015) (W) */
+#define WDCTL_4BIT 0x08 /* use four head bits (wd1003) */
+#define WDCTL_RST 0x04 /* reset the controller */
+#define WDCTL_IDS 0x02 /* disable controller interrupts */
+#define wd_digin 0x81c /* disk controller input (via 1015) (R) */
+
+/*
+ * Status bits.
+ */
+#define WDCS_BSY 0x80 /* busy */
+#define WDCS_DRDY 0x40 /* drive ready */
+#define WDCS_DWF 0x20 /* drive write fault */
+#define WDCS_DSC 0x10 /* drive seek complete */
+#define WDCS_DRQ 0x08 /* data request */
+#define WDCS_CORR 0x04 /* corrected data */
+#define WDCS_IDX 0x02 /* index */
+#define WDCS_ERR 0x01 /* error */
+#define WDCS_BITS "\020\010bsy\007drdy\006dwf\005dsc\004drq\003corr\002idx\001err"
+
+/*
+ * Error bits.
+ */
+#define WDCE_BBK 0x80 /* bad block detected */
+#define WDCE_UNC 0x40 /* uncorrectable data error */
+#define WDCE_MC 0x20 /* media changed */
+#define WDCE_IDNF 0x10 /* id not found */
+#define WDCE_ABRT 0x08 /* aborted command */
+#define WDCE_MCR 0x04 /* media change requested */
+#define WDCE_TK0NF 0x02 /* track 0 not found */
+#define WDCE_AMNF 0x01 /* address mark not found */
+#define WDERR_BITS "\020\010bbk\007unc\006mc\005idnf\004mcr\003abrt\002tk0nf\001amnf"
+
+/*
+ * Commands for Disk Controller.
+ */
+#define WDCC_RECAL 0x10 /* disk restore code -- resets cntlr */
+
+#define WDCC_READ 0x20 /* disk read code */
+#define WDCC_WRITE 0x30 /* disk write code */
+#define WDCC__LONG 0x02 /* modifier -- access ecc bytes */
+#define WDCC__NORETRY 0x01 /* modifier -- no retrys */
+
+#define WDCC_FORMAT 0x50 /* disk format code */
+#define WDCC_DIAGNOSE 0x90 /* controller diagnostic */
+#define WDCC_IDP 0x91 /* initialize drive parameters */
+
+#define WDCC_READMULTI 0xc4 /* read multiple */
+#define WDCC_WRITEMULTI 0xc5 /* write multiple */
+#define WDCC_SETMULTI 0xc6 /* set multiple mode */
+
+#define WDCC_READDMA 0xc8 /* read with DMA */
+#define WDCC_WRITEDMA 0xca /* write with DMA */
+
+#define WDCC_ACKMC 0xdb /* acknowledge media change */
+#define WDCC_LOCK 0xde /* lock drawer */
+#define WDCC_UNLOCK 0xdf /* unlock drawer */
+
+#define WDCC_IDENTIFY 0xec /* read parameters from controller */
+#define WDCC_CACHEC 0xef /* cache control */
+
+#define WDSD_IBM 0xa0 /* forced to 512 byte sector, ecc */
+#define WDSD_CHS 0x00 /* cylinder/head/sector addressing */
+#define WDSD_LBA 0x40 /* logical block addressing */
+
+
+#ifdef _KERNEL
+/*
+ * read parameters command returns this:
+ */
+struct wdparams {
+ /* drive info */
+ short wdp_config; /* general configuration */
+#define WD_CFG_REMOVABLE 0x0080
+#define WD_CFG_FIXED 0x0040
+ short wdp_cylinders; /* number of non-removable cylinders */
+ char __reserved1[2];
+ short wdp_heads; /* number of heads */
+ short wdp_unfbytespertrk; /* number of unformatted bytes/track */
+ short wdp_unfbytespersec; /* number of unformatted bytes/sector */
+ short wdp_sectors; /* number of sectors */
+ char wdp_vendor1[6];
+ /* controller info */
+ char wdp_serial[20]; /* serial number */
+ short wdp_buftype; /* buffer type */
+#define WD_BUF_SINGLEPORTSECTOR 1 /* single port, single sector buffer */
+#define WD_BUF_DUALPORTMULTI 2 /* dual port, multiple sector buffer */
+#define WD_BUF_DUALPORTMULTICACHE 3 /* above plus track cache */
+ short wdp_bufsize; /* buffer size, in 512-byte units */
+ short wdp_eccbytes; /* ecc bytes appended */
+ char wdp_revision[8]; /* firmware revision */
+ char wdp_model[40]; /* model name */
+ u_char wdp_maxmulti; /* maximum sectors per interrupt */
+ char wdp_vendor2[1];
+ short wdp_usedmovsd; /* can use double word read/write? */
+ char wdp_vendor3[1];
+ char wdp_capabilities; /* capability flags */
+#define WD_CAP_LBA 0x02
+#define WD_CAP_DMA 0x01
+ char __reserved2[2];
+ char wdp_vendor4[1];
+ char wdp_piotiming; /* PIO timing mode */
+ char wdp_vendor5[1];
+ char wdp_dmatiming; /* DMA timing mode */
+};
+#endif /* _KERNEL */