summaryrefslogtreecommitdiff
path: root/sys/arch/macppc/dev
diff options
context:
space:
mode:
authortsubai <tsubai@NetBSD.org>1998-05-15 10:15:45 +0000
committertsubai <tsubai@NetBSD.org>1998-05-15 10:15:45 +0000
commit2be6df07c656dc3c263b28bb8fee733c061fc80f (patch)
tree1a9de8d86d84d3e0e8141a09b5405621843f1a0b /sys/arch/macppc/dev
parentb230bf09a06b3aa79e007f7c5a40d86c3fa5a5d4 (diff)
Initial import of macppc port.
Diffstat (limited to 'sys/arch/macppc/dev')
-rw-r--r--sys/arch/macppc/dev/adb.c636
-rw-r--r--sys/arch/macppc/dev/adb_direct.c2075
-rw-r--r--sys/arch/macppc/dev/adb_direct.h53
-rw-r--r--sys/arch/macppc/dev/adbsys.c632
-rw-r--r--sys/arch/macppc/dev/adbvar.h114
-rw-r--r--sys/arch/macppc/dev/am79c950.c820
-rw-r--r--sys/arch/macppc/dev/am79c950reg.h200
-rw-r--r--sys/arch/macppc/dev/dbdma.c130
-rw-r--r--sys/arch/macppc/dev/dbdma.h211
-rw-r--r--sys/arch/macppc/dev/esp.c583
-rw-r--r--sys/arch/macppc/dev/espvar.h62
-rw-r--r--sys/arch/macppc/dev/font_8x16.c556
-rw-r--r--sys/arch/macppc/dev/grf.c286
-rw-r--r--sys/arch/macppc/dev/grf_ati.c130
-rw-r--r--sys/arch/macppc/dev/grf_subr.c59
-rw-r--r--sys/arch/macppc/dev/grfvar.h82
-rw-r--r--sys/arch/macppc/dev/if_mc.c404
-rw-r--r--sys/arch/macppc/dev/if_mcvar.h99
-rw-r--r--sys/arch/macppc/dev/ite.c1380
-rw-r--r--sys/arch/macppc/dev/itevar.h55
-rw-r--r--sys/arch/macppc/dev/obio.c102
-rw-r--r--sys/arch/macppc/dev/viareg.h250
-rw-r--r--sys/arch/macppc/dev/z8530tty.c1463
-rw-r--r--sys/arch/macppc/dev/zs.c1156
24 files changed, 11538 insertions, 0 deletions
diff --git a/sys/arch/macppc/dev/adb.c b/sys/arch/macppc/dev/adb.c
new file mode 100644
index 00000000000..0263a2b4a8c
--- /dev/null
+++ b/sys/arch/macppc/dev/adb.c
@@ -0,0 +1,636 @@
+/* $NetBSD: adb.c,v 1.1 1998/05/15 10:15:47 tsubai Exp $ */
+
+/*-
+ * Copyright (C) 1994 Bradley A. Grantham
+ * 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 Bradley A. Grantham.
+ * 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/device.h>
+#include <sys/fcntl.h>
+#include <sys/poll.h>
+#include <sys/select.h>
+#include <sys/proc.h>
+#include <sys/signalvar.h>
+#include <sys/systm.h>
+
+#include <machine/autoconf.h>
+#include <machine/keyboard.h>
+
+#include <macppc/dev/adbvar.h>
+#include <macppc/dev/viareg.h>
+
+#define spladb splhigh /* XXX */
+
+/*
+ * Function declarations.
+ */
+static int adbmatch __P((struct device *, struct cfdata *, void *));
+static void adbattach __P((struct device *, struct device *, void *));
+
+/*
+ * Global variables.
+ */
+int adb_polling = 0; /* Are we polling? (Debugger mode) */
+int adb_initted = 0; /* adb_init() has completed successfully */
+#ifdef ADB_DEBUG
+int adb_debug = 0; /* Output debugging messages */
+#endif /* ADB_DEBUG */
+
+volatile u_char *Via1Base;
+
+/*
+ * Local variables.
+ */
+
+/* External keyboard translation matrix */
+extern unsigned char keyboard[128][3];
+
+/* Event queue definitions */
+#if !defined(ADB_MAX_EVENTS)
+#define ADB_MAX_EVENTS 200 /* Maximum events to be kept in queue */
+ /* maybe should be higher for slower macs? */
+#endif /* !defined(ADB_MAX_EVENTS) */
+static adb_event_t adb_evq[ADB_MAX_EVENTS]; /* ADB event queue */
+static int adb_evq_tail = 0; /* event queue tail */
+static int adb_evq_len = 0; /* event queue length */
+
+/* ADB device state information */
+static int adb_isopen = 0; /* Are we queuing events for adb_read? */
+static struct selinfo adb_selinfo; /* select() info */
+static struct proc *adb_ioproc = NULL; /* process to wakeup */
+
+/* Key repeat parameters */
+static int adb_rptdelay = 20; /* ticks before auto-repeat */
+static int adb_rptinterval = 6; /* ticks between auto-repeat */
+static int adb_repeating = -1; /* key that is auto-repeating */
+static adb_event_t adb_rptevent;/* event to auto-repeat */
+
+/* Mouse button state */
+static int adb_ms_buttons = 0;
+
+/* Driver definition. -- This should probably be a bus... */
+struct cfattach adb_ca = {
+ sizeof(struct adb_softc), adbmatch, adbattach
+};
+
+static int
+adbmatch(parent, cf, aux)
+ struct device *parent;
+ struct cfdata *cf;
+ void *aux;
+{
+ struct confargs *ca = aux;
+
+ if (strcmp(ca->ca_name, "via-cuda") != 0)
+ return 0;
+
+ if (ca->ca_nreg < 8)
+ return 0;
+
+ if (ca->ca_nintr < 4)
+ return 0;
+
+ return 1;
+}
+
+static void
+adbattach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct adb_softc *sc = (struct adb_softc *)self;
+ struct confargs *ca = aux;
+ u_long time = -1;
+ extern adb_intr();
+
+ ca->ca_reg[0] += ca->ca_baseaddr;
+
+ sc->sc_regbase = mapiodev(ca->ca_reg[0], ca->ca_reg[1]);
+ Via1Base = sc->sc_regbase;
+
+ printf(" irq %d\n", ca->ca_intr[0]);
+
+ adb_polling = 1;
+ adb_init();
+ kbd_init();
+ adb_polling = 0;
+
+ intr_establish(ca->ca_intr[0], IST_LEVEL, IPL_HIGH, adb_intr, sc);
+}
+
+void
+adb_enqevent(event)
+ adb_event_t *event;
+{
+ int s;
+
+ s = spladb();
+
+#ifdef DIAGNOSTIC
+ if (adb_evq_tail < 0 || adb_evq_tail >= ADB_MAX_EVENTS)
+ panic("adb: event queue tail is out of bounds");
+
+ if (adb_evq_len < 0 || adb_evq_len > ADB_MAX_EVENTS)
+ panic("adb: event queue len is out of bounds");
+#endif
+
+ if (adb_evq_len == ADB_MAX_EVENTS) {
+ splx(s);
+ return; /* Oh, well... */
+ }
+ adb_evq[(adb_evq_len + adb_evq_tail) % ADB_MAX_EVENTS] =
+ *event;
+ adb_evq_len++;
+
+ selwakeup(&adb_selinfo);
+ if (adb_ioproc)
+ psignal(adb_ioproc, SIGIO);
+
+ splx(s);
+}
+
+void
+adb_handoff(event)
+ adb_event_t *event;
+{
+ if (adb_isopen && !adb_polling) {
+ adb_enqevent(event);
+ } else {
+ if (event->def_addr == 2)
+ ite_intr(event);
+ }
+}
+
+
+void
+adb_autorepeat(keyp)
+ void *keyp;
+{
+ int key = (int)keyp;
+
+ adb_rptevent.bytes[0] |= 0x80;
+ microtime(&adb_rptevent.timestamp);
+ adb_handoff(&adb_rptevent); /* do key up */
+
+ adb_rptevent.bytes[0] &= 0x7f;
+ microtime(&adb_rptevent.timestamp);
+ adb_handoff(&adb_rptevent); /* do key down */
+
+ if (adb_repeating == key) {
+ timeout(adb_autorepeat, keyp, adb_rptinterval);
+ }
+}
+
+
+void
+adb_dokeyupdown(event)
+ adb_event_t *event;
+{
+ int adb_key;
+
+ if (event->def_addr == 2) {
+ adb_key = event->u.k.key & 0x7f;
+ if (!(event->u.k.key & 0x80) &&
+ keyboard[event->u.k.key & 0x7f][0] != 0) {
+ /* ignore shift & control */
+ if (adb_repeating != -1) {
+ untimeout(adb_autorepeat,
+ (void *)adb_rptevent.u.k.key);
+ }
+ adb_rptevent = *event;
+ adb_repeating = adb_key;
+ timeout(adb_autorepeat,
+ (void *)adb_key, adb_rptdelay);
+ } else {
+ if (adb_repeating != -1) {
+ adb_repeating = -1;
+ untimeout(adb_autorepeat,
+ (void *)adb_rptevent.u.k.key);
+ }
+ adb_rptevent = *event;
+ }
+ }
+ adb_handoff(event);
+}
+
+void
+adb_keymaybemouse(event)
+ adb_event_t *event;
+{
+ static int optionkey_down = 0;
+ adb_event_t new_event;
+
+ if (event->u.k.key == ADBK_KEYDOWN(ADBK_OPTION)) {
+ optionkey_down = 1;
+ } else if (event->u.k.key == ADBK_KEYUP(ADBK_OPTION)) {
+ /* key up */
+ optionkey_down = 0;
+ if (adb_ms_buttons & 0xfe) {
+ adb_ms_buttons &= 1;
+ new_event.def_addr = ADBADDR_MS;
+ new_event.u.m.buttons = adb_ms_buttons;
+ new_event.u.m.dx = new_event.u.m.dy = 0;
+ microtime(&new_event.timestamp);
+ adb_dokeyupdown(&new_event);
+ }
+ } else if (optionkey_down) {
+#ifdef ALTXBUTTONS
+ if (event->u.k.key == ADBK_KEYDOWN(ADBK_1)) {
+ adb_ms_buttons |= 1; /* left down */
+ new_event.def_addr = ADBADDR_MS;
+ new_event.u.m.buttons = adb_ms_buttons;
+ new_event.u.m.dx = new_event.u.m.dy = 0;
+ microtime(&new_event.timestamp);
+ adb_dokeyupdown(&new_event);
+ } else if (event->u.k.key == ADBK_KEYUP(ADBK_1)) {
+ adb_ms_buttons &= ~1; /* left up */
+ new_event.def_addr = ADBADDR_MS;
+ new_event.u.m.buttons = adb_ms_buttons;
+ new_event.u.m.dx = new_event.u.m.dy = 0;
+ microtime(&new_event.timestamp);
+ adb_dokeyupdown(&new_event);
+ } else
+#endif
+ if (event->u.k.key == ADBK_KEYDOWN(ADBK_LEFT)
+#ifdef ALTXBUTTONS
+ || event->u.k.key == ADBK_KEYDOWN(ADBK_2)
+#endif
+ ) {
+ adb_ms_buttons |= 2; /* middle down */
+ new_event.def_addr = ADBADDR_MS;
+ new_event.u.m.buttons = adb_ms_buttons;
+ new_event.u.m.dx = new_event.u.m.dy = 0;
+ microtime(&new_event.timestamp);
+ adb_dokeyupdown(&new_event);
+ } else if (event->u.k.key == ADBK_KEYUP(ADBK_LEFT)
+#ifdef ALTXBUTTONS
+ || event->u.k.key == ADBK_KEYUP(ADBK_2)
+#endif
+ ) {
+ adb_ms_buttons &= ~2; /* middle up */
+ new_event.def_addr = ADBADDR_MS;
+ new_event.u.m.buttons = adb_ms_buttons;
+ new_event.u.m.dx = new_event.u.m.dy = 0;
+ microtime(&new_event.timestamp);
+ adb_dokeyupdown(&new_event);
+ } else if (event->u.k.key == ADBK_KEYDOWN(ADBK_RIGHT)
+#ifdef ALTXBUTTONS
+ || event->u.k.key == ADBK_KEYDOWN(ADBK_3)
+#endif
+ ) {
+ adb_ms_buttons |= 4; /* right down */
+ new_event.def_addr = ADBADDR_MS;
+ new_event.u.m.buttons = adb_ms_buttons;
+ new_event.u.m.dx = new_event.u.m.dy = 0;
+ microtime(&new_event.timestamp);
+ adb_dokeyupdown(&new_event);
+ } else if (event->u.k.key == ADBK_KEYUP(ADBK_RIGHT)
+#ifdef ALTXBUTTONS
+ || event->u.k.key == ADBK_KEYUP(ADBK_3)
+#endif
+ ) {
+ adb_ms_buttons &= ~4; /* right up */
+ new_event.def_addr = ADBADDR_MS;
+ new_event.u.m.buttons = adb_ms_buttons;
+ new_event.u.m.dx = new_event.u.m.dy = 0;
+ microtime(&new_event.timestamp);
+ adb_dokeyupdown(&new_event);
+ } else if (ADBK_MODIFIER(event->u.k.key)) {
+ /* ctrl, shift, cmd */
+ adb_dokeyupdown(event);
+ } else if (!(event->u.k.key & 0x80)) {
+ /* key down */
+ new_event = *event;
+
+ /* send option-down */
+ new_event.u.k.key = ADBK_KEYDOWN(ADBK_OPTION);
+ new_event.bytes[0] = new_event.u.k.key;
+ microtime(&new_event.timestamp);
+ adb_dokeyupdown(&new_event);
+
+ /* send key-down */
+ new_event.u.k.key = event->bytes[0];
+ new_event.bytes[0] = new_event.u.k.key;
+ microtime(&new_event.timestamp);
+ adb_dokeyupdown(&new_event);
+
+ /* send key-up */
+ new_event.u.k.key =
+ ADBK_KEYUP(ADBK_KEYVAL(event->bytes[0]));
+ microtime(&new_event.timestamp);
+ new_event.bytes[0] = new_event.u.k.key;
+ adb_dokeyupdown(&new_event);
+
+ /* send option-up */
+ new_event.u.k.key = ADBK_KEYUP(ADBK_OPTION);
+ new_event.bytes[0] = new_event.u.k.key;
+ microtime(&new_event.timestamp);
+ adb_dokeyupdown(&new_event);
+ } else {
+ /* option-keyup -- do nothing. */
+ }
+ } else {
+ adb_dokeyupdown(event);
+ }
+}
+
+
+void
+adb_processevent(event)
+ adb_event_t *event;
+{
+ adb_event_t new_event;
+ int i, button_bit, max_byte, mask, buttons;
+
+ new_event = *event;
+ buttons = 0;
+
+ switch (event->def_addr) {
+ case ADBADDR_KBD:
+ new_event.u.k.key = event->bytes[0];
+ new_event.bytes[1] = 0xff;
+ adb_keymaybemouse(&new_event);
+ if (event->bytes[1] != 0xff) {
+ new_event.u.k.key = event->bytes[1];
+ new_event.bytes[0] = event->bytes[1];
+ new_event.bytes[1] = 0xff;
+ adb_keymaybemouse(&new_event);
+ }
+ break;
+ case ADBADDR_MS:
+ /*
+ * This should handle both plain ol' Apple mice and mice
+ * that claim to support the Extended Apple Mouse Protocol.
+ */
+ max_byte = event->byte_count;
+ button_bit = 1;
+ switch (event->hand_id) {
+ case ADBMS_USPEED:
+ /* MicroSpeed mouse */
+ if (max_byte == 4)
+ buttons = (~event->bytes[2]) & 0xff;
+ else
+ buttons = (event->bytes[0] & 0x80) ? 0 : 1;
+ break;
+ case ADBMS_MSA3:
+ /* Mouse Systems A3 mouse */
+ if (max_byte == 3)
+ buttons = (~event->bytes[2]) & 0x07;
+ else
+ buttons = (event->bytes[0] & 0x80) ? 0 : 1;
+ break;
+ default:
+ /* Classic Mouse Protocol (up to 2 buttons) */
+ for (i = 0; i < 2; i++, button_bit <<= 1)
+ /* 0 when button down */
+ if (!(event->bytes[i] & 0x80))
+ buttons |= button_bit;
+ else
+ buttons &= ~button_bit;
+ /* Extended Protocol (up to 6 more buttons) */
+ for (mask = 0x80; i < max_byte;
+ i += (mask == 0x80), button_bit <<= 1) {
+ /* 0 when button down */
+ if (!(event->bytes[i] & mask))
+ buttons |= button_bit;
+ else
+ buttons &= ~button_bit;
+ mask = ((mask >> 4) & 0xf)
+ | ((mask & 0xf) << 4);
+ }
+ break;
+ }
+ new_event.u.m.buttons = adb_ms_buttons | buttons;
+ new_event.u.m.dx = ((signed int) (event->bytes[1] & 0x3f)) -
+ ((event->bytes[1] & 0x40) ? 64 : 0);
+ new_event.u.m.dy = ((signed int) (event->bytes[0] & 0x3f)) -
+ ((event->bytes[0] & 0x40) ? 64 : 0);
+ adb_dokeyupdown(&new_event);
+ break;
+ default: /* God only knows. */
+ adb_dokeyupdown(event);
+ }
+}
+
+
+int
+adbopen(dev, flag, mode, p)
+ dev_t dev;
+ int flag, mode;
+ struct proc *p;
+{
+ register int unit;
+ int error = 0;
+ int s;
+
+ unit = minor(dev);
+ if (unit != 0 || !adb_initted)
+ return (ENXIO);
+
+ s = spladb();
+ if (adb_isopen) {
+ splx(s);
+ return (EBUSY);
+ }
+ adb_evq_tail = 0;
+ adb_evq_len = 0;
+ adb_isopen = 1;
+ adb_ioproc = p;
+ splx(s);
+
+ return (error);
+}
+
+
+int
+adbclose(dev, flag, mode, p)
+ dev_t dev;
+ int flag, mode;
+ struct proc *p;
+{
+ int s = spladb();
+
+ adb_isopen = 0;
+ adb_ioproc = NULL;
+ splx(s);
+
+ return (0);
+}
+
+
+int
+adbread(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ int s, error;
+ int willfit;
+ int total;
+ int firstmove;
+ int moremove;
+
+ if (uio->uio_resid < sizeof(adb_event_t))
+ return (EMSGSIZE); /* close enough. */
+
+ s = spladb();
+ if (adb_evq_len == 0) {
+ splx(s);
+ return (0);
+ }
+ willfit = howmany(uio->uio_resid, sizeof(adb_event_t));
+ total = (adb_evq_len < willfit) ? adb_evq_len : willfit;
+
+ firstmove = (adb_evq_tail + total > ADB_MAX_EVENTS)
+ ? (ADB_MAX_EVENTS - adb_evq_tail) : total;
+
+ error = uiomove((caddr_t) & adb_evq[adb_evq_tail],
+ firstmove * sizeof(adb_event_t), uio);
+ if (error) {
+ splx(s);
+ return (error);
+ }
+ moremove = total - firstmove;
+
+ if (moremove > 0) {
+ error = uiomove((caddr_t) & adb_evq[0],
+ moremove * sizeof(adb_event_t), uio);
+ if (error) {
+ splx(s);
+ return (error);
+ }
+ }
+ adb_evq_tail = (adb_evq_tail + total) % ADB_MAX_EVENTS;
+ adb_evq_len -= total;
+ splx(s);
+ return (0);
+}
+
+
+int
+adbwrite(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ return 0;
+}
+
+
+int
+adbioctl(dev, cmd, data, flag, p)
+ dev_t dev;
+ int cmd;
+ caddr_t data;
+ int flag;
+ struct proc *p;
+{
+ switch (cmd) {
+ case ADBIOCDEVSINFO: {
+ adb_devinfo_t *di;
+ ADBDataBlock adbdata;
+ int totaldevs;
+ int adbaddr;
+ int i;
+
+ di = (void *)data;
+
+ /* Initialize to no devices */
+ for (i = 0; i < 16; i++)
+ di->dev[i].addr = -1;
+
+ totaldevs = CountADBs();
+ for (i = 1; i <= totaldevs; i++) {
+ adbaddr = GetIndADB(&adbdata, i);
+ di->dev[adbaddr].addr = adbaddr;
+ di->dev[adbaddr].default_addr = adbdata.origADBAddr;
+ di->dev[adbaddr].handler_id = adbdata.devType;
+ }
+
+ /* Must call ADB Manager to get devices now */
+ break;
+ }
+
+ case ADBIOCGETREPEAT:{
+ adb_rptinfo_t *ri;
+
+ ri = (void *)data;
+ ri->delay_ticks = adb_rptdelay;
+ ri->interval_ticks = adb_rptinterval;
+ break;
+ }
+
+ case ADBIOCSETREPEAT:{
+ adb_rptinfo_t *ri;
+
+ ri = (void *)data;
+ adb_rptdelay = ri->delay_ticks;
+ adb_rptinterval = ri->interval_ticks;
+ break;
+ }
+
+ case ADBIOCRESET:
+ adb_init();
+ break;
+
+ case ADBIOCLISTENCMD:{
+ adb_listencmd_t *lc;
+
+ lc = (void *)data;
+ }
+
+ default:
+ return (EINVAL);
+ }
+ return (0);
+}
+
+
+int
+adbpoll(dev, events, p)
+ dev_t dev;
+ int events;
+ struct proc *p;
+{
+ int s, revents;
+
+ revents = events & (POLLOUT | POLLWRNORM);
+
+ if ((events & (POLLIN | POLLRDNORM)) == 0)
+ return (revents);
+
+ s = spladb();
+ if (adb_evq_len > 0)
+ revents |= events & (POLLIN | POLLRDNORM);
+ else
+ selrecord(p, &adb_selinfo);
+ splx(s);
+
+ return (revents);
+}
diff --git a/sys/arch/macppc/dev/adb_direct.c b/sys/arch/macppc/dev/adb_direct.c
new file mode 100644
index 00000000000..c7110713989
--- /dev/null
+++ b/sys/arch/macppc/dev/adb_direct.c
@@ -0,0 +1,2075 @@
+/* $NetBSD: adb_direct.c,v 1.1 1998/05/15 10:15:47 tsubai Exp $ */
+
+/* From: adb_direct.c 2.02 4/18/97 jpw */
+
+/*
+ * Copyright (C) 1996, 1997 John P. Wittkoski
+ * 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 John P. Wittkoski.
+ * 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.
+ */
+
+/*
+ * This code is rather messy, but I don't have time right now
+ * to clean it up as much as I would like.
+ * But it works, so I'm happy. :-) jpw
+ */
+
+/*
+ * TO DO:
+ * - We could reduce the time spent in the adb_intr_* routines
+ * by having them save the incoming and outgoing data directly
+ * in the adbInbound and adbOutbound queues, as it would reduce
+ * the number of times we need to copy the data around. It
+ * would also make the code more readable and easier to follow.
+ * - (Related to above) Use the header part of adbCommand to
+ * reduce the number of copies we have to do of the data.
+ * - (Related to above) Actually implement the adbOutbound queue.
+ * This is fairly easy once you switch all the intr routines
+ * over to using adbCommand structs directly.
+ * - There is a bug in the state machine of adb_intr_cuda
+ * code that causes hangs, especially on 030 machines, probably
+ * because of some timing issues. Because I have been unable to
+ * determine the exact cause of this bug, I used the timeout function
+ * to check for and recover from this condition. If anyone finds
+ * the actual cause of this bug, the calls to timeout and the
+ * adb_cuda_tickle routine can be removed.
+ */
+
+#include <sys/param.h>
+#include <sys/cdefs.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+
+#include <machine/param.h>
+#include <machine/cpu.h>
+#include <machine/adbsys.h>
+
+#include <macppc/dev/viareg.h>
+#include <macppc/dev/adbvar.h>
+#include <macppc/dev/adb_direct.h>
+
+#define printf_intr printf
+
+/* some misc. leftovers */
+#define vPB 0x0000
+#define vPB3 0x08
+#define vPB4 0x10
+#define vPB5 0x20
+#define vSR_INT 0x04
+#define vSR_OUT 0x10
+
+/* types of adb hardware that we (will eventually) support */
+#define ADB_HW_UNKNOWN 0x01 /* don't know */
+#define ADB_HW_II 0x02 /* Mac II series */
+#define ADB_HW_IISI 0x03 /* Mac IIsi series */
+#define ADB_HW_PB 0x04 /* PowerBook series */
+#define ADB_HW_CUDA 0x05 /* Machines with a Cuda chip */
+
+/* the type of ADB action that we are currently preforming */
+#define ADB_ACTION_NOTREADY 0x01 /* has not been initialized yet */
+#define ADB_ACTION_IDLE 0x02 /* the bus is currently idle */
+#define ADB_ACTION_OUT 0x03 /* sending out a command */
+#define ADB_ACTION_IN 0x04 /* receiving data */
+#define ADB_ACTION_POLLING 0x05 /* polling - II only */
+
+/*
+ * These describe the state of the ADB bus itself, although they
+ * don't necessarily correspond directly to ADB states.
+ * Note: these are not really used in the IIsi code.
+ */
+#define ADB_BUS_UNKNOWN 0x01 /* we don't know yet - all models */
+#define ADB_BUS_IDLE 0x02 /* bus is idle - all models */
+#define ADB_BUS_CMD 0x03 /* starting a command - II models */
+#define ADB_BUS_ODD 0x04 /* the "odd" state - II models */
+#define ADB_BUS_EVEN 0x05 /* the "even" state - II models */
+#define ADB_BUS_ACTIVE 0x06 /* active state - IIsi models */
+#define ADB_BUS_ACK 0x07 /* currently ACKing - IIsi models */
+
+/*
+ * Shortcuts for setting or testing the VIA bit states.
+ * Not all shortcuts are used for every type of ADB hardware.
+ */
+#define ADB_SET_STATE_IDLE_II() via_reg_or(VIA1, vBufB, (vPB4 | vPB5))
+#define ADB_SET_STATE_IDLE_IISI() via_reg_and(VIA1, vBufB, ~(vPB4 | vPB5))
+#define ADB_SET_STATE_IDLE_CUDA() via_reg_or(VIA1, vBufB, (vPB4 | vPB5))
+#define ADB_SET_STATE_CMD() via_reg_and(VIA1, vBufB, ~(vPB4 | vPB5))
+#define ADB_SET_STATE_EVEN() write_via_reg(VIA1, vBufB, \
+ (read_via_reg(VIA1, vBufB) | vPB4) & ~vPB5)
+#define ADB_SET_STATE_ODD() write_via_reg(VIA1, vBufB, \
+ (read_via_reg(VIA1, vBufB) | vPB5) & ~vPB4 )
+#define ADB_SET_STATE_ACTIVE() via_reg_or(VIA1, vBufB, vPB5)
+#define ADB_SET_STATE_INACTIVE() via_reg_and(VIA1, vBufB, ~vPB5)
+#define ADB_SET_STATE_TIP() via_reg_and(VIA1, vBufB, ~vPB5)
+#define ADB_CLR_STATE_TIP() via_reg_or(VIA1, vBufB, vPB5)
+#define ADB_SET_STATE_ACKON() via_reg_or(VIA1, vBufB, vPB4)
+#define ADB_SET_STATE_ACKOFF() via_reg_and(VIA1, vBufB, ~vPB4)
+#define ADB_TOGGLE_STATE_ACK_CUDA() via_reg_xor(VIA1, vBufB, vPB4)
+#define ADB_SET_STATE_ACKON_CUDA() via_reg_and(VIA1, vBufB, ~vPB4)
+#define ADB_SET_STATE_ACKOFF_CUDA() via_reg_or(VIA1, vBufB, vPB4)
+#define ADB_SET_SR_INPUT() via_reg_and(VIA1, vACR, ~vSR_OUT)
+#define ADB_SET_SR_OUTPUT() via_reg_or(VIA1, vACR, vSR_OUT)
+#define ADB_SR() read_via_reg(VIA1, vSR)
+#define ADB_VIA_INTR_ENABLE() write_via_reg(VIA1, vIER, 0x84)
+#define ADB_VIA_INTR_DISABLE() write_via_reg(VIA1, vIER, 0x04)
+#define ADB_VIA_CLR_INTR() write_via_reg(VIA1, vIFR, 0x04)
+#define ADB_INTR_IS_OFF (vPB3 == (read_via_reg(VIA1, vBufB) & vPB3))
+#define ADB_INTR_IS_ON (0 == (read_via_reg(VIA1, vBufB) & vPB3))
+#define ADB_SR_INTR_IS_OFF (0 == (read_via_reg(VIA1, vIFR) & vSR_INT))
+#define ADB_SR_INTR_IS_ON (vSR_INT == (read_via_reg(VIA1, \
+ vIFR) & vSR_INT))
+
+/*
+ * This is the delay that is required (in uS) between certain
+ * ADB transactions. The actual timing delay for for each uS is
+ * calculated at boot time to account for differences in machine speed.
+ */
+/*#define ADB_DELAY 150*/
+#define ADB_DELAY 1000
+
+/*
+ * Maximum ADB message length; includes space for data, result, and
+ * device code - plus a little for safety.
+ */
+#define ADB_MAX_MSG_LENGTH 16
+#define ADB_MAX_HDR_LENGTH 8
+
+#define ADB_QUEUE 32
+#define ADB_TICKLE_TICKS 4
+
+/*
+ * A structure for storing information about each ADB device.
+ */
+struct ADBDevEntry {
+ void (*ServiceRtPtr) __P((void));
+ void *DataAreaAddr;
+ char devType;
+ char origAddr;
+ char currentAddr;
+};
+
+/*
+ * Used to hold ADB commands that are waiting to be sent out.
+ */
+struct adbCmdHoldEntry {
+ u_char outBuf[ADB_MAX_MSG_LENGTH]; /* our message */
+ u_char *saveBuf; /* buffer to know where to save result */
+ u_char *compRout; /* completion routine pointer */
+ u_char *data; /* completion routine data pointer */
+};
+
+/*
+ * Eventually used for two separate queues, the queue between
+ * the upper and lower halves, and the outgoing packet queue.
+ * TO DO: adbCommand can replace all of adbCmdHoldEntry eventually
+ */
+struct adbCommand {
+ u_char header[ADB_MAX_HDR_LENGTH]; /* not used yet */
+ u_char data[ADB_MAX_MSG_LENGTH]; /* packet data only */
+ u_char *saveBuf; /* where to save result */
+ u_char *compRout; /* completion routine pointer */
+ u_char *compData; /* completion routine data pointer */
+ u_int cmd; /* the original command for this data */
+ u_int unsol; /* 1 if packet was unsolicited */
+ u_int ack_only; /* 1 for no special processing */
+};
+
+/*
+ * A few variables that we need and their initial values.
+ */
+int adbHardware = ADB_HW_UNKNOWN;
+int adbActionState = ADB_ACTION_NOTREADY;
+int adbBusState = ADB_BUS_UNKNOWN;
+int adbWaiting = 0; /* waiting for return data from the device */
+int adbWriteDelay = 0; /* working on (or waiting to do) a write */
+int adbOutQueueHasData = 0; /* something in the queue waiting to go out */
+int adbNextEnd = 0; /* the next incoming bute is the last (II) */
+int adbSoftPower = 0; /* machine supports soft power */
+
+int adbWaitingCmd = 0; /* ADB command we are waiting for */
+u_char *adbBuffer = (long)0; /* pointer to user data area */
+void *adbCompRout = (long)0; /* pointer to the completion routine */
+void *adbCompData = (long)0; /* pointer to the completion routine data */
+long adbFakeInts = 0; /* keeps track of fake ADB interrupts for
+ * timeouts (II) */
+int adbStarting = 1; /* doing ADBReInit so do polling differently */
+int adbSendTalk = 0; /* the intr routine is sending the talk, not
+ * the user (II) */
+int adbPolling = 0; /* we are polling for service request */
+int adbPollCmd = 0; /* the last poll command we sent */
+
+u_char adbInputBuffer[ADB_MAX_MSG_LENGTH]; /* data input buffer */
+u_char adbOutputBuffer[ADB_MAX_MSG_LENGTH]; /* data output buffer */
+struct adbCmdHoldEntry adbOutQueue; /* our 1 entry output queue */
+
+int adbSentChars = 0; /* how many characters we have sent */
+int adbLastDevice = 0; /* last ADB dev we heard from (II ONLY) */
+int adbLastDevIndex = 0; /* last ADB dev loc in dev table (II ONLY) */
+int adbLastCommand = 0; /* the last ADB command we sent (II) */
+
+struct ADBDevEntry ADBDevTable[16]; /* our ADB device table */
+int ADBNumDevices; /* num. of ADB devices found with ADBReInit */
+
+struct adbCommand adbInbound[ADB_QUEUE]; /* incoming queue */
+int adbInCount = 0; /* how many packets in in queue */
+int adbInHead = 0; /* head of in queue */
+int adbInTail = 0; /* tail of in queue */
+struct adbCommand adbOutbound[ADB_QUEUE]; /* outgoing queue - not used yet */
+int adbOutCount = 0; /* how many packets in out queue */
+int adbOutHead = 0; /* head of out queue */
+int adbOutTail = 0; /* tail of out queue */
+
+int tickle_count = 0; /* how many tickles seen for this packet? */
+int tickle_serial = 0; /* the last packet tickled */
+int adb_cuda_serial = 0; /* the current packet */
+
+extern struct mac68k_machine_S mac68k_machine;
+extern int adb_polling;
+
+int zshard __P((int));
+
+void pm_setup_adb __P((void));
+void pm_check_adb_devices __P((int));
+int pm_adb_op __P((u_char *, void *, void *, int));
+void pm_init_adb_device __P((void));
+
+/*
+ * The following are private routines.
+ */
+void print_single __P((u_char *));
+void adb_intr __P((void));
+void adb_intr_II __P((void));
+void adb_intr_IIsi __P((void));
+void adb_intr_cuda __P((void));
+void adb_soft_intr __P((void));
+int send_adb_II __P((u_char *, u_char *, void *, void *, int));
+int send_adb_IIsi __P((u_char *, u_char *, void *, void *, int));
+int send_adb_cuda __P((u_char *, u_char *, void *, void *, int));
+void adb_intr_cuda_test __P((void));
+void adb_cuda_tickle __P((void));
+void adb_pass_up __P((struct adbCommand *));
+void adb_op_comprout __P((caddr_t, caddr_t, int));
+void adb_reinit __P((void));
+int count_adbs __P((void));
+int get_ind_adb_info __P((ADBDataBlock *, int));
+int get_adb_info __P((ADBDataBlock *, int));
+int set_adb_info __P((ADBSetInfoBlock *, int));
+void adb_setup_hw_type __P((void));
+int adb_op __P((Ptr, Ptr, Ptr, short));
+int adb_op_sync __P((Ptr, Ptr, Ptr, short));
+void adb_read_II __P((u_char *));
+void adb_hw_setup __P((void));
+void adb_hw_setup_IIsi __P((u_char *));
+void adb_comp_exec __P((void));
+int adb_cmd_result __P((u_char *));
+int adb_cmd_extra __P((u_char *));
+int adb_guess_next_device __P((void));
+int adb_prog_switch_enable __P((void));
+int adb_prog_switch_disable __P((void));
+/* we should create this and it will be the public version */
+int send_adb __P((u_char *, void *, void *));
+
+/*
+ * print_single
+ * Diagnostic display routine. Displays the hex values of the
+ * specified elements of the u_char. The length of the "string"
+ * is in [0].
+ */
+void
+print_single(thestring)
+ u_char *thestring;
+{
+ int x;
+
+ if ((int)(thestring[0]) == 0) {
+ printf_intr("nothing returned\n");
+ return;
+ }
+ if (thestring == 0) {
+ printf_intr("no data - null pointer\n");
+ return;
+ }
+ if (thestring[0] > 20) {
+ printf_intr("ADB: ACK > 20 no way!\n");
+ thestring[0] = 20;
+ }
+ printf_intr("(length=0x%x):", thestring[0]);
+ for (x = 0; x < thestring[0]; x++)
+ printf_intr(" 0x%02x", thestring[x + 1]);
+ printf_intr("\n");
+}
+
+void
+adb_cuda_tickle(void)
+{
+ volatile int s;
+
+ if (adbActionState == ADB_ACTION_IN) {
+ if (tickle_serial == adb_cuda_serial) {
+ if (++tickle_count > 0) {
+ s = splhigh();
+ adbActionState = ADB_ACTION_IDLE;
+ adbInputBuffer[0] = 0;
+ ADB_SET_STATE_IDLE_CUDA();
+ splx(s);
+ }
+ } else {
+ tickle_serial = adb_cuda_serial;
+ tickle_count = 0;
+ }
+ } else {
+ tickle_serial = adb_cuda_serial;
+ tickle_count = 0;
+ }
+
+ timeout((void *)adb_cuda_tickle, 0, ADB_TICKLE_TICKS);
+}
+
+/*
+ * called when when an adb interrupt happens
+ *
+ * Cuda version of adb_intr
+ * TO DO: do we want to add some zshard calls in here?
+ */
+void
+adb_intr_cuda(void)
+{
+ volatile int i, ending;
+ volatile unsigned int s;
+ struct adbCommand packet;
+
+ s = splhigh(); /* can't be too careful - might be called */
+ /* from a routine, NOT an interrupt */
+
+ ADB_VIA_CLR_INTR(); /* clear interrupt */
+ ADB_VIA_INTR_DISABLE(); /* disable ADB interrupt on IIs. */
+
+switch_start:
+ switch (adbActionState) {
+ case ADB_ACTION_IDLE:
+ /*
+ * This is an unexpected packet, so grab the first (dummy)
+ * byte, set up the proper vars, and tell the chip we are
+ * starting to receive the packet by setting the TIP bit.
+ */
+ adbInputBuffer[1] = ADB_SR();
+ adb_cuda_serial++;
+ if (ADB_INTR_IS_OFF) /* must have been a fake start */
+ break;
+
+ ADB_SET_SR_INPUT();
+ ADB_SET_STATE_TIP();
+
+ adbInputBuffer[0] = 1;
+ adbActionState = ADB_ACTION_IN;
+#ifdef ADB_DEBUG
+ if (adb_debug)
+ printf_intr("idle 0x%02x ", adbInputBuffer[1]);
+#endif
+ break;
+
+ case ADB_ACTION_IN:
+ adbInputBuffer[++adbInputBuffer[0]] = ADB_SR();
+ /* intr off means this is the last byte (end of frame) */
+ if (ADB_INTR_IS_OFF)
+ ending = 1;
+ else
+ ending = 0;
+
+ if (1 == ending) { /* end of message? */
+#ifdef ADB_DEBUG
+ if (adb_debug) {
+ printf_intr("in end 0x%02x ",
+ adbInputBuffer[adbInputBuffer[0]]);
+ print_single(adbInputBuffer);
+ }
+#endif
+
+ /*
+ * Are we waiting AND does this packet match what we
+ * are waiting for AND is it coming from either the
+ * ADB or RTC/PRAM sub-device? This section _should_
+ * recognize all ADB and RTC/PRAM type commands, but
+ * there may be more... NOTE: commands are always at
+ * [4], even for RTC/PRAM commands.
+ */
+ /* set up data for adb_pass_up */
+ for (i = 0; i <= adbInputBuffer[0]; i++)
+ packet.data[i] = adbInputBuffer[i];
+
+ if ((adbWaiting == 1) &&
+ (adbInputBuffer[4] == adbWaitingCmd) &&
+ ((adbInputBuffer[2] == 0x00) ||
+ (adbInputBuffer[2] == 0x01))) {
+ packet.saveBuf = adbBuffer;
+ packet.compRout = adbCompRout;
+ packet.compData = adbCompData;
+ packet.unsol = 0;
+ packet.ack_only = 0;
+ adb_pass_up(&packet);
+
+ adbWaitingCmd = 0; /* reset "waiting" vars */
+ adbWaiting = 0;
+ adbBuffer = (long)0;
+ adbCompRout = (long)0;
+ adbCompData = (long)0;
+ } else {
+ packet.unsol = 1;
+ packet.ack_only = 0;
+ adb_pass_up(&packet);
+ }
+
+
+ /* reset vars and signal the end of this frame */
+ adbActionState = ADB_ACTION_IDLE;
+ adbInputBuffer[0] = 0;
+ ADB_SET_STATE_IDLE_CUDA();
+ /*ADB_SET_SR_INPUT();*/
+
+ /*
+ * If there is something waiting to be sent out,
+ * the set everything up and send the first byte.
+ */
+ if (adbWriteDelay == 1) {
+ delay(ADB_DELAY); /* required */
+ adbSentChars = 0;
+ adbActionState = ADB_ACTION_OUT;
+ /*
+ * If the interrupt is on, we were too slow
+ * and the chip has already started to send
+ * something to us, so back out of the write
+ * and start a read cycle.
+ */
+ if (ADB_INTR_IS_ON) {
+ ADB_SET_SR_INPUT();
+ ADB_SET_STATE_IDLE_CUDA();
+ adbSentChars = 0;
+ adbActionState = ADB_ACTION_IDLE;
+ adbInputBuffer[0] = 0;
+ break;
+ }
+ /*
+ * If we got here, it's ok to start sending
+ * so load the first byte and tell the chip
+ * we want to send.
+ */
+ ADB_SET_STATE_TIP();
+ ADB_SET_SR_OUTPUT();
+ write_via_reg(VIA1, vSR, adbOutputBuffer[adbSentChars + 1]);
+ }
+ } else {
+ ADB_TOGGLE_STATE_ACK_CUDA();
+#ifdef ADB_DEBUG
+ if (adb_debug)
+ printf_intr("in 0x%02x ",
+ adbInputBuffer[adbInputBuffer[0]]);
+#endif
+ }
+ break;
+
+ case ADB_ACTION_OUT:
+ i = ADB_SR(); /* reset SR-intr in IFR */
+#ifdef ADB_DEBUG
+ if (adb_debug)
+ printf_intr("intr out 0x%02x ", i);
+#endif
+
+ adbSentChars++;
+ if (ADB_INTR_IS_ON) { /* ADB intr low during write */
+#ifdef ADB_DEBUG
+ if (adb_debug)
+ printf_intr("intr was on ");
+#endif
+ ADB_SET_SR_INPUT(); /* make sure SR is set to IN */
+ ADB_SET_STATE_IDLE_CUDA();
+ adbSentChars = 0; /* must start all over */
+ adbActionState = ADB_ACTION_IDLE; /* new state */
+ adbInputBuffer[0] = 0;
+ adbWriteDelay = 1; /* must retry when done with
+ * read */
+ delay(ADB_DELAY);
+ goto switch_start; /* process next state right
+ * now */
+ break;
+ }
+ if (adbOutputBuffer[0] == adbSentChars) { /* check for done */
+ if (0 == adb_cmd_result(adbOutputBuffer)) { /* do we expect data
+ * back? */
+ adbWaiting = 1; /* signal waiting for return */
+ adbWaitingCmd = adbOutputBuffer[2]; /* save waiting command */
+ } else { /* no talk, so done */
+ /* set up stuff for adb_pass_up */
+ for (i = 0; i <= adbInputBuffer[0]; i++)
+ packet.data[i] = adbInputBuffer[i];
+ packet.saveBuf = adbBuffer;
+ packet.compRout = adbCompRout;
+ packet.compData = adbCompData;
+ packet.cmd = adbWaitingCmd;
+ packet.unsol = 0;
+ packet.ack_only = 1;
+ adb_pass_up(&packet);
+
+ /* reset "waiting" vars, just in case */
+ adbWaitingCmd = 0;
+ adbBuffer = (long)0;
+ adbCompRout = (long)0;
+ adbCompData = (long)0;
+ }
+
+ adbWriteDelay = 0; /* done writing */
+ adbActionState = ADB_ACTION_IDLE; /* signal bus is idle */
+ ADB_SET_SR_INPUT();
+ ADB_SET_STATE_IDLE_CUDA();
+#ifdef ADB_DEBUG
+ if (adb_debug)
+ printf_intr("write done ");
+#endif
+ } else {
+ write_via_reg(VIA1, vSR, adbOutputBuffer[adbSentChars + 1]); /* send next byte */
+ ADB_TOGGLE_STATE_ACK_CUDA(); /* signal byte ready to
+ * shift */
+#ifdef ADB_DEBUG
+ if (adb_debug)
+ printf_intr("toggle ");
+#endif
+ }
+ break;
+
+ case ADB_ACTION_NOTREADY:
+ printf_intr("adb: not yet initialized\n");
+ break;
+
+ default:
+ printf_intr("intr: unknown ADB state\n");
+ }
+
+ ADB_VIA_INTR_ENABLE(); /* enable ADB interrupt on IIs. */
+
+ splx(s); /* restore */
+
+ return;
+} /* end adb_intr_cuda */
+
+
+int
+send_adb_cuda(u_char * in, u_char * buffer, void *compRout, void *data, int
+ command)
+{
+ int i, s, len;
+
+#ifdef ADB_DEBUG
+ if (adb_debug)
+ printf_intr("SEND\n");
+#endif
+
+ if (adbActionState == ADB_ACTION_NOTREADY)
+ return 1;
+
+ /* Don't interrupt while we are messing with the ADB */
+ s = splhigh();
+
+ if ((adbActionState == ADB_ACTION_IDLE) && /* ADB available? */
+ (ADB_INTR_IS_OFF)) { /* and no incoming interrupt? */
+ } else
+ if (adbWriteDelay == 0) /* it's busy, but is anything waiting? */
+ adbWriteDelay = 1; /* if no, then we'll "queue"
+ * it up */
+ else {
+ splx(s);
+ return 1; /* really busy! */
+ }
+
+#ifdef ADB_DEBUG
+ if (adb_debug)
+ printf_intr("QUEUE\n");
+#endif
+ if ((long)in == (long)0) { /* need to convert? */
+ /*
+ * Don't need to use adb_cmd_extra here because this section
+ * will be called ONLY when it is an ADB command (no RTC or
+ * PRAM)
+ */
+ if ((command & 0x0c) == 0x08) /* copy addl data ONLY if
+ * doing a listen! */
+ len = buffer[0]; /* length of additional data */
+ else
+ len = 0;/* no additional data */
+
+ adbOutputBuffer[0] = 2 + len; /* dev. type + command + addl.
+ * data */
+ adbOutputBuffer[1] = 0x00; /* mark as an ADB command */
+ adbOutputBuffer[2] = (u_char)command; /* load command */
+
+ for (i = 1; i <= len; i++) /* copy additional output
+ * data, if any */
+ adbOutputBuffer[2 + i] = buffer[i];
+ } else
+ for (i = 0; i <= (in[0] + 1); i++)
+ adbOutputBuffer[i] = in[i];
+
+ adbSentChars = 0; /* nothing sent yet */
+ adbBuffer = buffer; /* save buffer to know where to save result */
+ adbCompRout = compRout; /* save completion routine pointer */
+ adbCompData = data; /* save completion routine data pointer */
+ adbWaitingCmd = adbOutputBuffer[2]; /* save wait command */
+
+ if (adbWriteDelay != 1) { /* start command now? */
+#ifdef ADB_DEBUG
+ if (adb_debug)
+ printf_intr("out start NOW");
+#endif
+ delay(ADB_DELAY);
+ adbActionState = ADB_ACTION_OUT; /* set next state */
+ ADB_SET_SR_OUTPUT(); /* set shift register for OUT */
+ write_via_reg(VIA1, vSR, adbOutputBuffer[adbSentChars + 1]); /* load byte for output */
+ ADB_SET_STATE_ACKOFF_CUDA();
+ ADB_SET_STATE_TIP(); /* tell ADB that we want to send */
+ }
+ adbWriteDelay = 1; /* something in the write "queue" */
+
+ splx(s);
+
+ if ((s & (1 << 18)) || adb_polling) /* XXX were VIA1 interrupts blocked ? */
+ /* poll until byte done */
+ while ((adbActionState != ADB_ACTION_IDLE) || (ADB_INTR_IS_ON)
+ || (adbWaiting == 1))
+ if (ADB_SR_INTR_IS_ON) { /* wait for "interrupt" */
+ adb_intr_cuda(); /* process it */
+ adb_soft_intr();
+ }
+
+ return 0;
+} /* send_adb_cuda */
+
+
+void
+adb_intr_II(void)
+{
+ panic("adb_intr_II");
+}
+
+
+/*
+ * send_adb version for II series machines
+ */
+int
+send_adb_II(u_char * in, u_char * buffer, void *compRout, void *data, int command)
+{
+ panic("send_adb_II");
+}
+
+
+/*
+ * This routine is called from the II series interrupt routine
+ * to determine what the "next" device is that should be polled.
+ */
+int
+adb_guess_next_device(void)
+{
+ int last, i, dummy;
+
+ if (adbStarting) {
+ /*
+ * Start polling EVERY device, since we can't be sure there is
+ * anything in the device table yet
+ */
+ if (adbLastDevice < 1 || adbLastDevice > 15)
+ adbLastDevice = 1;
+ if (++adbLastDevice > 15) /* point to next one */
+ adbLastDevice = 1;
+ } else {
+ /* find the next device using the device table */
+ if (adbLastDevice < 1 || adbLastDevice > 15) /* let's be parinoid */
+ adbLastDevice = 2;
+ last = 1; /* default index location */
+
+ for (i = 1; i < 16; i++) /* find index entry */
+ if (ADBDevTable[i].currentAddr == adbLastDevice) { /* look for device */
+ last = i; /* found it */
+ break;
+ }
+ dummy = last; /* index to start at */
+ for (;;) { /* find next device in index */
+ if (++dummy > 15) /* wrap around if needed */
+ dummy = 1;
+ if (dummy == last) { /* didn't find any other
+ * device! This can happen if
+ * there are no devices on the
+ * bus */
+ dummy = 2;
+ break;
+ }
+ /* found the next device */
+ if (ADBDevTable[dummy].devType != 0)
+ break;
+ }
+ adbLastDevice = ADBDevTable[dummy].currentAddr;
+ }
+ return adbLastDevice;
+}
+
+
+/*
+ * Called when when an adb interrupt happens.
+ * This routine simply transfers control over to the appropriate
+ * code for the machine we are running on.
+ */
+void
+adb_intr(void)
+{
+ switch (adbHardware) {
+ case ADB_HW_II:
+ adb_intr_II();
+ break;
+
+ case ADB_HW_IISI:
+ adb_intr_IIsi();
+ break;
+
+ case ADB_HW_PB:
+ break;
+
+ case ADB_HW_CUDA:
+ adb_intr_cuda();
+ break;
+
+ case ADB_HW_UNKNOWN:
+ break;
+ }
+}
+
+
+/*
+ * called when when an adb interrupt happens
+ *
+ * IIsi version of adb_intr
+ *
+ */
+void
+adb_intr_IIsi(void)
+{
+ panic("adb_intr_IIsi");
+}
+
+
+/*****************************************************************************
+ * if the device is currently busy, and there is no data waiting to go out, then
+ * the data is "queued" in the outgoing buffer. If we are already waiting, then
+ * we return.
+ * in: if (in == 0) then the command string is built from command and buffer
+ * if (in != 0) then in is used as the command string
+ * buffer: additional data to be sent (used only if in == 0)
+ * this is also where return data is stored
+ * compRout: the completion routine that is called when then return value
+ * is received (if a return value is expected)
+ * data: a data pointer that can be used by the completion routine
+ * command: an ADB command to be sent (used only if in == 0)
+ *
+ */
+int
+send_adb_IIsi(u_char * in, u_char * buffer, void *compRout, void *data, int
+ command)
+{
+ panic("send_adb_IIsi");
+}
+
+
+/*
+ * adb_pass_up is called by the interrupt-time routines.
+ * It takes the raw packet data that was received from the
+ * device and puts it into the queue that the upper half
+ * processes. It then signals for a soft ADB interrupt which
+ * will eventually call the upper half routine (adb_soft_intr).
+ *
+ * If in->unsol is 0, then this is either the notification
+ * that the packet was sent (on a LISTEN, for example), or the
+ * response from the device (on a TALK). The completion routine
+ * is called only if the user specified one.
+ *
+ * If in->unsol is 1, then this packet was unsolicited and
+ * so we look up the device in the ADB device table to determine
+ * what it's default service routine is.
+ *
+ * If in->ack_only is 1, then we really only need to call
+ * the completion routine, so don't do any other stuff.
+ *
+ * Note that in->data contains the packet header AND data,
+ * while adbInbound[]->data contains ONLY data.
+ *
+ * Note: Called only at interrupt time. Assumes this.
+ */
+void
+adb_pass_up(struct adbCommand *in)
+{
+ int i, start = 0, len = 0, cmd = 0;
+ ADBDataBlock block;
+
+ /* temp for testing */
+ /*u_char *buffer = 0;*/
+ /*u_char *compdata = 0;*/
+ /*u_char *comprout = 0;*/
+
+ if (adbInCount >= ADB_QUEUE) {
+ printf_intr("adb: ring buffer overflow\n");
+ return;
+ }
+
+ if (in->ack_only) {
+ len = in->data[0];
+ cmd = in->cmd;
+ start = 0;
+ } else {
+ switch (adbHardware) {
+ case ADB_HW_II:
+ cmd = in->data[1];
+ if (in->data[0] < 2)
+ len = 0;
+ else
+ len = in->data[0]-1;
+ start = 1;
+ break;
+
+ case ADB_HW_IISI:
+ case ADB_HW_CUDA:
+ /* If it's unsolicited, accept only ADB data for now */
+ if (in->unsol)
+ if (0 != in->data[2])
+ return;
+ cmd = in->data[4];
+ if (in->data[0] < 5)
+ len = 0;
+ else
+ len = in->data[0]-4;
+ start = 4;
+ break;
+
+ case ADB_HW_PB:
+ return; /* how does PM handle "unsolicited" messages? */
+
+ case ADB_HW_UNKNOWN:
+ return;
+ }
+
+ /* Make sure there is a valid device entry for this device */
+ if (in->unsol) {
+ /* ignore unsolicited data during adbreinit */
+ if (adbStarting)
+ return;
+ /* get device's comp. routine and data area */
+ if (-1 == get_adb_info(&block, ((cmd & 0xf0) >> 4)))
+ return;
+ }
+ }
+
+ /*
+ * If this is an unsolicited packet, we need to fill in
+ * some info so adb_soft_intr can process this packet
+ * properly. If it's not unsolicited, then use what
+ * the caller sent us.
+ */
+ if (in->unsol) {
+ adbInbound[adbInTail].compRout = (void *)block.dbServiceRtPtr;
+ adbInbound[adbInTail].compData = (void *)block.dbDataAreaAddr;
+ adbInbound[adbInTail].saveBuf = (void *)adbInbound[adbInTail].data;
+ } else {
+ adbInbound[adbInTail].compRout = (void *)in->compRout;
+ adbInbound[adbInTail].compData = (void *)in->compData;
+ adbInbound[adbInTail].saveBuf = (void *)in->saveBuf;
+ }
+
+#ifdef ADB_DEBUG
+ if (adb_debug && in->data[1] == 2)
+ printf_intr("adb: caught error\n");
+#endif
+
+ /* copy the packet data over */
+ /*
+ * TO DO: If the *_intr routines fed their incoming data
+ * directly into an adbCommand struct, which is passed to
+ * this routine, then we could eliminate this copy.
+ */
+ for (i = 1; i <= len; i++)
+ adbInbound[adbInTail].data[i] = in->data[start+i];
+
+ adbInbound[adbInTail].data[0] = len;
+ adbInbound[adbInTail].cmd = cmd;
+
+ adbInCount++;
+ if (++adbInTail >= ADB_QUEUE)
+ adbInTail = 0;
+
+ /*
+ * If the debugger is running, call upper half manually.
+ * Otherwise, trigger a soft interrupt to handle the rest later.
+ */
+ if (adb_polling)
+ adb_soft_intr();
+ else
+ setsoftadb();
+
+ return;
+}
+
+
+/*
+ * Called to process the packets after they have been
+ * placed in the incoming queue.
+ *
+ */
+void
+adb_soft_intr(void)
+{
+ int s, i;
+ int cmd = 0;
+ u_char *buffer = 0;
+ u_char *comprout = 0;
+ u_char *compdata = 0;
+
+#if 0
+ s = splhigh();
+ printf_intr("sr: %x\n", (s & 0x0700));
+ splx(s);
+#endif
+
+/*delay(2*ADB_DELAY);*/
+
+ while (adbInCount) {
+#ifdef ADB_DEBUG
+ if (adb_debug & 0x80)
+ printf_intr("%x %x %x ",
+ adbInCount, adbInHead, adbInTail);
+#endif
+ /* get the data we need from the queue */
+ buffer = adbInbound[adbInHead].saveBuf;
+ comprout = adbInbound[adbInHead].compRout;
+ compdata = adbInbound[adbInHead].compData;
+ cmd = adbInbound[adbInHead].cmd;
+
+ /* copy over data to data area if it's valid */
+ /*
+ * Note that for unsol packets we don't want to copy the
+ * data anywhere, so buffer was already set to 0.
+ * For ack_only buffer was set to 0, so don't copy.
+ */
+ if (buffer)
+ for (i = 0; i <= adbInbound[adbInHead].data[0]; i++)
+ *(buffer+i) = adbInbound[adbInHead].data[i];
+
+#ifdef ADB_DEBUG
+ if (adb_debug & 0x80) {
+ printf_intr("%p %p %p %x ",
+ buffer, comprout, compdata, (short)cmd);
+ printf_intr("buf: ");
+ print_single(adbInbound[adbInHead].data);
+ }
+#endif
+
+ /* call default completion routine if it's valid */
+ if (comprout) {
+ int (*f)() = (void *)comprout;
+
+ (*f)(buffer, compdata, cmd);
+#if 0
+#ifdef __NetBSD__
+ asm(" movml #0xffff,sp@- | save all registers
+ movl %0,a2 | compdata
+ movl %1,a1 | comprout
+ movl %2,a0 | buffer
+ movl %3,d0 | cmd
+ jbsr a1@ | go call the routine
+ movml sp@+,#0xffff | restore all registers"
+ :
+ : "g"(compdata), "g"(comprout),
+ "g"(buffer), "g"(cmd)
+ : "d0", "a0", "a1", "a2");
+#else /* for macos based testing */
+ asm
+ {
+ movem.l a0/a1/a2/d0, -(a7)
+ move.l compdata, a2
+ move.l comprout, a1
+ move.l buffer, a0
+ move.w cmd, d0
+ jsr(a1)
+ movem.l(a7)+, d0/a2/a1/a0
+ }
+#endif
+#endif
+ }
+
+ s = splhigh();
+ adbInCount--;
+ if (++adbInHead >= ADB_QUEUE)
+ adbInHead = 0;
+ splx(s);
+
+ }
+ return;
+}
+
+
+/*
+ * This is my version of the ADBOp routine. It mainly just calls the
+ * hardware-specific routine.
+ *
+ * data : pointer to data area to be used by compRout
+ * compRout : completion routine
+ * buffer : for LISTEN: points to data to send - MAX 8 data bytes,
+ * byte 0 = # of bytes
+ * : for TALK: points to place to save return data
+ * command : the adb command to send
+ * result : 0 = success
+ * : -1 = could not complete
+ */
+int
+adb_op(Ptr buffer, Ptr compRout, Ptr data, short command)
+{
+ int result;
+
+ switch (adbHardware) {
+ case ADB_HW_II:
+ result = send_adb_II((u_char *)0, (u_char *)buffer,
+ (void *)compRout, (void *)data, (int)command);
+ if (result == 0)
+ return 0;
+ else
+ return -1;
+ break;
+
+ case ADB_HW_IISI:
+ result = send_adb_IIsi((u_char *)0, (u_char *)buffer,
+ (void *)compRout, (void *)data, (int)command);
+ /*
+ * I wish I knew why this delay is needed. It usually needs to
+ * be here when several commands are sent in close succession,
+ * especially early in device probes when doing collision
+ * detection. It must be some race condition. Sigh. - jpw
+ */
+ delay(100);
+ if (result == 0)
+ return 0;
+ else
+ return -1;
+ break;
+
+#if 0
+ case ADB_HW_PB:
+ result = pm_adb_op((u_char *)buffer, (void *)compRout,
+ (void *)data, (int)command);
+
+ if (result == 0)
+ return 0;
+ else
+ return -1;
+ break;
+#endif
+
+ case ADB_HW_CUDA:
+ result = send_adb_cuda((u_char *)0, (u_char *)buffer,
+ (void *)compRout, (void *)data, (int)command);
+ if (result == 0)
+ return 0;
+ else
+ return -1;
+ break;
+
+ case ADB_HW_UNKNOWN:
+ default:
+ return -1;
+ }
+}
+
+
+/*
+ * adb_hw_setup
+ * This routine sets up the possible machine specific hardware
+ * config (mainly VIA settings) for the various models.
+ */
+void
+adb_hw_setup(void)
+{
+ volatile int i;
+ u_char send_string[ADB_MAX_MSG_LENGTH];
+
+ switch (adbHardware) {
+ case ADB_HW_II:
+ via_reg(VIA1, vDirB) |= 0x30; /* register B bits 4 and 5:
+ * outputs */
+ via_reg(VIA1, vDirB) &= 0xf7; /* register B bit 3: input */
+ via_reg(VIA1, vACR) &= ~vSR_OUT; /* make sure SR is set
+ * to IN (II, IIsi) */
+ adbActionState = ADB_ACTION_IDLE; /* used by all types of
+ * hardware (II, IIsi) */
+ adbBusState = ADB_BUS_IDLE; /* this var. used in II-series
+ * code only */
+ via_reg(VIA1, vIER) = 0x84; /* make sure VIA interrupts
+ * are on (II, IIsi) */
+ ADB_SET_STATE_IDLE_II(); /* set ADB bus state to idle */
+
+ ADB_VIA_CLR_INTR(); /* clear interrupt */
+ break;
+
+ case ADB_HW_IISI:
+ via_reg(VIA1, vDirB) |= 0x30; /* register B bits 4 and 5:
+ * outputs */
+ via_reg(VIA1, vDirB) &= 0xf7; /* register B bit 3: input */
+ via_reg(VIA1, vACR) &= ~vSR_OUT; /* make sure SR is set
+ * to IN (II, IIsi) */
+ adbActionState = ADB_ACTION_IDLE; /* used by all types of
+ * hardware (II, IIsi) */
+ adbBusState = ADB_BUS_IDLE; /* this var. used in II-series
+ * code only */
+ via_reg(VIA1, vIER) = 0x84; /* make sure VIA interrupts
+ * are on (II, IIsi) */
+ ADB_SET_STATE_IDLE_IISI(); /* set ADB bus state to idle */
+
+ /* get those pesky clock ticks we missed while booting */
+ for (i = 0; i < 30; i++) {
+ delay(ADB_DELAY);
+ adb_hw_setup_IIsi(send_string);
+ printf_intr("adb: cleanup: ");
+ print_single(send_string);
+ delay(ADB_DELAY);
+ if (ADB_INTR_IS_OFF)
+ break;
+ }
+ break;
+
+ case ADB_HW_PB:
+ /*
+ * XXX - really PM_VIA_CLR_INTR - should we put it in
+ * pm_direct.h?
+ */
+ via_reg(VIA1, vIFR) = 0x90; /* clear interrupt */
+ break;
+
+ case ADB_HW_CUDA:
+ via_reg_or(VIA1, vDirB, 0x30); /* register B bits 4 and 5:
+ * outputs */
+ via_reg_and(VIA1, vDirB, 0xf7); /* register B bit 3: input */
+ via_reg_and(VIA1, vACR, ~vSR_OUT); /* make sure SR is set
+ * to IN */
+ write_via_reg(VIA1, vACR, (read_via_reg(VIA1, vACR) | 0x0c) & ~0x10);
+ adbActionState = ADB_ACTION_IDLE; /* used by all types of
+ * hardware */
+ adbBusState = ADB_BUS_IDLE; /* this var. used in II-series
+ * code only */
+ write_via_reg(VIA1, vIER, 0x84);/* make sure VIA interrupts
+ * are on */
+ ADB_SET_STATE_IDLE_CUDA(); /* set ADB bus state to idle */
+
+ /* sort of a device reset */
+ i = ADB_SR(); /* clear interrupt */
+ ADB_VIA_INTR_DISABLE(); /* no interrupts while clearing */
+ ADB_SET_STATE_IDLE_CUDA(); /* reset state to idle */
+ delay(ADB_DELAY);
+ ADB_SET_STATE_TIP(); /* signal start of frame */
+ delay(ADB_DELAY);
+ ADB_TOGGLE_STATE_ACK_CUDA();
+ delay(ADB_DELAY);
+ ADB_CLR_STATE_TIP();
+ delay(ADB_DELAY);
+ ADB_SET_STATE_IDLE_CUDA(); /* back to idle state */
+ i = ADB_SR(); /* clear interrupt */
+ ADB_VIA_INTR_ENABLE(); /* ints ok now */
+ break;
+
+ case ADB_HW_UNKNOWN:
+ default:
+ via_reg(VIA1, vIER) = 0x04; /* turn interrupts off - TO
+ * DO: turn PB ints off? */
+ return;
+ break;
+ }
+}
+
+
+/*
+ * adb_hw_setup_IIsi
+ * This is sort of a "read" routine that forces the adb hardware through a read cycle
+ * if there is something waiting. This helps "clean up" any commands that may have gotten
+ * stuck or stopped during the boot process.
+ *
+ */
+void
+adb_hw_setup_IIsi(u_char * buffer)
+{
+ panic("adb_hw_setup_IIsi");
+}
+
+
+
+/*
+ * adb_reinit sets up the adb stuff
+ *
+ */
+void
+adb_reinit(void)
+{
+ u_char send_string[ADB_MAX_MSG_LENGTH];
+ int s = 0;
+ volatile int i, x;
+ int command;
+ int result;
+ int saveptr; /* point to next free relocation address */
+ int device;
+ int nonewtimes; /* times thru loop w/o any new devices */
+ ADBDataBlock data; /* temp. holder for getting device info */
+
+ (void)(&s); /* work around lame GCC bug */
+
+ /* Make sure we are not interrupted while building the table. */
+ if (adbHardware != ADB_HW_PB) /* ints must be on for PB? */
+ s = splhigh();
+
+ ADBNumDevices = 0; /* no devices yet */
+
+ /* Let intr routines know we are running reinit */
+ adbStarting = 1;
+
+ /*
+ * Initialize the ADB table. For now, we'll always use the same table
+ * that is defined at the beginning of this file - no mallocs.
+ */
+ for (i = 0; i < 16; i++)
+ ADBDevTable[i].devType = 0;
+
+ adb_setup_hw_type(); /* setup hardware type */
+
+ adb_hw_setup(); /* init the VIA bits and hard reset ADB */
+
+ DELAY(1000);
+
+ /* send an ADB reset first */
+ adb_op_sync((Ptr)0, (Ptr)0, (Ptr)0, (short)0x00);
+
+ /*
+ * Probe for ADB devices. Probe devices 1-15 quickly to determine
+ * which device addresses are in use and which are free. For each
+ * address that is in use, move the device at that address to a higher
+ * free address. Continue doing this at that address until no device
+ * responds at that address. Then move the last device that was moved
+ * back to the original address. Do this for the remaining addresses
+ * that we determined were in use.
+ *
+ * When finished, do this entire process over again with the updated
+ * list of in use addresses. Do this until no new devices have been
+ * found in 20 passes though the in use address list. (This probably
+ * seems long and complicated, but it's the best way to detect multiple
+ * devices at the same address - sometimes it takes a couple of tries
+ * before the collision is detected.)
+ */
+
+ /* initial scan through the devices */
+ for (i = 1; i < 16; i++) {
+ command = (int)(0x0f | ((int)(i & 0x000f) << 4)); /* talk R3 */
+ result = adb_op_sync((Ptr)send_string, (Ptr)0,
+ (Ptr)0, (short)command);
+ if (0x00 != send_string[0]) { /* anything come back ?? */
+ ADBDevTable[++ADBNumDevices].devType =
+ (u_char)send_string[2];
+ ADBDevTable[ADBNumDevices].origAddr = i;
+ ADBDevTable[ADBNumDevices].currentAddr = i;
+ ADBDevTable[ADBNumDevices].DataAreaAddr =
+ (long)0;
+ ADBDevTable[ADBNumDevices].ServiceRtPtr = (void *)0;
+ pm_check_adb_devices(i); /* tell pm driver device
+ * is here */
+ }
+ }
+
+ /* find highest unused address */
+ for (saveptr = 15; saveptr > 0; saveptr--)
+ if (-1 == get_adb_info(&data, saveptr))
+ break;
+
+ if (saveptr == 0) /* no free addresses??? */
+ saveptr = 15;
+
+#ifdef ADB_DEBUG
+ if (adb_debug & 0x80) {
+ printf_intr("first free is: 0x%02x\n", saveptr);
+ printf_intr("devices: %i\n", ADBNumDevices);
+ }
+#endif
+
+ nonewtimes = 0; /* no loops w/o new devices */
+ while (nonewtimes++ < 11) {
+ for (i = 1; i <= ADBNumDevices; i++) {
+ device = ADBDevTable[i].currentAddr;
+#ifdef ADB_DEBUG
+ if (adb_debug & 0x80)
+ printf_intr("moving device 0x%02x to 0x%02x "
+ "(index 0x%02x) ", device, saveptr, i);
+#endif
+
+ /* send TALK R3 to address */
+ command = (int)(0x0f | ((int)(device & 0x000f) << 4));
+ adb_op_sync((Ptr)send_string, (Ptr)0,
+ (Ptr)0, (short)command);
+
+ /* move device to higher address */
+ command = (int)(0x0b | ((int)(device & 0x000f) << 4));
+ send_string[0] = 2;
+ send_string[1] = (u_char)(saveptr | 0x60);
+ send_string[2] = 0xfe;
+ adb_op_sync((Ptr)send_string, (Ptr)0,
+ (Ptr)0, (short)command);
+
+ /* send TALK R3 - anything at old address? */
+ command = (int)(0x0f | ((int)(device & 0x000f) << 4));
+ result = adb_op_sync((Ptr)send_string, (Ptr)0,
+ (Ptr)0, (short)command);
+ if (send_string[0] != 0) {
+ /* new device found */
+ /* update data for previously moved device */
+ ADBDevTable[i].currentAddr = saveptr;
+#ifdef ADB_DEBUG
+ if (adb_debug & 0x80)
+ printf_intr("old device at index %i\n",i);
+#endif
+ /* add new device in table */
+#ifdef ADB_DEBUG
+ if (adb_debug & 0x80)
+ printf_intr("new device found\n");
+#endif
+ ADBDevTable[++ADBNumDevices].devType =
+ (u_char)send_string[2];
+ ADBDevTable[ADBNumDevices].origAddr = device;
+ ADBDevTable[ADBNumDevices].currentAddr = device;
+ /* These will be set correctly in adbsys.c */
+ /* Until then, unsol. data will be ignored. */
+ ADBDevTable[ADBNumDevices].DataAreaAddr =
+ (long)0;
+ ADBDevTable[ADBNumDevices].ServiceRtPtr =
+ (void *)0;
+ /* find next unused address */
+ for (x = saveptr; x > 0; x--)
+ if (-1 == get_adb_info(&data, x)) {
+ saveptr = x;
+ break;
+ }
+#ifdef ADB_DEBUG
+ if (adb_debug & 0x80)
+ printf_intr("new free is 0x%02x\n",
+ saveptr);
+#endif
+ nonewtimes = 0;
+ /* tell pm driver device is here */
+ pm_check_adb_devices(device);
+ } else {
+#ifdef ADB_DEBUG
+ if (adb_debug & 0x80)
+ printf_intr("moving back...\n");
+#endif
+ /* move old device back */
+ command = (int)(0x0b | ((int)(saveptr & 0x000f) << 4));
+ send_string[0] = 2;
+ send_string[1] = (u_char)(device | 0x60);
+ send_string[2] = 0xfe;
+ adb_op_sync((Ptr)send_string, (Ptr)0,
+ (Ptr)0, (short)command);
+ }
+ }
+ }
+
+#ifdef ADB_DEBUG
+ if (adb_debug) {
+ for (i = 1; i <= ADBNumDevices; i++) {
+ x = get_ind_adb_info(&data, i);
+ if (x != -1)
+ printf_intr("index 0x%x, addr 0x%x, type 0x%x\n",
+ i, x, data.devType);
+ }
+ }
+#endif
+
+ /* enable the programmer's switch, if we have one */
+ adb_prog_switch_enable();
+
+ if (0 == ADBNumDevices) /* tell user if no devices found */
+ printf_intr("adb: no devices found\n");
+
+ adbStarting = 0; /* not starting anymore */
+#ifdef ADB_DEBUG
+ printf_intr("adb: ADBReInit complete\n");
+#endif
+
+ if (adbHardware == ADB_HW_CUDA)
+ timeout((void *)adb_cuda_tickle, 0, ADB_TICKLE_TICKS);
+
+ if (adbHardware != ADB_HW_PB) /* ints must be on for PB? */
+ splx(s);
+ return;
+}
+
+
+#if 0
+/*
+ * adb_comp_exec
+ * This is a general routine that calls the completion routine if there is one.
+ * NOTE: This routine is now only used by pm_direct.c
+ * All the code in this file (adb_direct.c) uses
+ * the adb_pass_up routine now.
+ */
+void
+adb_comp_exec(void)
+{
+ if ((long)0 != adbCompRout) /* don't call if empty return location */
+#ifdef __NetBSD__
+ asm(" movml #0xffff,sp@- | save all registers
+ movl %0,a2 | adbCompData
+ movl %1,a1 | adbCompRout
+ movl %2,a0 | adbBuffer
+ movl %3,d0 | adbWaitingCmd
+ jbsr a1@ | go call the routine
+ movml sp@+,#0xffff | restore all registers"
+ :
+ : "g"(adbCompData), "g"(adbCompRout),
+ "g"(adbBuffer), "g"(adbWaitingCmd)
+ : "d0", "a0", "a1", "a2");
+#else /* for Mac OS-based testing */
+ asm {
+ movem.l a0/a1/a2/d0, -(a7)
+ move.l adbCompData, a2
+ move.l adbCompRout, a1
+ move.l adbBuffer, a0
+ move.w adbWaitingCmd, d0
+ jsr(a1)
+ movem.l(a7) +, d0/a2/a1/a0
+ }
+#endif
+}
+#endif
+
+
+/*
+ * adb_cmd_result
+ *
+ * This routine lets the caller know whether the specified adb command string
+ * should expect a returned result, such as a TALK command.
+ *
+ * returns: 0 if a result should be expected
+ * 1 if a result should NOT be expected
+ */
+int
+adb_cmd_result(u_char *in)
+{
+ switch (adbHardware) {
+ case ADB_HW_II:
+ /* was it an ADB talk command? */
+ if ((in[1] & 0x0c) == 0x0c)
+ return 0;
+ return 1;
+
+ case ADB_HW_IISI:
+ case ADB_HW_CUDA:
+ /* was it an ADB talk command? */
+ if ((in[1] == 0x00) && ((in[2] & 0x0c) == 0x0c))
+ return 0;
+ /* was it an RTC/PRAM read date/time? */
+ if ((in[1] == 0x01) && (in[2] == 0x03))
+ return 0;
+ return 1;
+
+ case ADB_HW_PB:
+ return 1;
+
+ case ADB_HW_UNKNOWN:
+ default:
+ return 1;
+ }
+}
+
+
+/*
+ * adb_cmd_extra
+ *
+ * This routine lets the caller know whether the specified adb command string
+ * may have extra data appended to the end of it, such as a LISTEN command.
+ *
+ * returns: 0 if extra data is allowed
+ * 1 if extra data is NOT allowed
+ */
+int
+adb_cmd_extra(u_char *in)
+{
+ switch (adbHardware) {
+ case ADB_HW_II:
+ if ((in[1] & 0x0c) == 0x08) /* was it a listen command? */
+ return 0;
+ return 1;
+
+ case ADB_HW_IISI:
+ case ADB_HW_CUDA:
+ /*
+ * TO DO: support needs to be added to recognize RTC and PRAM
+ * commands
+ */
+ if ((in[2] & 0x0c) == 0x08) /* was it a listen command? */
+ return 0;
+ /* add others later */
+ return 1;
+
+ case ADB_HW_PB:
+ return 1;
+
+ case ADB_HW_UNKNOWN:
+ default:
+ return 1;
+ }
+}
+
+
+/*
+ * adb_op_sync
+ *
+ * This routine does exactly what the adb_op routine does, except that after
+ * the adb_op is called, it waits until the return value is present before
+ * returning.
+ *
+ * NOTE: The user specified compRout is ignored, since this routine specifies
+ * it's own to adb_op, which is why you really called this in the first place
+ * anyway.
+ */
+int
+adb_op_sync(Ptr buffer, Ptr compRout, Ptr data, short command)
+{
+ int result;
+ volatile int flag = 0;
+
+ result = adb_op(buffer, (void *)adb_op_comprout,
+ (void *)&flag, command); /* send command */
+ if (result == 0) /* send ok? */
+ while (0 == flag)
+ /* wait for compl. routine */;
+
+ return result;
+}
+
+
+/*
+ * adb_op_comprout
+ *
+ * This function is used by the adb_op_sync routine so it knows when the
+ * function is done.
+ */
+void
+adb_op_comprout(buffer, compdata, cmd)
+ caddr_t buffer, compdata;
+ int cmd;
+{
+ short *p = (short *)compdata;
+
+ *p = 1;
+}
+
+void
+adb_setup_hw_type(void)
+{
+ long response;
+
+ adbHardware = ADB_HW_CUDA;
+ return;
+
+ response = 0; /*mac68k_machine.machineid;*/
+
+ /*
+ * Determine what type of ADB hardware we are running on.
+ */
+ switch (response) {
+ case 6: /* II */
+ case 7: /* IIx */
+ case 8: /* IIcx */
+ case 9: /* SE/30 */
+ case 11: /* IIci */
+ case 22: /* Quadra 700 */
+ case 30: /* Centris 650 */
+ case 35: /* Quadra 800 */
+ case 36: /* Quadra 650 */
+ case 52: /* Centris 610 */
+ case 53: /* Quadra 610 */
+ adbHardware = ADB_HW_II;
+ printf_intr("adb: using II series hardware support\n");
+ break;
+ case 18: /* IIsi */
+ case 20: /* Quadra 900 - not sure if IIsi or not */
+ case 23: /* Classic II */
+ case 26: /* Quadra 950 - not sure if IIsi or not */
+ case 27: /* LC III, Performa 450 */
+ case 37: /* LC II, Performa 400/405/430 */
+ case 44: /* IIvi */
+ case 45: /* Performa 600 */
+ case 48: /* IIvx */
+ case 62: /* Performa 460/465/467 */
+ adbHardware = ADB_HW_IISI;
+ printf_intr("adb: using IIsi series hardware support\n");
+ break;
+ case 21: /* PowerBook 170 */
+ case 25: /* PowerBook 140 */
+ case 54: /* PowerBook 145 */
+ case 34: /* PowerBook 160 */
+ case 84: /* PowerBook 165 */
+ case 50: /* PowerBook 165c */
+ case 33: /* PowerBook 180 */
+ case 71: /* PowerBook 180c */
+ case 115: /* PowerBook 150 */
+ adbHardware = ADB_HW_PB;
+ pm_setup_adb();
+ printf_intr("adb: using PowerBook 100-series hardware support\n");
+ break;
+ case 29: /* PowerBook Duo 210 */
+ case 32: /* PowerBook Duo 230 */
+ case 38: /* PowerBook Duo 250 */
+ case 72: /* PowerBook 500 series */
+ case 77: /* PowerBook Duo 270 */
+ case 102: /* PowerBook Duo 280 */
+ case 103: /* PowerBook Duo 280c */
+ adbHardware = ADB_HW_PB;
+ pm_setup_adb();
+ printf_intr("adb: using PowerBook Duo-series and PowerBook 500-series hardware support\n");
+ break;
+ case 49: /* Color Classic */
+ case 56: /* LC 520 */
+ case 60: /* Centris 660AV */
+ case 78: /* Quadra 840AV */
+ case 80: /* LC 550, Performa 550 */
+ case 83: /* Color Classic II */
+ case 89: /* LC 475, Performa 475/476 */
+ case 92: /* LC 575, Performa 575/577/578 */
+ case 94: /* Quadra 605 */
+ case 98: /* LC 630, Performa 630, Quadra 630 */
+ case 99: /* Performa 580(?)/588 */
+ adbHardware = ADB_HW_CUDA;
+ printf_intr("adb: using Cuda series hardware support\n");
+ break;
+ default:
+ adbHardware = ADB_HW_UNKNOWN;
+ printf_intr("adb: hardware type unknown for this machine\n");
+ printf_intr("adb: ADB support is disabled\n");
+ break;
+ }
+
+ /*
+ * Determine whether this machine has ADB based soft power.
+ */
+ switch (response) {
+ case 18: /* IIsi */
+ case 20: /* Quadra 900 - not sure if IIsi or not */
+ case 26: /* Quadra 950 - not sure if IIsi or not */
+ case 44: /* IIvi */
+ case 45: /* Performa 600 */
+ case 48: /* IIvx */
+ case 49: /* Color Classic */
+ case 83: /* Color Classic II */
+ case 56: /* LC 520 */
+ case 78: /* Quadra 840AV */
+ case 80: /* LC 550, Performa 550 */
+ case 92: /* LC 575, Performa 575/577/578 */
+ case 98: /* LC 630, Performa 630, Quadra 630 */
+ adbSoftPower = 1;
+ break;
+ }
+}
+
+int
+count_adbs(void)
+{
+ int i;
+ int found;
+
+ found = 0;
+
+ for (i = 1; i < 16; i++)
+ if (0 != ADBDevTable[i].devType)
+ found++;
+
+ return found;
+}
+
+int
+get_ind_adb_info(ADBDataBlock * info, int index)
+{
+ if ((index < 1) || (index > 15)) /* check range 1-15 */
+ return (-1);
+
+#ifdef ADB_DEBUG
+ if (adb_debug & 0x80)
+ printf_intr("index 0x%x devType is: 0x%x\n", index,
+ ADBDevTable[index].devType);
+#endif
+ if (0 == ADBDevTable[index].devType) /* make sure it's a valid entry */
+ return (-1);
+
+ info->devType = ADBDevTable[index].devType;
+ info->origADBAddr = ADBDevTable[index].origAddr;
+ info->dbServiceRtPtr = (Ptr)ADBDevTable[index].ServiceRtPtr;
+ info->dbDataAreaAddr = (Ptr)ADBDevTable[index].DataAreaAddr;
+
+ return (ADBDevTable[index].currentAddr);
+}
+
+int
+get_adb_info(ADBDataBlock * info, int adbAddr)
+{
+ int i;
+
+ if ((adbAddr < 1) || (adbAddr > 15)) /* check range 1-15 */
+ return (-1);
+
+ for (i = 1; i < 15; i++)
+ if (ADBDevTable[i].currentAddr == adbAddr) {
+ info->devType = ADBDevTable[i].devType;
+ info->origADBAddr = ADBDevTable[i].origAddr;
+ info->dbServiceRtPtr = (Ptr)ADBDevTable[i].ServiceRtPtr;
+ info->dbDataAreaAddr = ADBDevTable[i].DataAreaAddr;
+ return 0; /* found */
+ }
+
+ return (-1); /* not found */
+}
+
+int
+set_adb_info(ADBSetInfoBlock * info, int adbAddr)
+{
+ int i;
+
+ if ((adbAddr < 1) || (adbAddr > 15)) /* check range 1-15 */
+ return (-1);
+
+ for (i = 1; i < 15; i++)
+ if (ADBDevTable[i].currentAddr == adbAddr) {
+ ADBDevTable[i].ServiceRtPtr =
+ (void *)(info->siServiceRtPtr);
+ ADBDevTable[i].DataAreaAddr = info->siDataAreaAddr;
+ return 0; /* found */
+ }
+
+ return (-1); /* not found */
+
+}
+
+/* caller should really use machine-independant version: getPramTime */
+/* this version does pseudo-adb access only */
+int
+adb_read_date_time(unsigned long *time)
+{
+ u_char output[ADB_MAX_MSG_LENGTH];
+ int result;
+ volatile int flag = 0;
+
+ switch (adbHardware) {
+ case ADB_HW_II:
+ return -1;
+
+ case ADB_HW_IISI:
+ output[0] = 0x02; /* 2 byte message */
+ output[1] = 0x01; /* to pram/rtc device */
+ output[2] = 0x03; /* read date/time */
+ result = send_adb_IIsi((u_char *)output, (u_char *)output,
+ (void *)adb_op_comprout, (int *)&flag, (int)0);
+ if (result != 0) /* exit if not sent */
+ return -1;
+
+ while (0 == flag) /* wait for result */
+ ;
+
+ *time = (long)(*(long *)(output + 1));
+ return 0;
+
+ case ADB_HW_PB:
+ return -1;
+
+ case ADB_HW_CUDA:
+ output[0] = 0x02; /* 2 byte message */
+ output[1] = 0x01; /* to pram/rtc device */
+ output[2] = 0x03; /* read date/time */
+ result = send_adb_cuda((u_char *)output, (u_char *)output,
+ (void *)adb_op_comprout, (void *)&flag, (int)0);
+ if (result != 0) /* exit if not sent */
+ return -1;
+
+ while (0 == flag) /* wait for result */
+ ;
+
+ /* *time = (long)(*(long *)(output + 1)) - 2082844800; */
+ bcopy(output + 1, time, 4);
+ *time -= 2082844800;
+ return 0;
+
+ case ADB_HW_UNKNOWN:
+ default:
+ return -1;
+ }
+}
+
+/* caller should really use machine-independant version: setPramTime */
+/* this version does pseudo-adb access only */
+int
+adb_set_date_time(unsigned long time)
+{
+ u_char output[ADB_MAX_MSG_LENGTH];
+ int result;
+ volatile int flag = 0;
+
+ time += 2082844800;
+
+ switch (adbHardware) {
+
+ case ADB_HW_CUDA:
+ output[0] = 0x06; /* 6 byte message */
+ output[1] = 0x01; /* to pram/rtc device */
+ output[2] = 0x09; /* set date/time */
+ output[3] = (u_char)(time >> 24);
+ output[4] = (u_char)(time >> 16);
+ output[5] = (u_char)(time >> 8);
+ output[6] = (u_char)(time);
+ result = send_adb_cuda((u_char *)output, (u_char *)0,
+ (void *)adb_op_comprout, (void *)&flag, (int)0);
+ if (result != 0) /* exit if not sent */
+ return -1;
+
+ while (0 == flag) /* wait for send to finish */
+ ;
+
+ return 0;
+
+ case ADB_HW_II:
+ case ADB_HW_IISI:
+ case ADB_HW_PB:
+ case ADB_HW_UNKNOWN:
+ default:
+ return -1;
+ }
+}
+
+
+int
+adb_poweroff(void)
+{
+ u_char output[ADB_MAX_MSG_LENGTH];
+ int result;
+
+ if (!adbSoftPower)
+ return -1;
+
+ switch (adbHardware) {
+ case ADB_HW_IISI:
+ output[0] = 0x02; /* 2 byte message */
+ output[1] = 0x01; /* to pram/rtc/soft-power device */
+ output[2] = 0x0a; /* set date/time */
+ result = send_adb_IIsi((u_char *)output, (u_char *)0,
+ (void *)0, (void *)0, (int)0);
+ if (result != 0) /* exit if not sent */
+ return -1;
+
+ for (;;); /* wait for power off */
+
+ return 0;
+
+ case ADB_HW_PB:
+ return -1;
+
+ case ADB_HW_CUDA:
+ output[0] = 0x02; /* 2 byte message */
+ output[1] = 0x01; /* to pram/rtc/soft-power device */
+ output[2] = 0x0a; /* set date/time */
+ result = send_adb_cuda((u_char *)output, (u_char *)0,
+ (void *)0, (void *)0, (int)0);
+ if (result != 0) /* exit if not sent */
+ return -1;
+
+ for (;;); /* wait for power off */
+
+ return 0;
+
+ case ADB_HW_II: /* II models don't do ADB soft power */
+ case ADB_HW_UNKNOWN:
+ default:
+ return -1;
+ }
+}
+
+int
+adb_prog_switch_enable(void)
+{
+ u_char output[ADB_MAX_MSG_LENGTH];
+ int result;
+ volatile int flag = 0;
+
+ switch (adbHardware) {
+ case ADB_HW_IISI:
+ output[0] = 0x03; /* 3 byte message */
+ output[1] = 0x01; /* to pram/rtc/soft-power device */
+ output[2] = 0x1c; /* prog. switch control */
+ output[3] = 0x01; /* enable */
+ result = send_adb_IIsi((u_char *)output, (u_char *)0,
+ (void *)adb_op_comprout, (void *)&flag, (int)0);
+ if (result != 0) /* exit if not sent */
+ return -1;
+
+ while (0 == flag) /* wait for send to finish */
+ ;
+
+ return 0;
+
+ case ADB_HW_PB:
+ return -1;
+
+ case ADB_HW_II: /* II models don't do prog. switch */
+ case ADB_HW_CUDA: /* cuda doesn't do prog. switch TO DO: verify this */
+ case ADB_HW_UNKNOWN:
+ default:
+ return -1;
+ }
+}
+
+int
+adb_prog_switch_disable(void)
+{
+ u_char output[ADB_MAX_MSG_LENGTH];
+ int result;
+ volatile int flag = 0;
+
+ switch (adbHardware) {
+ case ADB_HW_IISI:
+ output[0] = 0x03; /* 3 byte message */
+ output[1] = 0x01; /* to pram/rtc/soft-power device */
+ output[2] = 0x1c; /* prog. switch control */
+ output[3] = 0x01; /* disable */
+ result = send_adb_IIsi((u_char *)output, (u_char *)0,
+ (void *)adb_op_comprout, (void *)&flag, (int)0);
+ if (result != 0) /* exit if not sent */
+ return -1;
+
+ while (0 == flag) /* wait for send to finish */
+ ;
+
+ return 0;
+
+ case ADB_HW_PB:
+ return -1;
+
+ case ADB_HW_II: /* II models don't do prog. switch */
+ case ADB_HW_CUDA: /* cuda doesn't do prog. switch */
+ case ADB_HW_UNKNOWN:
+ default:
+ return -1;
+ }
+}
+
+#ifndef MRG_ADB
+
+int
+CountADBs(void)
+{
+ return (count_adbs());
+}
+
+void
+ADBReInit(void)
+{
+ adb_reinit();
+}
+
+int
+GetIndADB(ADBDataBlock * info, int index)
+{
+ return (get_ind_adb_info(info, index));
+}
+
+int
+GetADBInfo(ADBDataBlock * info, int adbAddr)
+{
+ return (get_adb_info(info, adbAddr));
+}
+
+int
+SetADBInfo(ADBSetInfoBlock * info, int adbAddr)
+{
+ return (set_adb_info(info, adbAddr));
+}
+
+int
+ADBOp(Ptr buffer, Ptr compRout, Ptr data, short commandNum)
+{
+ return (adb_op(buffer, compRout, data, commandNum));
+}
+
+#endif
+
+
+
+void
+pm_check_adb_devices(x)
+ int x;
+{
+}
+
+int
+setsoftadb()
+{
+ timeout((void *)adb_soft_intr, NULL, 1);
+ return 0;
+}
+
+void
+kbd_init()
+{
+ volatile int flag = 0;
+ int result;
+ u_char output[16];
+ extern void adb_op_comprout();
+
+ output[0] = 0x03; /* 3-byte message */
+ output[1] = 0x01; /* to pram/rtc device */
+ output[2] = 0x01; /* cuda autopoll */
+ output[3] = 0x01;
+ result = send_adb_cuda(output, output, adb_op_comprout,
+ (void *)&flag, 0);
+ if (result != 0) /* exit if not sent */
+ return;
+
+ while (flag == 0); /* wait for result */
+}
+
+void
+powermac_restart()
+{
+ volatile int flag = 0;
+ int result;
+ u_char output[16];
+
+ output[0] = 0x02; /* 2 byte message */
+ output[1] = 0x01; /* to pram/rtc/soft-power device */
+ output[2] = 0x11; /* restart */
+ result = send_adb_cuda((u_char *)output, (u_char *)0,
+ (void *)0, (void *)0, (int)0);
+ if (result != 0) /* exit if not sent */
+ return;
+
+ while (1); /* not return */
+}
diff --git a/sys/arch/macppc/dev/adb_direct.h b/sys/arch/macppc/dev/adb_direct.h
new file mode 100644
index 00000000000..76aff051d1b
--- /dev/null
+++ b/sys/arch/macppc/dev/adb_direct.h
@@ -0,0 +1,53 @@
+/* $NetBSD: adb_direct.h,v 1.1 1998/05/15 10:15:47 tsubai Exp $ */
+
+/*
+ * Copyright (C) 1996 John P. Wittkoski
+ * 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 John P. Wittkoski.
+ * 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.
+ */
+/* From: adb_direct.h 1.4 10/23/96 jpw */
+
+/*
+ * These are public declarations that other routines may need.
+ */
+
+/* types of adb hardware that we (will eventually) support */
+#define ADB_HW_UNKNOWN 0x01 /* don't know */
+#define ADB_HW_II 0x02 /* Mac II series */
+#define ADB_HW_IISI 0x03 /* Mac IIsi series */
+#define ADB_HW_PB 0x04 /* PowerBook series */
+#define ADB_HW_CUDA 0x05 /* Machines with a Cuda chip */
+
+int adb_poweroff __P((void));
+int CountADBs __P((void));
+void ADBReInit __P((void));
+int GetIndADB __P((ADBDataBlock *info, int index));
+int GetADBInfo __P((ADBDataBlock *info, int adbAddr));
+int SetADBInfo __P((ADBSetInfoBlock *info, int adbAddr));
+int ADBOp __P((Ptr buffer, Ptr compRout, Ptr data, short commandNum));
+int adb_read_date_time __P((unsigned long *));
+int adb_set_date_time __P((unsigned long));
diff --git a/sys/arch/macppc/dev/adbsys.c b/sys/arch/macppc/dev/adbsys.c
new file mode 100644
index 00000000000..4d78551faa8
--- /dev/null
+++ b/sys/arch/macppc/dev/adbsys.c
@@ -0,0 +1,632 @@
+/* $NetBSD: adbsys.c,v 1.1 1998/05/15 10:15:47 tsubai Exp $ */
+
+/*-
+ * Copyright (C) 1994 Bradley A. Grantham
+ * 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 Bradley A. Grantham.
+ * 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/device.h>
+
+#include <machine/cpu.h>
+
+#include <macppc/dev/viareg.h>
+#include <macppc/dev/adbvar.h>
+
+/* from adb.c */
+void adb_processevent __P((adb_event_t * event));
+
+extern void adb_jadbproc __P((void));
+
+void
+adb_complete(buffer, data_area, adb_command)
+ caddr_t buffer;
+ caddr_t data_area;
+ int adb_command;
+{
+ adb_event_t event;
+ ADBDataBlock adbdata;
+ int adbaddr;
+ int error;
+#ifdef ADB_DEBUG
+ int i;
+
+ if (adb_debug)
+ printf("adb: transaction completion\n");
+#endif
+
+ adbaddr = (adb_command & 0xf0) >> 4;
+ error = GetADBInfo(&adbdata, adbaddr);
+#ifdef ADB_DEBUG
+ if (adb_debug)
+ printf("adb: GetADBInfo returned %d\n", error);
+#endif
+
+ event.addr = adbaddr;
+ event.hand_id = adbdata.devType;
+ event.def_addr = adbdata.origADBAddr;
+ event.byte_count = buffer[0];
+ memcpy(event.bytes, buffer + 1, event.byte_count);
+
+#ifdef ADB_DEBUG
+ if (adb_debug) {
+ printf("adb: from %d at %d (org %d) %d:", event.addr,
+ event.hand_id, event.def_addr, buffer[0]);
+ for (i = 1; i <= buffer[0]; i++)
+ printf(" %x", buffer[i]);
+ printf("\n");
+ }
+#endif
+
+ microtime(&event.timestamp);
+
+ adb_processevent(&event);
+}
+
+void
+adb_msa3_complete(buffer, data_area, adb_command)
+ caddr_t buffer;
+ caddr_t data_area;
+ int adb_command;
+{
+ adb_event_t event;
+ ADBDataBlock adbdata;
+ int adbaddr;
+ int error;
+#ifdef ADB_DEBUG
+ int i;
+
+ if (adb_debug)
+ printf("adb: transaction completion\n");
+#endif
+
+ adbaddr = (adb_command & 0xf0) >> 4;
+ error = GetADBInfo(&adbdata, adbaddr);
+#ifdef ADB_DEBUG
+ if (adb_debug)
+ printf("adb: GetADBInfo returned %d\n", error);
+#endif
+
+ event.addr = adbaddr;
+ event.hand_id = ADBMS_MSA3;
+ event.def_addr = adbdata.origADBAddr;
+ event.byte_count = buffer[0];
+ memcpy(event.bytes, buffer + 1, event.byte_count);
+
+#ifdef ADB_DEBUG
+ if (adb_debug) {
+ printf("adb: from %d at %d (org %d) %d:",
+ event.addr, event.hand_id, event.def_addr, buffer[0]);
+ for (i = 1; i <= buffer[0]; i++)
+ printf(" %x", buffer[i]);
+ printf("\n");
+ }
+#endif
+
+ microtime(&event.timestamp);
+
+ adb_processevent(&event);
+}
+
+void
+adb_mm_nonemp_complete(buffer, data_area, adb_command)
+ caddr_t buffer;
+ caddr_t data_area;
+ int adb_command;
+{
+ adb_event_t event;
+ ADBDataBlock adbdata;
+ int adbaddr;
+ int error;
+
+#ifdef ADB_DEBUG
+ int i;
+
+ if (adb_debug)
+ printf("adb: transaction completion\n");
+#endif
+
+ adbaddr = (adb_command & 0xf0) >> 4;
+ error = GetADBInfo(&adbdata, adbaddr);
+#ifdef ADB_DEBUG
+ if (adb_debug)
+ printf("adb: GetADBInfo returned %d\n", error);
+#endif
+
+#if 0
+ printf("adb: from %d at %d (org %d) %d:", event.addr,
+ event.hand_id, event.def_addr, buffer[0]);
+ for (i = 1; i <= buffer[0]; i++)
+ printf(" %x", buffer[i]);
+ printf("\n");
+#endif
+
+ /* massage the data to look like EMP data */
+ if ((buffer[3] & 0x04) == 0x04)
+ buffer[1] &= 0x7f;
+ else
+ buffer[1] |= 0x80;
+ if ((buffer[3] & 0x02) == 0x02)
+ buffer[2] &= 0x7f;
+ else
+ buffer[2] |= 0x80;
+ if ((buffer[3] & 0x01) == 0x01)
+ buffer[3] = 0x00;
+ else
+ buffer[3] = 0x80;
+
+ event.addr = adbaddr;
+ event.hand_id = adbdata.devType;
+ event.def_addr = adbdata.origADBAddr;
+ event.byte_count = buffer[0];
+ memcpy(event.bytes, buffer + 1, event.byte_count);
+
+#ifdef ADB_DEBUG
+ if (adb_debug) {
+ printf("adb: from %d at %d (org %d) %d:", event.addr,
+ event.hand_id, event.def_addr, buffer[0]);
+ for (i = 1; i <= buffer[0]; i++)
+ printf(" %x", buffer[i]);
+ printf("\n");
+ }
+#endif
+
+ microtime(&event.timestamp);
+
+ adb_processevent(&event);
+}
+
+static volatile int extdms_done;
+
+/*
+ * initialize extended mouse - probes devices as
+ * described in _Inside Macintosh, Devices_.
+ */
+void
+extdms_init(totaladbs)
+ int totaladbs;
+{
+ ADBDataBlock adbdata;
+ int adbindex, adbaddr, count;
+ short cmd;
+ u_char buffer[9];
+
+ for (adbindex = 1; adbindex <= totaladbs; adbindex++) {
+ /* Get the ADB information */
+ adbaddr = GetIndADB(&adbdata, adbindex);
+ if (adbdata.origADBAddr == ADBADDR_MS &&
+ (adbdata.devType == ADBMS_USPEED)) {
+ /* Found MicroSpeed Mouse Deluxe Mac */
+ cmd = ((adbaddr<<4)&0xF0)|0x9; /* listen 1 */
+
+ /*
+ * To setup the MicroSpeed, it appears that we can
+ * send the following command to the mouse and then
+ * expect data back in the form:
+ * buffer[0] = 4 (bytes)
+ * buffer[1], buffer[2] as std. mouse
+ * buffer[3] = buffer[4] = 0xff when no buttons
+ * are down. When button N down, bit N is clear.
+ * buffer[4]'s locking mask enables a
+ * click to toggle the button down state--sort of
+ * like the "Easy Access" shift/control/etc. keys.
+ * buffer[3]'s alternative speed mask enables using
+ * different speed when the corr. button is down
+ */
+ buffer[0] = 4;
+ buffer[1] = 0x00; /* Alternative speed */
+ buffer[2] = 0x00; /* speed = maximum */
+ buffer[3] = 0x10; /* enable extended protocol,
+ * lower bits = alt. speed mask
+ * = 0000b
+ */
+ buffer[4] = 0x07; /* Locking mask = 0000b,
+ * enable buttons = 0111b
+ */
+ extdms_done = 0;
+ ADBOp((Ptr)buffer, (Ptr)extdms_complete,
+ (Ptr)&extdms_done, cmd);
+ while (!extdms_done)
+ /* busy wait until done */;
+ }
+ if (adbdata.origADBAddr == ADBADDR_MS &&
+ (adbdata.devType == ADBMS_100DPI ||
+ adbdata.devType == ADBMS_200DPI)) {
+ /* found a mouse */
+ cmd = ((adbaddr << 4) & 0xf0) | 0x3;
+
+ extdms_done = 0;
+ cmd = (cmd & 0xf3) | 0x0c; /* talk command */
+ ADBOp((Ptr)buffer, (Ptr)extdms_complete,
+ (Ptr)&extdms_done, cmd);
+
+ /* Wait until done, but no more than 2 secs */
+ count = 40000;
+ while (!extdms_done && count-- > 0)
+ delay(50);
+
+ if (!extdms_done) {
+#ifdef ADB_DEBUG
+ if (adb_debug)
+ printf("adb: extdms_init timed out\n");
+#endif
+ return;
+ }
+
+ DELAY(1000);
+
+ /* Attempt to initialize Extended Mouse Protocol */
+ buffer[2] = '\004'; /* make handler ID 4 */
+ extdms_done = 0;
+ cmd = (cmd & 0xf3) | 0x08; /* listen command */
+ ADBOp((Ptr)buffer, (Ptr)extdms_complete,
+ (Ptr)&extdms_done, cmd);
+ while (!extdms_done)
+ /* busy wait until done */;
+
+ /*
+ * Check to see if successful, if not
+ * try to initialize it as other types
+ */
+ cmd = ((adbaddr << 4) & 0xf0) | 0x3;
+ extdms_done = 0;
+ cmd = (cmd & 0xf3) | 0x0c; /* talk command */
+ ADBOp((Ptr)buffer, (Ptr)extdms_complete,
+ (Ptr)&extdms_done, cmd);
+ while (!extdms_done)
+ /* busy wait until done */;
+
+ if (buffer[2] != ADBMS_EXTENDED) {
+ /* Attempt to initialize as an A3 mouse */
+ buffer[2] = 0x03; /* make handler ID 3 */
+ extdms_done = 0;
+ cmd = (cmd & 0xf3) | 0x08; /* listen command */
+ ADBOp((Ptr)buffer, (Ptr)extdms_complete,
+ (Ptr)&extdms_done, cmd);
+ while (!extdms_done)
+ /* busy wait until done */;
+
+ /*
+ * Check to see if successful, if not
+ * try to initialize it as other types
+ */
+ cmd = ((adbaddr << 4) & 0xf0) | 0x3;
+ extdms_done = 0;
+ cmd = (cmd & 0xf3) | 0x0c; /* talk command */
+ ADBOp((Ptr)buffer, (Ptr)extdms_complete,
+ (Ptr)&extdms_done, cmd);
+ while (!extdms_done)
+ /* busy wait until done */;
+
+ if (buffer[2] == ADBMS_MSA3) {
+ /* Initialize as above */
+ cmd = ((adbaddr << 4) & 0xF0) | 0xA;
+ /* listen 2 */
+ buffer[0] = 3;
+ buffer[1] = 0x00;
+ /* Irrelevant, buffer has 0x77 */
+ buffer[2] = 0x07;
+ /*
+ * enable 3 button mode = 0111b,
+ * speed = normal
+ */
+ extdms_done = 0;
+ ADBOp((Ptr)buffer, (Ptr)extdms_complete,
+ (Ptr)&extdms_done, cmd);
+ while (!extdms_done)
+ /* busy wait until done */;
+ } else {
+ /* No special support for this mouse */
+ }
+ }
+ }
+ }
+}
+
+void
+adb_init()
+{
+ ADBDataBlock adbdata;
+ ADBSetInfoBlock adbinfo;
+ int totaladbs;
+ int adbindex, adbaddr;
+ int error, cmd, count, devtype = 0;
+ u_char buffer[9];
+ extern int adb_initted;
+
+ ADBReInit();
+
+#ifdef ADB_DEBUG
+ if (adb_debug)
+ printf("adb: done with ADBReInit\n");
+#endif
+
+ totaladbs = CountADBs();
+ extdms_init(totaladbs);
+
+ /* for each ADB device */
+ for (adbindex = 1; adbindex <= totaladbs; adbindex++) {
+ /* Get the ADB information */
+ adbaddr = GetIndADB(&adbdata, adbindex);
+
+ /* Print out the glory */
+ printf("adb: ");
+ switch (adbdata.origADBAddr) {
+ case ADBADDR_SECURE:
+ printf("security dongle (%d)", adbdata.devType);
+ break;
+ case ADBADDR_MAP:
+ switch (adbdata.devType) {
+ case ADB_STDKBD:
+ printf("standard keyboard");
+ break;
+ case ADB_ISOKBD:
+ printf("standard keyboard (ISO layout)");
+ break;
+ case ADB_EXTKBD:
+ extdms_done = 0;
+ /* talk R1 */
+ cmd = (((adbaddr << 4) & 0xf0) | 0x0d );
+ ADBOp((Ptr)buffer, (Ptr)extdms_complete,
+ (Ptr)&extdms_done, cmd);
+
+ /* Wait until done, but no more than 2 secs */
+ count = 40000;
+ while (!extdms_done && count-- > 0)
+ delay(50);
+
+ if (extdms_done &&
+ buffer[1] == 0x9a && buffer[2] == 0x20)
+ printf("Mouseman (non-EMP) pseudo keyboard");
+ else
+ printf("extended keyboard");
+ break;
+ case ADB_EXTISOKBD:
+ printf("extended keyboard (ISO layout)");
+ break;
+ case ADB_KBDII:
+ printf("keyboard II");
+ break;
+ case ADB_ISOKBDII:
+ printf("keyboard II (ISO layout)");
+ break;
+ case ADB_PBKBD:
+ printf("PowerBook keyboard");
+ break;
+ case ADB_PBISOKBD:
+ printf("PowerBook keyboard (ISO layout)");
+ break;
+ case ADB_ADJKPD:
+ printf("adjustable keypad");
+ break;
+ case ADB_ADJKBD:
+ printf("adjustable keyboard");
+ break;
+ case ADB_ADJISOKBD:
+ printf("adjustable keyboard (ISO layout)");
+ break;
+ case ADB_ADJJAPKBD:
+ printf("adjustable keyboard (Japanese layout)");
+ break;
+ case ADB_PBEXTISOKBD:
+ printf("PowerBook extended keyboard (ISO layout)");
+ break;
+ case ADB_PBEXTJAPKBD:
+ printf("PowerBook extended keyboard (Japanese layout)");
+ break;
+ case ADB_JISKBDII:
+ printf("keyboard II (JIS)");
+ break;
+ case ADB_PBEXTKBD:
+ printf("PowerBook extended keyboard");
+ break;
+ case ADB_DESIGNKBD:
+ printf("extended keyboard");
+ break;
+ default:
+ printf("mapped device (%d)", adbdata.devType);
+ break;
+ }
+ break;
+ case ADBADDR_REL:
+ extdms_done = 0;
+ /* talk register 3 */
+ ADBOp((Ptr)buffer, (Ptr)extdms_complete,
+ (Ptr)&extdms_done, (adbaddr << 4) | 0xf);
+
+ /* Wait until done, but no more than 2 secs */
+ count = 40000;
+ while (!extdms_done && count-- > 0)
+ delay(50);
+
+ DELAY(1000);
+
+ if (!extdms_done) {
+ printf("ghost mouse?");
+ break;
+ }
+
+ devtype = buffer[2];
+ switch (devtype) {
+ case ADBMS_100DPI:
+ printf("100 dpi mouse");
+ break;
+ case ADBMS_200DPI:
+ printf("200 dpi mouse");
+ break;
+ case ADBMS_MSA3:
+ printf("Mouse Systems A3 mouse, default parameters");
+ break;
+ case ADBMS_USPEED:
+ printf("MicroSpeed mouse, default parameters");
+ break;
+ case ADBMS_EXTENDED:
+ extdms_done = 0;
+ /* talk register 1 */
+ ADBOp((Ptr)buffer, (Ptr)extdms_complete,
+ (Ptr)&extdms_done, (adbaddr << 4) | 0xd);
+ while (!extdms_done)
+ /* busy-wait until done */;
+ if (buffer[1] == 0x9a && buffer[2] == 0x20)
+ printf("Mouseman (non-EMP) mouse");
+ else {
+ printf("extended mouse <%c%c%c%c> "
+ "%d-button %d dpi ",
+ buffer[1], buffer[2],
+ buffer[3], buffer[4],
+ (int)buffer[8],
+ (int)*(short *)&buffer[5]);
+ if (buffer[7] == 1)
+ printf("mouse");
+ else if (buffer[7] == 2)
+ printf("trackball");
+ else
+ printf("unknown device");
+ }
+ break;
+ default:
+ printf("relative positioning device (mouse?) "
+ "(%d)", adbdata.devType);
+ break;
+ }
+ break;
+ case ADBADDR_ABS:
+ switch (adbdata.devType) {
+ case ADB_ARTPAD:
+ printf("WACOM ArtPad II");
+ break;
+ default:
+ printf("abs. pos. device (tablet?) (%d)",
+ adbdata.devType);
+ break;
+ }
+ break;
+ case ADBADDR_DATATX:
+ printf("data transfer device (modem?) (%d)",
+ adbdata.devType);
+ break;
+ case ADBADDR_MISC:
+ switch (adbdata.devType) {
+ case ADB_POWERKEY:
+ printf("Sophisticated Circuits PowerKey");
+ break;
+ default:
+ printf("misc. device (remote control?) (%d)",
+ adbdata.devType);
+ break;
+ }
+ break;
+ default:
+ printf("unknown type device, (def %d, handler %d)",
+ adbdata.origADBAddr, adbdata.devType);
+ break;
+ }
+ printf(" at %d\n", adbaddr);
+
+ /* Set completion routine to be NetBSD's */
+ if ((adbdata.origADBAddr == ADBADDR_REL) &&
+ (buffer[0] > 0) && (buffer[2] == ADBMS_MSA3)) {
+ /* Special device handler for the A3 mouse */
+ adbinfo.siServiceRtPtr = (Ptr)adb_msa3_complete;
+ } else if ((adbdata.origADBAddr == ADBADDR_MAP) &&
+ (adbdata.devType == ADB_EXTKBD) &&
+ (buffer[1] == 0x9a) && (buffer[2] == 0x20)) {
+ /* ignore non-EMP Mouseman pseudo keyboard */
+ adbinfo.siServiceRtPtr = (Ptr)0;
+ } else if ((adbdata.origADBAddr == ADBADDR_REL) &&
+ (devtype == ADBMS_EXTENDED) &&
+ (buffer[1] == 0x9a) && (buffer[2] == 0x20)) {
+ /*
+ * Set up non-EMP Mouseman to put button
+ * bits in 3rd byte instead of sending via
+ * pseudo keyboard device.
+ */
+ extdms_done = 0;
+ /* listen register 1 */
+ buffer[0] = 2;
+ buffer[1] = 0x00;
+ buffer[2] = 0x81;
+ ADBOp((Ptr)buffer, (Ptr)extdms_complete,
+ (Ptr)&extdms_done, (adbaddr << 4) | 0x9);
+ while (!extdms_done)
+ /* busy-wait until done */;
+ extdms_done = 0;
+ /* listen register 1 */
+ buffer[0] = 2;
+ buffer[1] = 0x01;
+ buffer[2] = 0x81;
+ ADBOp((Ptr)buffer, (Ptr)extdms_complete,
+ (Ptr)&extdms_done, (adbaddr << 4) | 0x9);
+ while (!extdms_done)
+ /* busy-wait until done */;
+ extdms_done = 0;
+ /* listen register 1 */
+ buffer[0] = 2;
+ buffer[1] = 0x02;
+ buffer[2] = 0x81;
+ ADBOp((Ptr)buffer, (Ptr)extdms_complete,
+ (Ptr)&extdms_done, (adbaddr << 4) | 0x9);
+ while (!extdms_done)
+ /* busy-wait until done */;
+ extdms_done = 0;
+ /* listen register 1 */
+ buffer[0] = 2;
+ buffer[1] = 0x03;
+ buffer[2] = 0x38;
+ ADBOp((Ptr)buffer, (Ptr)extdms_complete,
+ (Ptr)&extdms_done, (adbaddr << 4) | 0x9);
+ while (!extdms_done)
+ /* busy-wait until done */;
+ /* non-EMP Mouseman has special handler */
+ adbinfo.siServiceRtPtr = (Ptr)adb_mm_nonemp_complete;
+ } else {
+ /* Default completion routine */
+ adbinfo.siServiceRtPtr = (Ptr)adb_complete;
+ }
+ adbinfo.siDataAreaAddr = NULL;
+ error = SetADBInfo(&adbinfo, adbaddr);
+#ifdef ADB_DEBUG
+ if (adb_debug)
+ printf("adb: returned %d from SetADBInfo\n", error);
+#endif
+ }
+
+ adb_initted = 1;
+}
+
+
+void
+extdms_complete(buffer, compdata, cmd)
+ caddr_t buffer, compdata;
+ int cmd;
+{
+ long *p = (long *)compdata;
+
+ *p= -1;
+}
diff --git a/sys/arch/macppc/dev/adbvar.h b/sys/arch/macppc/dev/adbvar.h
new file mode 100644
index 00000000000..b4aa265f0b3
--- /dev/null
+++ b/sys/arch/macppc/dev/adbvar.h
@@ -0,0 +1,114 @@
+/* $NetBSD: adbvar.h,v 1.1 1998/05/15 10:15:47 tsubai Exp $ */
+
+/*-
+ * Copyright (C) 1994 Bradley A. Grantham
+ * 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 Bradley A. Grantham.
+ * 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 <machine/adbsys.h>
+
+#define ADB_MAXTRACE (NBPG / sizeof(int) - 1)
+extern int adb_traceq[ADB_MAXTRACE];
+extern int adb_traceq_tail;
+extern int adb_traceq_len;
+
+typedef struct adb_trace_xlate_s {
+ int params;
+ char *string;
+} adb_trace_xlate_t;
+
+extern adb_trace_xlate_t adb_trace_xlations[];
+
+#ifdef DEBUG
+#ifndef ADB_DEBUG
+#define ADB_DEBUG
+#endif
+extern int adb_debug;
+#endif
+
+typedef caddr_t Ptr;
+typedef caddr_t *Handle;
+
+/* ADB Manager */
+typedef struct {
+ Ptr siServiceRtPtr;
+ Ptr siDataAreaAddr;
+} ADBSetInfoBlock;
+typedef struct {
+ unsigned char devType;
+ unsigned char origADBAddr;
+ Ptr dbServiceRtPtr;
+ Ptr dbDataAreaAddr;
+} ADBDataBlock;
+
+struct adb_softc {
+ struct device sc_dev;
+ char *sc_regbase;
+};
+
+
+/* adb.c */
+void adb_enqevent __P((adb_event_t *event));
+void adb_handoff __P((adb_event_t *event));
+void adb_autorepeat __P((void *keyp));
+void adb_dokeyupdown __P((adb_event_t *event));
+void adb_keymaybemouse __P((adb_event_t *event));
+void adb_processevent __P((adb_event_t *event));
+int adbopen __P((dev_t dev, int flag, int mode, struct proc *p));
+int adbclose __P((dev_t dev, int flag, int mode, struct proc *p));
+int adbread __P((dev_t dev, struct uio *uio, int flag));
+int adbwrite __P((dev_t dev, struct uio *uio, int flag));
+int adbioctl __P((dev_t , int , caddr_t , int , struct proc *));
+int adbpoll __P((dev_t dev, int events, struct proc *p));
+
+/* adbsys.c */
+void adb_complete __P((caddr_t buffer, caddr_t data_area, int adb_command));
+void adb_msa3_complete __P((caddr_t buffer, caddr_t data_area, int adb_command));
+void adb_mm_nonemp_complete __P((caddr_t buffer, caddr_t data_area, int adb_command));
+void extdms_init __P((int));
+void extdms_complete __P((caddr_t, caddr_t, int));
+
+#ifndef MRG_ADB
+/* types of adb hardware that we (will eventually) support */
+#define ADB_HW_UNKNOWN 0x01 /* don't know */
+#define ADB_HW_II 0x02 /* Mac II series */
+#define ADB_HW_IISI 0x03 /* Mac IIsi series */
+#define ADB_HW_PB 0x04 /* PowerBook series */
+#define ADB_HW_CUDA 0x05 /* Machines with a Cuda chip */
+
+/* adb_direct.c */
+int adb_poweroff __P((void));
+int CountADBs __P((void));
+void ADBReInit __P((void));
+int GetIndADB __P((ADBDataBlock * info, int index));
+int GetADBInfo __P((ADBDataBlock * info, int adbAddr));
+int SetADBInfo __P((ADBSetInfoBlock * info, int adbAddr));
+int ADBOp __P((Ptr buffer, Ptr compRout, Ptr data, short commandNum));
+int adb_read_date_time __P((unsigned long *t));
+int adb_set_date_time __P((unsigned long t));
+#endif /* !MRG_ADB */
diff --git a/sys/arch/macppc/dev/am79c950.c b/sys/arch/macppc/dev/am79c950.c
new file mode 100644
index 00000000000..27c35551a72
--- /dev/null
+++ b/sys/arch/macppc/dev/am79c950.c
@@ -0,0 +1,820 @@
+/* $NetBSD: am79c950.c,v 1.1 1998/05/15 10:15:47 tsubai Exp $ */
+
+/*-
+ * Copyright (c) 1997 David Huang <khym@bga.com>
+ * All rights reserved.
+ *
+ * Portions of this code are based on code by Denton Gentry <denny1@home.com>,
+ * Charles M. Hannum, Yanagisawa Takeshi <yanagisw@aa.ap.titech.ac.jp>, and
+ * Jason R. Thorpe.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/*
+ * Driver for the AMD Am79C940 (MACE) ethernet chip, used for onboard
+ * ethernet on the Centris/Quadra 660av and Quadra 840av.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/buf.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/syslog.h>
+#include <sys/ioctl.h>
+#include <sys/errno.h>
+#include <sys/device.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_ether.h>
+#include <net/if_media.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/if_inarp.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#endif
+
+#ifdef NS
+#include <netns/ns.h>
+#include <netns/ns_if.h>
+#endif
+
+#if defined(CCITT) && defined(LLC)
+#include <sys/socketvar.h>
+#include <netccitt/x25.h>
+#include <netccitt/pk.h>
+#include <netccitt/pk_var.h>
+#include <netccitt/pk_extern.h>
+#endif
+
+#include <vm/vm.h>
+
+#include "bpfilter.h"
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#include <net/bpfdesc.h>
+#endif
+
+#include <machine/pio.h>
+#include <machine/bus.h>
+
+#include <macppc/dev/am79c950reg.h>
+#include <macppc/dev/if_mcvar.h>
+
+hide void mcwatchdog __P((struct ifnet *));
+hide int mcinit __P((struct mc_softc *sc));
+hide int mcstop __P((struct mc_softc *sc));
+hide int mcioctl __P((struct ifnet *ifp, u_long cmd, caddr_t data));
+hide void mcstart __P((struct ifnet *ifp));
+hide void mcreset __P((struct mc_softc *sc));
+
+integrate u_int maceput __P((struct mc_softc *sc, struct mbuf *m0));
+integrate void mc_tint __P((struct mc_softc *sc));
+integrate void mace_read __P((struct mc_softc *, caddr_t, int));
+integrate struct mbuf *mace_get __P((struct mc_softc *, caddr_t, int));
+static void mace_calcladrf __P((struct ethercom *ac, u_int8_t *af));
+static inline u_int16_t ether_cmp __P((void *, void *));
+static int mc_mediachange __P((struct ifnet *));
+static void mc_mediastatus __P((struct ifnet *, struct ifmediareq *));
+
+/*
+ * Compare two Ether/802 addresses for equality, inlined and
+ * unrolled for speed. Use this like bcmp().
+ *
+ * XXX: Add <machine/inlines.h> for stuff like this?
+ * XXX: or maybe add it to libkern.h instead?
+ *
+ * "I'd love to have an inline assembler version of this."
+ * XXX: Who wanted that? mycroft? I wrote one, but this
+ * version in C is as good as hand-coded assembly. -gwr
+ *
+ * Please do NOT tweak this without looking at the actual
+ * assembly code generated before and after your tweaks!
+ */
+static inline u_int16_t
+ether_cmp(one, two)
+ void *one, *two;
+{
+ register u_int16_t *a = (u_short *) one;
+ register u_int16_t *b = (u_short *) two;
+ register u_int16_t diff;
+
+#ifdef m68k
+ /*
+ * The post-increment-pointer form produces the best
+ * machine code for m68k. This was carefully tuned
+ * so it compiles to just 8 short (2-byte) op-codes!
+ */
+ diff = *a++ - *b++;
+ diff |= *a++ - *b++;
+ diff |= *a++ - *b++;
+#else
+ /*
+ * Most modern CPUs do better with a single expresion.
+ * Note that short-cut evaluation is NOT helpful here,
+ * because it just makes the code longer, not faster!
+ */
+ diff = (a[0] - b[0]) | (a[1] - b[1]) | (a[2] - b[2]);
+#endif
+
+ return (diff);
+}
+
+#define ETHER_CMP ether_cmp
+
+/*
+ * Interface exists: make available by filling in network interface
+ * record. System will initialize the interface when it is ready
+ * to accept packets.
+ */
+int
+mcsetup(sc, lladdr)
+ struct mc_softc *sc;
+ u_int8_t *lladdr;
+{
+ struct ifnet *ifp = &sc->sc_if;
+
+ /* reset the chip and disable all interrupts */
+ NIC_PUT(sc, MACE_BIUCC, SWRST);
+ DELAY(100);
+ NIC_PUT(sc, MACE_IMR, ~0);
+
+ bcopy(lladdr, sc->sc_enaddr, ETHER_ADDR_LEN);
+ printf(": address %s\n", ether_sprintf(lladdr));
+
+ bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
+ ifp->if_softc = sc;
+ ifp->if_ioctl = mcioctl;
+ ifp->if_start = mcstart;
+ ifp->if_flags =
+ IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST;
+ ifp->if_watchdog = mcwatchdog;
+
+#if NBPFILTER > 0
+ bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
+#endif
+
+ /* initialize ifmedia structures */
+ ifmedia_init(&sc->sc_media, 0, mc_mediachange, mc_mediastatus);
+ ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_MANUAL, 0, NULL);
+ ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_MANUAL);
+
+ if_attach(ifp);
+ ether_ifattach(ifp, lladdr);
+
+ return (0);
+}
+
+hide int
+mcioctl(ifp, cmd, data)
+ struct ifnet *ifp;
+ u_long cmd;
+ caddr_t data;
+{
+ struct mc_softc *sc = ifp->if_softc;
+ struct ifaddr *ifa;
+ struct ifreq *ifr;
+
+ int s = splnet(), err = 0;
+ int temp;
+
+ switch (cmd) {
+
+ case SIOCSIFADDR:
+ ifa = (struct ifaddr *)data;
+ ifp->if_flags |= IFF_UP;
+ switch (ifa->ifa_addr->sa_family) {
+#ifdef INET
+ case AF_INET:
+ mcinit(sc);
+ arp_ifinit(ifp, ifa);
+ break;
+#endif
+#ifdef NS
+ case AF_NS:
+ {
+ register struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
+
+ if (ns_nullhost(*ina))
+ ina->x_host =
+ *(union ns_host *)LLADDR(ifp->if_sadl);
+ else {
+ bcopy(ina->x_host.c_host,
+ LLADDR(ifp->if_sadl),
+ sizeof(sc->sc_enaddr));
+ }
+ /* Set new address. */
+ mcinit(sc);
+ break;
+ }
+#endif
+ default:
+ mcinit(sc);
+ break;
+ }
+ break;
+
+ case SIOCSIFFLAGS:
+ if ((ifp->if_flags & IFF_UP) == 0 &&
+ (ifp->if_flags & IFF_RUNNING) != 0) {
+ /*
+ * If interface is marked down and it is running,
+ * then stop it.
+ */
+ mcstop(sc);
+ ifp->if_flags &= ~IFF_RUNNING;
+ } else if ((ifp->if_flags & IFF_UP) != 0 &&
+ (ifp->if_flags & IFF_RUNNING) == 0) {
+ /*
+ * If interface is marked up and it is stopped,
+ * then start it.
+ */
+ (void)mcinit(sc);
+ } else {
+ /*
+ * reset the interface to pick up any other changes
+ * in flags
+ */
+ temp = ifp->if_flags & IFF_UP;
+ mcreset(sc);
+ ifp->if_flags |= temp;
+ mcstart(ifp);
+ }
+ break;
+
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ ifr = (struct ifreq *) data;
+ err = (cmd == SIOCADDMULTI) ?
+ ether_addmulti(ifr, &sc->sc_ethercom) :
+ ether_delmulti(ifr, &sc->sc_ethercom);
+
+ if (err == ENETRESET) {
+ /*
+ * Multicast list has changed; set the hardware
+ * filter accordingly. But remember UP flag!
+ */
+ temp = ifp->if_flags & IFF_UP;
+ mcreset(sc);
+ ifp->if_flags |= temp;
+ err = 0;
+ }
+ break;
+
+ case SIOCGIFMEDIA:
+ case SIOCSIFMEDIA:
+ ifr = (struct ifreq *) data;
+ err = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
+ break;
+
+ default:
+ err = EINVAL;
+ }
+ splx(s);
+ return (err);
+}
+
+/*
+ * Encapsulate a packet of type family for the local net.
+ */
+hide void
+mcstart(ifp)
+ struct ifnet *ifp;
+{
+ struct mc_softc *sc = ifp->if_softc;
+ struct mbuf *m;
+
+ if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
+ return;
+
+ while (1) {
+ if (ifp->if_flags & IFF_OACTIVE)
+ return;
+
+ IF_DEQUEUE(&ifp->if_snd, m);
+ if (m == 0)
+ return;
+
+#if NBPFILTER > 0
+ /*
+ * If bpf is listening on this interface, let it
+ * see the packet before we commit it to the wire.
+ */
+ if (ifp->if_bpf)
+ bpf_mtap(ifp->if_bpf, m);
+#endif
+
+ /*
+ * Copy the mbuf chain into the transmit buffer.
+ */
+ ifp->if_flags |= IFF_OACTIVE;
+ maceput(sc, m);
+
+ ifp->if_opackets++; /* # of pkts */
+ }
+}
+
+/*
+ * reset and restart the MACE. Called in case of fatal
+ * hardware/software errors.
+ */
+hide void
+mcreset(sc)
+ struct mc_softc *sc;
+{
+ mcstop(sc);
+ mcinit(sc);
+}
+
+hide int
+mcinit(sc)
+ struct mc_softc *sc;
+{
+ int s;
+ u_int8_t maccc, ladrf[8];
+
+ if (sc->sc_if.if_flags & IFF_RUNNING)
+ /* already running */
+ return (0);
+
+ s = splnet();
+
+ NIC_PUT(sc, MACE_BIUCC, sc->sc_biucc);
+ NIC_PUT(sc, MACE_FIFOCC, sc->sc_fifocc);
+ NIC_PUT(sc, MACE_IMR, ~0); /* disable all interrupts */
+ NIC_PUT(sc, MACE_PLSCC, sc->sc_plscc);
+
+ NIC_PUT(sc, MACE_UTR, RTRD); /* disable reserved test registers */
+
+ /* set MAC address */
+ NIC_PUT(sc, MACE_IAC, ADDRCHG);
+ while (NIC_GET(sc, MACE_IAC) & ADDRCHG)
+ ;
+ NIC_PUT(sc, MACE_IAC, PHYADDR);
+ bus_space_write_multi_1(sc->sc_regt, sc->sc_regh, MACE_REG(MACE_PADR),
+ sc->sc_enaddr, ETHER_ADDR_LEN);
+
+ /* set logical address filter */
+ mace_calcladrf(&sc->sc_ethercom, ladrf);
+
+ NIC_PUT(sc, MACE_IAC, ADDRCHG);
+ while (NIC_GET(sc, MACE_IAC) & ADDRCHG)
+ ;
+ NIC_PUT(sc, MACE_IAC, LOGADDR);
+ bus_space_write_multi_1(sc->sc_regt, sc->sc_regh, MACE_REG(MACE_LADRF),
+ ladrf, 8);
+
+ NIC_PUT(sc, MACE_XMTFC, APADXMT);
+ /*
+ * No need to autostrip padding on receive... Ethernet frames
+ * don't have a length field, unlike 802.3 frames, so the MACE
+ * can't figure out the length of the packet anyways.
+ */
+ NIC_PUT(sc, MACE_RCVFC, 0);
+
+ maccc = ENXMT | ENRCV;
+ if (sc->sc_if.if_flags & IFF_PROMISC)
+ maccc |= PROM;
+
+ NIC_PUT(sc, MACE_MACCC, maccc);
+
+ if (sc->sc_bus_init)
+ (*sc->sc_bus_init)(sc);
+
+ /*
+ * Enable all interrupts except receive, since we use the DMA
+ * completion interrupt for that.
+ */
+ NIC_PUT(sc, MACE_IMR, RCVINTM);
+
+ /* flag interface as "running" */
+ sc->sc_if.if_flags |= IFF_RUNNING;
+ sc->sc_if.if_flags &= ~IFF_OACTIVE;
+
+ splx(s);
+ return (0);
+}
+
+/*
+ * close down an interface and free its buffers
+ * Called on final close of device, or if mcinit() fails
+ * part way through.
+ */
+hide int
+mcstop(sc)
+ struct mc_softc *sc;
+{
+ int s = splnet();
+
+ NIC_PUT(sc, MACE_BIUCC, SWRST);
+ DELAY(100);
+
+ sc->sc_if.if_timer = 0;
+ sc->sc_if.if_flags &= ~(IFF_RUNNING | IFF_UP);
+
+ splx(s);
+ return (0);
+}
+
+/*
+ * Called if any Tx packets remain unsent after 5 seconds,
+ * In all cases we just reset the chip, and any retransmission
+ * will be handled by higher level protocol timeouts.
+ */
+hide void
+mcwatchdog(ifp)
+ struct ifnet *ifp;
+{
+ struct mc_softc *sc = ifp->if_softc;
+ int temp;
+
+ printf("mcwatchdog: resetting chip\n");
+ temp = ifp->if_flags & IFF_UP;
+ mcreset(sc);
+ ifp->if_flags |= temp;
+}
+
+/*
+ * stuff packet into MACE (at splnet)
+ */
+integrate u_int
+maceput(sc, m)
+ struct mc_softc *sc;
+ struct mbuf *m;
+{
+ struct mbuf *n;
+ u_int len, totlen = 0;
+ u_char *buff;
+
+ buff = sc->sc_txbuf;
+
+ for (; m; m = n) {
+ u_char *data = mtod(m, u_char *);
+ len = m->m_len;
+ totlen += len;
+ bcopy(data, buff, len);
+ buff += len;
+ MFREE(m, n);
+ }
+
+ if (totlen > NBPG)
+ panic("%s: maceput: packet overflow", sc->sc_dev.dv_xname);
+
+#if 0
+ if (totlen < ETHERMIN + sizeof(struct ether_header)) {
+ int pad = ETHERMIN + sizeof(struct ether_header) - totlen;
+ bzero(sc->sc_txbuf + totlen, pad);
+ totlen = ETHERMIN + sizeof(struct ether_header);
+ }
+#endif
+
+ (*sc->sc_putpacket)(sc, totlen);
+
+ sc->sc_if.if_timer = 5; /* 5 seconds to watch for failing to transmit */
+ return (totlen);
+}
+
+void
+mcintr(arg)
+ void *arg;
+{
+ struct mc_softc *sc = arg;
+ u_int8_t ir;
+
+ ir = NIC_GET(sc, MACE_IR) & ~NIC_GET(sc, MACE_IMR);
+ if (ir & JAB) {
+#ifdef MCDEBUG
+ printf("%s: jabber error\n", sc->sc_dev.dv_xname);
+#endif
+ sc->sc_if.if_oerrors++;
+ }
+
+ if (ir & BABL) {
+#ifdef MCDEBUG
+ printf("%s: babble\n", sc->sc_dev.dv_xname);
+#endif
+ sc->sc_if.if_oerrors++;
+ }
+
+ if (ir & CERR) {
+ printf("%s: collision error\n", sc->sc_dev.dv_xname);
+ sc->sc_if.if_collisions++;
+ }
+
+ /*
+ * Pretend we have carrier; if we don't this will be cleared
+ * shortly.
+ */
+ sc->sc_havecarrier = 1;
+
+ if (ir & XMTINT)
+ mc_tint(sc);
+
+ if (ir & RCVINT)
+ mc_rint(sc);
+}
+
+integrate void
+mc_tint(sc)
+ struct mc_softc *sc;
+{
+ u_int8_t xmtrc, xmtfs;
+
+ xmtrc = NIC_GET(sc, MACE_XMTRC);
+ xmtfs = NIC_GET(sc, MACE_XMTFS);
+
+ if ((xmtfs & XMTSV) == 0)
+ return;
+
+ if (xmtfs & UFLO) {
+ printf("%s: underflow\n", sc->sc_dev.dv_xname);
+ mcreset(sc);
+ return;
+ }
+
+ if (xmtfs & LCOL) {
+ printf("%s: late collision\n", sc->sc_dev.dv_xname);
+ sc->sc_if.if_oerrors++;
+ sc->sc_if.if_collisions++;
+ }
+
+ if (xmtfs & MORE)
+ /* Real number is unknown. */
+ sc->sc_if.if_collisions += 2;
+ else if (xmtfs & ONE)
+ sc->sc_if.if_collisions++;
+ else if (xmtfs & RTRY) {
+ sc->sc_if.if_collisions += 16;
+ sc->sc_if.if_oerrors++;
+ }
+
+ if (xmtfs & LCAR) {
+ sc->sc_havecarrier = 0;
+ printf("%s: lost carrier\n", sc->sc_dev.dv_xname);
+ sc->sc_if.if_oerrors++;
+ }
+
+ sc->sc_if.if_flags &= ~IFF_OACTIVE;
+ sc->sc_if.if_timer = 0;
+ mcstart(&sc->sc_if);
+}
+
+void
+mc_rint(sc)
+ struct mc_softc *sc;
+{
+#define rxf sc->sc_rxframe
+ u_int len;
+
+ len = (rxf.rx_rcvcnt | ((rxf.rx_rcvsts & 0xf) << 8)) - 4;
+
+#ifdef MCDEBUG
+ if (rxf.rx_rcvsts & 0xf0)
+ printf("%s: rcvcnt %02x rcvsts %02x rntpc 0x%02x rcvcc 0x%02x\n",
+ sc->sc_dev.dv_xname, rxf.rx_rcvcnt, rxf.rx_rcvsts,
+ rxf.rx_rntpc, rxf.rx_rcvcc);
+#endif
+
+ if (rxf.rx_rcvsts & OFLO) {
+ printf("%s: receive FIFO overflow\n", sc->sc_dev.dv_xname);
+ sc->sc_if.if_ierrors++;
+ return;
+ }
+
+ if (rxf.rx_rcvsts & CLSN)
+ sc->sc_if.if_collisions++;
+
+ if (rxf.rx_rcvsts & FRAM) {
+#ifdef MCDEBUG
+ printf("%s: framing error\n", sc->sc_dev.dv_xname);
+#endif
+ sc->sc_if.if_ierrors++;
+ return;
+ }
+
+ if (rxf.rx_rcvsts & FCS) {
+#ifdef MCDEBUG
+ printf("%s: frame control checksum error\n", sc->sc_dev.dv_xname);
+#endif
+ sc->sc_if.if_ierrors++;
+ return;
+ }
+
+ mace_read(sc, rxf.rx_frame, len);
+#undef rxf
+}
+
+integrate void
+mace_read(sc, pkt, len)
+ struct mc_softc *sc;
+ caddr_t pkt;
+ int len;
+{
+ struct ifnet *ifp = &sc->sc_if;
+ struct ether_header *eh = (struct ether_header *)pkt;
+ struct mbuf *m;
+
+ if (len <= sizeof(struct ether_header) ||
+ len > ETHERMTU + sizeof(struct ether_header)) {
+#ifdef MCDEBUG
+ printf("%s: invalid packet size %d; dropping\n",
+ sc->sc_dev.dv_xname, len);
+#endif
+ ifp->if_ierrors++;
+ return;
+ }
+
+#if NBPFILTER > 0
+ /*
+ * Check if there's a bpf filter listening on this interface.
+ * If so, hand off the raw packet to enet, then discard things
+ * not destined for us (but be sure to keep broadcast/multicast).
+ */
+ if (ifp->if_bpf) {
+ bpf_tap(ifp->if_bpf, pkt, len);
+ if ((ifp->if_flags & IFF_PROMISC) != 0 &&
+ (eh->ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */
+ ETHER_CMP(eh->ether_dhost, sc->sc_enaddr))
+ return;
+ }
+#endif
+ m = mace_get(sc, pkt, len);
+ if (m == NULL) {
+ ifp->if_ierrors++;
+ return;
+ }
+
+ ifp->if_ipackets++;
+
+ /* Pass the packet up, with the ether header sort-of removed. */
+ m_adj(m, sizeof(struct ether_header));
+ ether_input(ifp, eh, m);
+}
+
+/*
+ * Pull data off an interface.
+ * Len is length of data, with local net header stripped.
+ * We copy the data into mbufs. When full cluster sized units are present
+ * we copy into clusters.
+ */
+integrate struct mbuf *
+mace_get(sc, pkt, totlen)
+ struct mc_softc *sc;
+ caddr_t pkt;
+ int totlen;
+{
+ register struct mbuf *m;
+ struct mbuf *top, **mp;
+ int len;
+
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == 0)
+ return (0);
+ m->m_pkthdr.rcvif = &sc->sc_if;
+ m->m_pkthdr.len = totlen;
+ len = MHLEN;
+ top = 0;
+ mp = &top;
+
+ while (totlen > 0) {
+ if (top) {
+ MGET(m, M_DONTWAIT, MT_DATA);
+ if (m == 0) {
+ m_freem(top);
+ return 0;
+ }
+ len = MLEN;
+ }
+ if (totlen >= MINCLSIZE) {
+ MCLGET(m, M_DONTWAIT);
+ if ((m->m_flags & M_EXT) == 0) {
+ m_free(m);
+ m_freem(top);
+ return 0;
+ }
+ len = MCLBYTES;
+ }
+ m->m_len = len = min(totlen, len);
+ bcopy(pkt, mtod(m, caddr_t), len);
+ pkt += len;
+ totlen -= len;
+ *mp = m;
+ mp = &m->m_next;
+ }
+
+ return (top);
+}
+
+/*
+ * Go through the list of multicast addresses and calculate the logical
+ * address filter.
+ */
+void
+mace_calcladrf(ac, af)
+ struct ethercom *ac;
+ u_int8_t *af;
+{
+ struct ifnet *ifp = &ac->ec_if;
+ struct ether_multi *enm;
+ register u_char *cp, c;
+ register u_int32_t crc;
+ register int i, len;
+ struct ether_multistep step;
+
+ /*
+ * Set up multicast address filter by passing all multicast addresses
+ * through a crc generator, and then using the high order 6 bits as an
+ * index into the 64 bit logical address filter. The high order bit
+ * selects the word, while the rest of the bits select the bit within
+ * the word.
+ */
+
+ *((u_int32_t *)af) = *((u_int32_t *)af + 1) = 0;
+
+ ETHER_FIRST_MULTI(step, ac, enm);
+ while (enm != NULL) {
+ if (ETHER_CMP(enm->enm_addrlo, enm->enm_addrhi)) {
+ /*
+ * We must listen to a range of multicast addresses.
+ * For now, just accept all multicasts, rather than
+ * trying to set only those filter bits needed to match
+ * the range. (At this time, the only use of address
+ * ranges is for IP multicast routing, for which the
+ * range is big enough to require all bits set.)
+ */
+ goto allmulti;
+ }
+
+ cp = enm->enm_addrlo;
+ crc = 0xffffffff;
+ for (len = sizeof(enm->enm_addrlo); --len >= 0;) {
+ c = *cp++;
+ for (i = 8; --i >= 0;) {
+ if ((crc & 0x01) ^ (c & 0x01)) {
+ crc >>= 1;
+ crc ^= 0xedb88320;
+ } else
+ crc >>= 1;
+ c >>= 1;
+ }
+ }
+ /* Just want the 6 most significant bits. */
+ crc >>= 26;
+
+ /* Set the corresponding bit in the filter. */
+ af[crc >> 3] |= 1 << (crc & 7);
+
+ ETHER_NEXT_MULTI(step, enm);
+ }
+ ifp->if_flags &= ~IFF_ALLMULTI;
+ return;
+
+allmulti:
+ ifp->if_flags |= IFF_ALLMULTI;
+ *((u_int32_t *)af) = *((u_int32_t *)af + 1) = 0xffffffff;
+}
+
+int
+mc_mediachange(ifp)
+ struct ifnet *ifp;
+{
+ return EINVAL;
+}
+
+void
+mc_mediastatus(ifp, ifmr)
+ struct ifnet *ifp;
+ struct ifmediareq *ifmr;
+{
+ struct mc_softc *sc = ifp->if_softc;
+
+ if ((ifp->if_flags & IFF_UP) == 0)
+ return;
+
+ if (sc->sc_havecarrier)
+ ifmr->ifm_status |= IFM_ACTIVE;
+}
diff --git a/sys/arch/macppc/dev/am79c950reg.h b/sys/arch/macppc/dev/am79c950reg.h
new file mode 100644
index 00000000000..51c9aeedd52
--- /dev/null
+++ b/sys/arch/macppc/dev/am79c950reg.h
@@ -0,0 +1,200 @@
+/* $NetBSD: am79c950reg.h,v 1.1 1998/05/15 10:15:47 tsubai Exp $ */
+
+/*-
+ * Copyright (c) 1997 David Huang <khym@bga.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/*
+ * AMD MACE (Am79C940) register definitions
+ */
+#define MACE_RCVFIFO 0 /* Receive FIFO [15-00] (read only) */
+#define MACE_XMTFIFO 1 /* Transmit FIFO [15-00] (write only) */
+#define MACE_XMTFC 2 /* Transmit Frame Control (read/write) */
+#define MACE_XMTFS 3 /* Transmit Frame Status (read only) */
+#define MACE_XMTRC 4 /* Transmit Retry Count (read only) */
+#define MACE_RCVFC 5 /* Receive Frame Control (read/write) */
+#define MACE_RCVFS 6 /* Receive Frame Status (4 bytes) (read only) */
+#define MACE_FIFOFC 7 /* FIFO Frame Count (read only) */
+#define MACE_IR 8 /* Interrupt Register (read only) */
+#define MACE_IMR 9 /* Interrupt Mask Register (read/write) */
+#define MACE_PR 10 /* Poll Register (read only) */
+#define MACE_BIUCC 11 /* BIU Configuration Control (read/write) */
+#define MACE_FIFOCC 12 /* FIFO Configuration Control (read/write) */
+#define MACE_MACCC 13 /* MAC Configuration Control (read/write) */
+#define MACE_PLSCC 14 /* PLS Configuration Control (read/write) */
+#define MACE_PHYCC 15 /* PHY Confiuration Control (read/write) */
+#define MACE_CHIPIDL 16 /* Chip ID Register [07-00] (read only) */
+#define MACE_CHIPIDH 17 /* Chip ID Register [15-08] (read only) */
+#define MACE_IAC 18 /* Internal Address Configuration (read/write) */
+/* RESERVED 19 Reserved (read/write as 0) */
+#define MACE_LADRF 20 /* Logical Address Filter (8 bytes) (read/write) */
+#define MACE_PADR 21 /* Physical Address (6 bytes) (read/write) */
+/* RESERVED 22 Reserved (read/write as 0) */
+/* RESERVED 23 Reserved (read/write as 0) */
+#define MACE_MPC 24 /* Missed Packet Count (read only) */
+/* RESERVED 25 Reserved (read/write as 0) */
+#define MACE_RNTPC 26 /* Runt Packet Count (read only) */
+#define MACE_RCVCC 27 /* Receive Collision Count (read only) */
+/* RESERVED 28 Reserved (read/write as 0) */
+#define MACE_UTR 29 /* User Test Register (read/write) */
+#define MACE_RTR1 30 /* Reserved Test Register 1 (read/write as 0) */
+#define MACE_RTR2 31 /* Reserved Test Register 2 (read/write as 0) */
+
+#define MACE_NREGS 32
+
+/* 2: Transmit Frame Control (XMTFC) */
+#define DRTRY 0x80 /* Disable Retry */
+#define DXMTFCS 0x08 /* Disable Transmit FCS */
+#define APADXMT 0x01 /* Auto Pad Transmit */
+
+/* 3: Transmit Frame Status (XMTFS) */
+#define XMTSV 0x80 /* Transmit Status Valid */
+#define UFLO 0x40 /* Underflow */
+#define LCOL 0x20 /* Late Collision */
+#define MORE 0x10 /* More than one retry needed */
+#define ONE 0x08 /* Exactly one retry needed */
+#define DEFER 0x04 /* Transmission deferred */
+#define LCAR 0x02 /* Loss of Carrier */
+#define RTRY 0x01 /* Retry Error */
+
+/* 4: Transmit Retry Count (XMTRC) */
+#define EXDEF 0x80 /* Excessive Defer */
+#define XMTRC 0x0f /* Transmit Retry Count */
+
+/* 5: Receive Frame Control (RCVFC) */
+#define LLRCV 0x08 /* Low Latency Receive */
+#define MR 0x04 /* Match/Reject */
+#define ASTRPRCV 0x01 /* Auto Strip Receive */
+
+/* 6: Receive Frame Status (RCVFS) */
+/* 4 byte register; read 4 times to get all of the bytes */
+/* Read 1: RFS0 - Receive Message Byte Count [7-0] (RCVCNT) */
+
+/* Read 2: RFS1 - Receive Status (RCVSTS) */
+#define OFLO 0x80 /* Overflow flag */
+#define CLSN 0x40 /* Collision flag */
+#define FRAM 0x20 /* Framing Error flag */
+#define FCS 0x10 /* FCS Error flag */
+#define RCVCNT 0x0f /* Receive Message Byte Count [11-8] */
+
+/* Read 3: RFS2 - Runt Packet Count (RNTPC) [7-0] */
+
+/* Read 4: RFS3 - Receive Collision Count (RCVCC) [7-0] */
+
+/* 7: FIFO Frame Count (FIFOFC) */
+#define RCVFC 0xf0 /* Receive Frame Count */
+#define XMTFC 0x0f /* Transmit Frame Count */
+
+/* 8: Interrupt Register (IR) */
+#define JAB 0x80 /* Jabber Error */
+#define BABL 0x40 /* Babble Error */
+#define CERR 0x20 /* Collision Error */
+#define RCVCCO 0x10 /* Receive Collision Count Overflow */
+#define RNTPCO 0x08 /* Runt Packet Count Overflow */
+#define MPCO 0x04 /* Missed Packet Count Overflow */
+#define RCVINT 0x02 /* Receive Interrupt */
+#define XMTINT 0x01 /* Transmit Interrupt */
+
+/* 9: Interrut Mask Register (IMR) */
+#define JABM 0x80 /* Jabber Error Mask */
+#define BABLM 0x40 /* Babble Error Mask */
+#define CERRM 0x20 /* Collision Error Mask */
+#define RCVCCOM 0x10 /* Receive Collision Count Overflow Mask */
+#define RNTPCOM 0x08 /* Runt Packet Count Overflow Mask */
+#define MPCOM 0x04 /* Missed Packet Count Overflow Mask */
+#define RCVINTM 0x02 /* Receive Interrupt Mask */
+#define XMTINTM 0x01 /* Transmit Interrupt Mask */
+
+/* 10: Poll Register (PR) */
+#define XMTSV 0x80 /* Transmit Status Valid */
+#define TDTREQ 0x40 /* Transmit Data Transfer Request */
+#define RDTREQ 0x20 /* Receive Data Transfer Request */
+
+/* 11: BIU Configuration Control (BIUCC) */
+#define BSWP 0x40 /* Byte Swap */
+#define XMTSP 0x30 /* Transmit Start Point */
+#define XMTSP_4 0x00 /* 4 bytes */
+#define XMTSP_16 0x10 /* 16 bytes */
+#define XMTSP_64 0x20 /* 64 bytes */
+#define XMTSP_112 0x30 /* 112 bytes */
+#define SWRST 0x01 /* Software Reset */
+
+/* 12: FIFO Configuration Control (FIFOCC) */
+#define XMTFW 0xc0 /* Transmit FIFO Watermark */
+#define XMTFW_8 0x00 /* 8 write cycles */
+#define XMTFW_16 0x40 /* 16 write cycles */
+#define XMTFW_32 0x80 /* 32 write cycles */
+#define RCVFW 0x30 /* Receive FIFO Watermark */
+#define RCVFW_16 0x00 /* 16 bytes */
+#define RCVFW_32 0x10 /* 32 bytes */
+#define RCVFW_64 0x20 /* 64 bytes */
+#define XMTFWU 0x08 /* Transmit FIFO Watermark Update */
+#define RCVFWU 0x04 /* Receive FIFO Watermark Update */
+#define XMTBRST 0x02 /* Transmit Burst */
+#define RCVBRST 0x01 /* Receive Burst */
+
+/* 13: MAC Configuration (MACCC) */
+#define PROM 0x80 /* Promiscuous */
+#define DXMT2PD 0x40 /* Disable Transmit Two Part Deferral */
+#define EMBA 0x20 /* Enable Modified Back-off Algorithm */
+#define DRCVPA 0x08 /* Disable Receive Physical Address */
+#define DRCVBC 0x04 /* Disable Receive Broadcast */
+#define ENXMT 0x02 /* Enable Transmit */
+#define ENRCV 0x01 /* Enable Receive */
+
+/* 14: PLS Configuration Control (PLSCC) */
+#define XMTSEL 0x08 /* Transmit Mode Select */
+#define PORTSEL 0x06 /* Port Select */
+#define PORTSEL_AUI 0x00 /* Select AUI */
+#define PORTSEL_10BT 0x02 /* Select 10BASE-T */
+#define PORTSEL_DAI 0x04 /* Select DAI port */
+#define PORTSEL_GPSI 0x06 /* Select GPSI */
+#define ENPLSIO 0x01 /* Enable PLS I/O */
+
+/* 15: PHY Configuration (PHYCC) */
+#define LNKFL 0x80 /* Link Fail */
+#define DLNKTST 0x40 /* Disable Link Test */
+#define REVPOL 0x20 /* Reversed Polarity */
+#define DAPC 0x10 /* Disable Auto Polarity Correction */
+#define LRT 0x08 /* Low Receive Threshold */
+#define ASEL 0x04 /* Auto Select */
+#define RWAKE 0x02 /* Remote Wake */
+#define AWAKE 0x01 /* Auto Wake */
+
+/* 18: Internal Address Configuration (IAC) */
+#define ADDRCHG 0x80 /* Address Change */
+#define PHYADDR 0x04 /* Physical Address Reset */
+#define LOGADDR 0x02 /* Logical Address Reset */
+
+/* 28: User Test Register (UTR) */
+#define RTRE 0x80 /* Reserved Test Register Enable */
+#define RTRD 0x40 /* Reserved Test Register Disable */
+#define RPA 0x20 /* Run Packet Accept */
+#define FCOLL 0x10 /* Force Collision */
+#define RCVFCSE 0x08 /* Receive FCS Enable */
+#define LOOP 0x06 /* Loopback Control */
+#define LOOP_NONE 0x00 /* No Loopback */
+#define LOOP_EXT 0x02 /* External Loopback */
+#define LOOP_INT 0x04 /* Internal Loopback, excludes MENDEC */
+#define LOOP_INT_MENDEC 0x06 /* Internal Loopback, includes MENDEC */
diff --git a/sys/arch/macppc/dev/dbdma.c b/sys/arch/macppc/dev/dbdma.c
new file mode 100644
index 00000000000..14bb871657c
--- /dev/null
+++ b/sys/arch/macppc/dev/dbdma.c
@@ -0,0 +1,130 @@
+/*
+ * Copyright 1996 1995 by Open Software Foundation, Inc. 1997 1996 1995 1994 1993 1992 1991
+ * All Rights Reserved
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appears in all copies and
+ * that both the copyright notice and this permission notice appear in
+ * supporting documentation.
+ *
+ * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include <sys/param.h>
+#include <sys/malloc.h>
+
+#include <machine/pio.h>
+#include <macppc/dev/dbdma.h>
+
+#define eieio() __asm__ volatile("eieio")
+
+
+static int dbdma_alloc_index = 0;
+dbdma_command_t *dbdma_alloc_commands = NULL;
+
+void
+dbdma_start(dmap, commands)
+ dbdma_regmap_t *dmap;
+ dbdma_command_t *commands;
+{
+ unsigned long addr = kvtop((vm_offset_t) commands);
+
+ if (addr & 0xf)
+ panic("dbdma_start command structure not 16-byte aligned");
+
+ dmap->d_intselect = 0xff; /* Endian magic - clear out interrupts */
+ DBDMA_ST4_ENDIAN(&dmap->d_control,
+ DBDMA_CLEAR_CNTRL( (DBDMA_CNTRL_ACTIVE |
+ DBDMA_CNTRL_DEAD |
+ DBDMA_CNTRL_WAKE |
+ DBDMA_CNTRL_FLUSH |
+ DBDMA_CNTRL_PAUSE |
+ DBDMA_CNTRL_RUN )));
+ eieio();
+
+ while (DBDMA_LD4_ENDIAN(&dmap->d_status) & DBDMA_CNTRL_ACTIVE)
+ eieio();
+
+ dmap->d_cmdptrhi = 0; eieio();/* 64-bit not yet */
+ DBDMA_ST4_ENDIAN(&dmap->d_cmdptrlo, addr); eieio();
+
+ DBDMA_ST4_ENDIAN(&dmap->d_control, DBDMA_SET_CNTRL(DBDMA_CNTRL_RUN));
+ eieio();
+}
+
+void
+dbdma_stop(dmap)
+ dbdma_regmap_t *dmap;
+{
+ out32rb(&dmap->d_control, DBDMA_CLEAR_CNTRL(DBDMA_CNTRL_RUN) |
+ DBDMA_SET_CNTRL(DBDMA_CNTRL_FLUSH));
+
+ while (in32rb(&dmap->d_status) &
+ (DBDMA_CNTRL_ACTIVE|DBDMA_CNTRL_FLUSH));
+}
+
+void
+dbdma_flush(dmap)
+ dbdma_regmap_t *dmap;
+{
+ out32rb(&dmap->d_control, DBDMA_SET_CNTRL(DBDMA_CNTRL_FLUSH));
+
+ while (in32rb(&dmap->d_status) & (DBDMA_CNTRL_FLUSH));
+}
+
+void
+dbdma_reset(dmap)
+ dbdma_regmap_t *dmap;
+{
+ out32rb(&dmap->d_control,
+ DBDMA_CLEAR_CNTRL( (DBDMA_CNTRL_ACTIVE |
+ DBDMA_CNTRL_DEAD |
+ DBDMA_CNTRL_WAKE |
+ DBDMA_CNTRL_FLUSH |
+ DBDMA_CNTRL_PAUSE |
+ DBDMA_CNTRL_RUN )));
+
+ while (in32rb(&dmap->d_status) & DBDMA_CNTRL_RUN);
+}
+
+void
+dbdma_continue(dmap)
+ dbdma_regmap_t *dmap;
+{
+ out32rb(&dmap->d_control,
+ DBDMA_SET_CNTRL(DBDMA_CNTRL_RUN | DBDMA_CNTRL_WAKE) |
+ DBDMA_CLEAR_CNTRL(DBDMA_CNTRL_PAUSE | DBDMA_CNTRL_DEAD));
+}
+
+void
+dbdma_pause(dmap)
+ dbdma_regmap_t *dmap;
+{
+ DBDMA_ST4_ENDIAN(&dmap->d_control,DBDMA_SET_CNTRL(DBDMA_CNTRL_PAUSE));
+ eieio();
+
+ while (DBDMA_LD4_ENDIAN(&dmap->d_status) & DBDMA_CNTRL_ACTIVE)
+ eieio();
+}
+
+dbdma_command_t *
+dbdma_alloc(size)
+ int size;
+{
+ u_int buf;
+
+ buf = (u_int)malloc(size + 0x0f, M_DEVBUF, M_WAITOK);
+ buf = (buf + 0x0f) & ~0x0f;
+
+ return (dbdma_command_t *)buf;
+}
diff --git a/sys/arch/macppc/dev/dbdma.h b/sys/arch/macppc/dev/dbdma.h
new file mode 100644
index 00000000000..672ef018a5d
--- /dev/null
+++ b/sys/arch/macppc/dev/dbdma.h
@@ -0,0 +1,211 @@
+/*
+ * Copyright 1996 1995 by Open Software Foundation, Inc. 1997 1996 1995 1994 1993 1992 1991
+ * All Rights Reserved
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appears in all copies and
+ * that both the copyright notice and this permission notice appear in
+ * supporting documentation.
+ *
+ * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#ifndef _POWERMAC_DBDMA_H_
+#define _POWERMAC_DBDMA_H_
+
+#define DBDMA_CMD_OUT_MORE 0
+#define DBDMA_CMD_OUT_LAST 1
+#define DBDMA_CMD_IN_MORE 2
+#define DBDMA_CMD_IN_LAST 3
+#define DBDMA_CMD_STORE_QUAD 4
+#define DBDMA_CMD_LOAD_QUAD 5
+#define DBDMA_CMD_NOP 6
+#define DBDMA_CMD_STOP 7
+
+/* Keys */
+
+#define DBDMA_KEY_STREAM0 0
+#define DBDMA_KEY_STREAM1 1
+#define DBDMA_KEY_STREAM2 2
+#define DBDMA_KEY_STREAM3 3
+
+/* value 4 is reserved */
+#define DBDMA_KEY_REGS 5
+#define DBDMA_KEY_SYSTEM 6
+#define DBDMA_KEY_DEVICE 7
+
+#define DBDMA_INT_NEVER 0
+#define DBDMA_INT_IF_TRUE 1
+#define DBDMA_INT_IF_FALSE 2
+#define DBDMA_INT_ALWAYS 3
+
+#define DBDMA_BRANCH_NEVER 0
+#define DBDMA_BRANCH_IF_TRUE 1
+#define DBDMA_BRANCH_IF_FALSE 2
+#define DBDMA_BRANCH_ALWAYS 3
+
+#define DBDMA_WAIT_NEVER 0
+#define DBDMA_WAIT_IF_TRUE 1
+#define DBDMA_WAIT_IF_FALSE 2
+#define DBDMA_WAIT_ALWAYS 3
+
+
+/* Channels */
+
+#define DBDMA_SCSI0 0x0
+#define DBDMA_CURIO_SCSI DBDMA_SCSI0
+#define DBDMA_FLOPPY 0x1
+#define DBDMA_ETHERNET_TX 0x2
+#define DBDMA_ETHERNET_RV 0x3
+#define DBDMA_SCC_XMIT_A 0x4
+#define DBDMA_SCC_RECV_A 0x5
+#define DBDMA_SCC_XMIT_B 0x6
+#define DBDMA_SCC_RECV_B 0x7
+#define DBDMA_AUDIO_OUT 0x8
+#define DBDMA_AUDIO_IN 0x9
+#define DBDMA_SCSI1 0xA
+
+/* Control register values (in little endian) */
+
+#define DBDMA_STATUS_MASK 0x000000ff /* Status Mask */
+#define DBDMA_CNTRL_BRANCH 0x00000100
+ /* 0x200 reserved */
+#define DBDMA_CNTRL_ACTIVE 0x00000400
+#define DBDMA_CNTRL_DEAD 0x00000800
+#define DBDMA_CNTRL_WAKE 0x00001000
+#define DBDMA_CNTRL_FLUSH 0x00002000
+#define DBDMA_CNTRL_PAUSE 0x00004000
+#define DBDMA_CNTRL_RUN 0x00008000
+
+#define DBDMA_SET_CNTRL(x) ( ((x) | (x) << 16) )
+#define DBDMA_CLEAR_CNTRL(x) ( (x) << 16)
+
+
+#define DBDMA_REGMAP(channel) \
+ (dbdma_regmap_t *)((v_u_char *) POWERMAC_IO(PCI_DMA_BASE_PHYS) \
+ + (channel << 8))
+
+/* This struct is layout in little endian format */
+
+struct dbdma_command {
+ u_int16_t d_count;
+ u_int16_t d_command;
+ u_int32_t d_address;
+ u_int32_t d_cmddep;
+ u_int16_t d_resid;
+ u_int16_t d_status;
+};
+
+typedef struct dbdma_command dbdma_command_t;
+
+#define DBDMA_BUILD_CMD(d, cmd, key, interrupt, wait, branch) { \
+ dbdma_st16(&(d)->d_command, \
+ ((cmd) << 12) | ((key) << 8) | \
+ ((interrupt) << 4) | \
+ ((branch) << 2) | (wait)); \
+ }
+
+#define DBDMA_BUILD(d, cmd, key, count, address, interrupt, wait, branch) { \
+ dbdma_st16(&(d)->d_command, \
+ ((cmd) << 12) | ((key) << 8) | \
+ ((interrupt) << 4) | \
+ ((branch) << 2) | (wait)); \
+ dbdma_st16(&(d)->d_count, count); \
+ dbdma_st32(&(d)->d_address, address); \
+ (d)->d_resid = 0; \
+ (d)->d_status = 0; \
+ (d)->d_cmddep = 0; \
+ }
+
+static __inline__ void
+dbdma_st32(a, x)
+ volatile u_int32_t *a;
+ u_int32_t x;
+{
+ __asm__ volatile
+ ("stwbrx %0,0,%1" : : "r" (x), "r" (a) : "memory");
+}
+
+static __inline__ void
+dbdma_st16(a, x)
+ volatile u_int16_t *a;
+ u_int16_t x;
+{
+ __asm__ volatile
+ ("sthbrx %0,0,%1" : : "r" (x), "r" (a) : "memory");
+}
+
+static __inline__ u_int32_t
+dbdma_ld32(a)
+ volatile u_int32_t *a;
+{
+ u_int32_t swap;
+
+ __asm__ volatile
+ ("lwbrx %0,0,%1" : "=r" (swap) : "r" (a));
+
+ return swap;
+}
+
+static __inline__ u_int16_t
+dbdma_ld16(a)
+ volatile u_int16_t *a;
+{
+ u_int16_t swap;
+
+ __asm__ volatile
+ ("lhbrx %0,0,%1" : "=r" (swap) : "r" (a));
+
+ return swap;
+}
+
+#define DBDMA_LD4_ENDIAN(a) dbdma_ld32(a)
+#define DBDMA_ST4_ENDIAN(a, x) dbdma_st32(a, x)
+
+/*
+ * DBDMA Channel layout
+ *
+ * NOTE - This structure is in little-endian format.
+ */
+
+struct dbdma_regmap {
+ unsigned long d_control; /* Control Register */
+ unsigned long d_status; /* DBDMA Status Register */
+ unsigned long d_cmdptrhi; /* MSB of command pointer (not used yet) */
+ unsigned long d_cmdptrlo; /* LSB of command pointer */
+ unsigned long d_intselect; /* Interrupt Select */
+ unsigned long d_branch; /* Branch selection */
+ unsigned long d_wait; /* Wait selection */
+ unsigned long d_transmode; /* Transfer modes */
+ unsigned long d_dataptrhi; /* MSB of Data Pointer */
+ unsigned long d_dataptrlo; /* LSB of Data Pointer */
+ unsigned long d_reserved; /* Reserved for the moment */
+ unsigned long d_branchptrhi; /* MSB of Branch Pointer */
+ unsigned long d_branchptrlo; /* LSB of Branch Pointer */
+ /* The remaining fields are undefinied and unimplemented */
+};
+
+typedef volatile struct dbdma_regmap dbdma_regmap_t;
+
+/* DBDMA routines */
+
+void dbdma_start(dbdma_regmap_t *channel, dbdma_command_t *commands);
+void dbdma_stop(dbdma_regmap_t *channel);
+void dbdma_flush(dbdma_regmap_t *channel);
+void dbdma_reset(dbdma_regmap_t *channel);
+void dbdma_continue(dbdma_regmap_t *channel);
+void dbdma_pause(dbdma_regmap_t *channel);
+
+dbdma_command_t *dbdma_alloc(int); /* Allocate command structures */
+
+#endif /* !defined(_POWERMAC_DBDMA_H_) */
diff --git a/sys/arch/macppc/dev/esp.c b/sys/arch/macppc/dev/esp.c
new file mode 100644
index 00000000000..7752213c5c8
--- /dev/null
+++ b/sys/arch/macppc/dev/esp.c
@@ -0,0 +1,583 @@
+/* $NetBSD: esp.c,v 1.1 1998/05/15 10:15:48 tsubai Exp $ */
+
+/*-
+ * Copyright (c) 1997 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * 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 NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/*
+ * Copyright (c) 1996 Charles M. Hannum. 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 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.
+ */
+
+/*
+ * Copyright (c) 1994 Peter Galbavy
+ * Copyright (c) 1995 Paul Kranenburg
+ * 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 Peter Galbavy
+ * 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.
+ */
+
+/*
+ * Based on aic6360 by Jarle Greipsland
+ *
+ * Acknowledgements: Many of the algorithms used in this driver are
+ * inspired by the work of Julian Elischer (julian@tfs.com) and
+ * Charles Hannum (mycroft@duality.gnu.ai.mit.edu). Thanks a million!
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+#include <sys/device.h>
+#include <sys/buf.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/queue.h>
+#include <sys/malloc.h>
+
+#include <vm/vm_param.h> /* for trunc_page */
+
+#include <dev/scsipi/scsi_all.h>
+#include <dev/scsipi/scsipi_all.h>
+#include <dev/scsipi/scsiconf.h>
+#include <dev/scsipi/scsi_message.h>
+
+#include <dev/ofw/openfirm.h>
+
+#include <machine/cpu.h>
+#include <machine/autoconf.h>
+#include <machine/pio.h>
+
+#include <dev/ic/ncr53c9xreg.h>
+#include <dev/ic/ncr53c9xvar.h>
+
+#include <macppc/dev/dbdma.h>
+#include <macppc/dev/espvar.h>
+
+void espattach __P((struct device *, struct device *, void *));
+int espmatch __P((struct device *, struct cfdata *, void *));
+
+/* Linkup to the rest of the kernel */
+struct cfattach esp_ca = {
+ sizeof(struct esp_softc), espmatch, espattach
+};
+
+struct scsipi_adapter esp_switch = {
+ ncr53c9x_scsi_cmd,
+ minphys, /* no max at this level; handled by DMA code */
+ NULL,
+ NULL,
+};
+
+struct scsipi_device esp_dev = {
+ NULL, /* Use default error handler */
+ NULL, /* have a queue, served by this */
+ NULL, /* have no async handler */
+ NULL, /* Use default 'done' routine */
+};
+
+/*
+ * Functions and the switch for the MI code.
+ */
+u_char esp_read_reg __P((struct ncr53c9x_softc *, int));
+void esp_write_reg __P((struct ncr53c9x_softc *, int, u_char));
+int esp_dma_isintr __P((struct ncr53c9x_softc *));
+void esp_dma_reset __P((struct ncr53c9x_softc *));
+int esp_dma_intr __P((struct ncr53c9x_softc *));
+int esp_dma_setup __P((struct ncr53c9x_softc *, caddr_t *,
+ size_t *, int, size_t *));
+void esp_dma_go __P((struct ncr53c9x_softc *));
+void esp_dma_stop __P((struct ncr53c9x_softc *));
+int esp_dma_isactive __P((struct ncr53c9x_softc *));
+
+struct ncr53c9x_glue esp_glue = {
+ esp_read_reg,
+ esp_write_reg,
+ esp_dma_isintr,
+ esp_dma_reset,
+ esp_dma_intr,
+ esp_dma_setup,
+ esp_dma_go,
+ esp_dma_stop,
+ esp_dma_isactive,
+ NULL, /* gl_clear_latched_intr */
+};
+
+static int espdmaintr __P((struct esp_softc *));
+static void esp_shutdownhook __P((void *));
+
+int
+espmatch(parent, cf, aux)
+ struct device *parent;
+ struct cfdata *cf;
+ void *aux;
+{
+ struct confargs *ca = aux;
+
+ if (strcmp(ca->ca_name, "53c94") != 0)
+ return 0;
+
+ if (ca->ca_nreg != 16)
+ return 0;
+ if (ca->ca_nintr != 8)
+ return 0;
+
+ return 1;
+}
+
+/*
+ * Attach this instance, and then all the sub-devices
+ */
+void
+espattach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ register struct confargs *ca = aux;
+ struct esp_softc *esc = (void *)self;
+ struct ncr53c9x_softc *sc = &esc->sc_ncr53c9x;
+ u_int *reg;
+ int sz;
+
+ /*
+ * Set up glue for MI code early; we use some of it here.
+ */
+ sc->sc_glue = &esp_glue;
+
+ esc->sc_node = ca->ca_node;
+ esc->sc_pri = ca->ca_intr[0];
+ printf(" irq %d", esc->sc_pri);
+
+ /*
+ * Map my registers in.
+ */
+ reg = ca->ca_reg;
+ esc->sc_reg = mapiodev(ca->ca_baseaddr + reg[0], reg[1]);
+ esc->sc_dmareg = mapiodev(ca->ca_baseaddr + reg[2], reg[3]);
+
+ /* Allocate 16-byte aligned dma command space */
+ esc->sc_dmacmd = dbdma_alloc(sizeof(dbdma_command_t) * 20);
+
+ /* Other settings */
+ sc->sc_id = 7;
+ sz = OF_getprop(ca->ca_node, "clock-frequency",
+ &sc->sc_freq, sizeof(int));
+ if (sz != sizeof(int))
+ sc->sc_freq = 25000000;
+
+ /* gimme Mhz */
+ sc->sc_freq /= 1000000;
+
+ /* esc->sc_dma->sc_esp = esc;*/
+
+ /*
+ * XXX More of this should be in ncr53c9x_attach(), but
+ * XXX should we really poke around the chip that much in
+ * XXX the MI code? Think about this more...
+ */
+
+ /*
+ * Set up static configuration info.
+ */
+ sc->sc_cfg1 = sc->sc_id | NCRCFG1_PARENB;
+ sc->sc_cfg2 = NCRCFG2_SCSI2; /* | NCRCFG2_FE */
+ sc->sc_cfg3 = NCRCFG3_CDB;
+ sc->sc_rev = NCR_VARIANT_NCR53C94;
+
+ /*
+ * XXX minsync and maxxfer _should_ be set up in MI code,
+ * XXX but it appears to have some dependency on what sort
+ * XXX of DMA we're hooked up to, etc.
+ */
+
+ /*
+ * This is the value used to start sync negotiations
+ * Note that the NCR register "SYNCTP" is programmed
+ * in "clocks per byte", and has a minimum value of 4.
+ * The SCSI period used in negotiation is one-fourth
+ * of the time (in nanoseconds) needed to transfer one byte.
+ * Since the chip's clock is given in MHz, we have the following
+ * formula: 4 * period = (1000 / freq) * 4
+ */
+ sc->sc_minsync = 1000 / sc->sc_freq;
+
+ sc->sc_maxxfer = 64 * 1024;
+
+ /* and the interuppts */
+ intr_establish(esc->sc_pri, IST_LEVEL, IPL_BIO, (void *)ncr53c9x_intr,
+ sc);
+
+ /* Do the common parts of attachment. */
+ ncr53c9x_attach(sc, &esp_switch, &esp_dev);
+
+ /* Turn on target selection using the `dma' method */
+ ncr53c9x_dmaselect = 1;
+
+ /* Reset SCSI bus when halt. */
+ shutdownhook_establish(esp_shutdownhook, sc);
+}
+
+/*
+ * Glue functions.
+ */
+
+u_char
+esp_read_reg(sc, reg)
+ struct ncr53c9x_softc *sc;
+ int reg;
+{
+ struct esp_softc *esc = (struct esp_softc *)sc;
+
+ return in8(&esc->sc_reg[reg * 16]);
+ /*return (esc->sc_reg[reg * 16]);*/
+}
+
+void
+esp_write_reg(sc, reg, val)
+ struct ncr53c9x_softc *sc;
+ int reg;
+ u_char val;
+{
+ struct esp_softc *esc = (struct esp_softc *)sc;
+ u_char v = val;
+
+ out8(&esc->sc_reg[reg * 16], v);
+ /*esc->sc_reg[reg * 16] = v;*/
+}
+
+int
+esp_dma_isintr(sc)
+ struct ncr53c9x_softc *sc;
+{
+ return esp_read_reg(sc, NCR_STAT) & NCRSTAT_INT;
+}
+
+void
+esp_dma_reset(sc)
+ struct ncr53c9x_softc *sc;
+{
+ struct esp_softc *esc = (struct esp_softc *)sc;
+
+ dbdma_stop(esc->sc_dmareg);
+ esc->sc_dmaactive = 0;
+}
+
+int
+esp_dma_intr(sc)
+ struct ncr53c9x_softc *sc;
+{
+ struct esp_softc *esc = (struct esp_softc *)sc;
+
+ return (espdmaintr(esc));
+}
+
+int
+esp_dma_setup(sc, addr, len, datain, dmasize)
+ struct ncr53c9x_softc *sc;
+ caddr_t *addr;
+ size_t *len;
+ int datain;
+ size_t *dmasize;
+{
+ struct esp_softc *esc = (struct esp_softc *)sc;
+ dbdma_command_t *cmdp;
+ u_int cmd;
+ u_int va;
+ int count, offset;
+
+ cmdp = esc->sc_dmacmd;
+ cmd = datain ? DBDMA_CMD_IN_MORE : DBDMA_CMD_OUT_MORE;
+
+ count = *dmasize;
+
+ if (count / NBPG > 32)
+ panic("esp: transfer size >= 128k");
+
+ esc->sc_dmaaddr = addr;
+ esc->sc_dmalen = len;
+ esc->sc_dmasize = count;
+
+ va = (u_int)*esc->sc_dmaaddr;
+ offset = va & PGOFSET;
+
+ /* if va is not page-aligned, setup the first page */
+ if (offset != 0) {
+ int rest = NBPG - offset; /* the rest of the page */
+
+ if (count > rest) { /* if continues to next page */
+ DBDMA_BUILD(cmdp, cmd, 0, rest, kvtop((caddr_t)va),
+ DBDMA_INT_NEVER, DBDMA_WAIT_NEVER,
+ DBDMA_BRANCH_NEVER);
+ count -= rest;
+ va += rest;
+ cmdp++;
+ }
+ }
+
+ /* now va is page-aligned */
+ while (count > NBPG) {
+ DBDMA_BUILD(cmdp, cmd, 0, NBPG, kvtop((caddr_t)va),
+ DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
+ count -= NBPG;
+ va += NBPG;
+ cmdp++;
+ }
+
+ /* the last page (count <= NBPG here) */
+ cmd = datain ? DBDMA_CMD_IN_LAST : DBDMA_CMD_OUT_LAST;
+ DBDMA_BUILD(cmdp, cmd , 0, count, kvtop((caddr_t)va),
+ DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
+ cmdp++;
+
+ DBDMA_BUILD(cmdp, DBDMA_CMD_STOP, 0, 0, 0,
+ DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
+
+ esc->sc_dma_direction = datain ? D_WRITE : 0;
+
+ return 0;
+}
+
+void
+esp_dma_go(sc)
+ struct ncr53c9x_softc *sc;
+{
+ struct esp_softc *esc = (struct esp_softc *)sc;
+
+ dbdma_start(esc->sc_dmareg, esc->sc_dmacmd);
+ esc->sc_dmaactive = 1;
+}
+
+void
+esp_dma_stop(sc)
+ struct ncr53c9x_softc *sc;
+{
+ struct esp_softc *esc = (struct esp_softc *)sc;
+
+ dbdma_stop(esc->sc_dmareg);
+ esc->sc_dmaactive = 0;
+}
+
+int
+esp_dma_isactive(sc)
+ struct ncr53c9x_softc *sc;
+{
+ struct esp_softc *esc = (struct esp_softc *)sc;
+
+ return (esc->sc_dmaactive);
+}
+
+
+/*
+ * Pseudo (chained) interrupt from the esp driver to kick the
+ * current running DMA transfer. I am replying on espintr() to
+ * pickup and clean errors for now
+ *
+ * return 1 if it was a DMA continue.
+ */
+int
+espdmaintr(sc)
+ struct esp_softc *sc;
+{
+ struct ncr53c9x_softc *nsc = (struct ncr53c9x_softc *)sc;
+ int trans, resid;
+ u_long csr = sc->sc_dma_direction;
+
+#if 0
+ if (csr & D_ERR_PEND) {
+ DMACSR(sc) &= ~D_EN_DMA; /* Stop DMA */
+ DMACSR(sc) |= D_INVALIDATE;
+ printf("%s: error: csr=%s\n", nsc->sc_dev.dv_xname,
+ bitmask_snprintf(csr, DMACSRBITS, bits, sizeof(bits)));
+ return -1;
+ }
+#endif
+
+ /* This is an "assertion" :) */
+ if (sc->sc_dmaactive == 0)
+ panic("dmaintr: DMA wasn't active");
+
+ /* dbdma_flush(sc->sc_dmareg); */
+
+ /* DMA has stopped */
+ dbdma_stop(sc->sc_dmareg);
+ sc->sc_dmaactive = 0;
+
+ if (sc->sc_dmasize == 0) {
+ /* A "Transfer Pad" operation completed */
+ NCR_DMA(("dmaintr: discarded %d bytes (tcl=%d, tcm=%d)\n",
+ NCR_READ_REG(nsc, NCR_TCL) |
+ (NCR_READ_REG(nsc, NCR_TCM) << 8),
+ NCR_READ_REG(nsc, NCR_TCL),
+ NCR_READ_REG(nsc, NCR_TCM)));
+ return 0;
+ }
+
+ resid = 0;
+ /*
+ * If a transfer onto the SCSI bus gets interrupted by the device
+ * (e.g. for a SAVEPOINTER message), the data in the FIFO counts
+ * as residual since the ESP counter registers get decremented as
+ * bytes are clocked into the FIFO.
+ */
+ if (!(csr & D_WRITE) &&
+ (resid = (NCR_READ_REG(nsc, NCR_FFLAG) & NCRFIFO_FF)) != 0) {
+ NCR_DMA(("dmaintr: empty esp FIFO of %d ", resid));
+ }
+
+ if ((nsc->sc_espstat & NCRSTAT_TC) == 0) {
+ /*
+ * `Terminal count' is off, so read the residue
+ * out of the ESP counter registers.
+ */
+ resid += (NCR_READ_REG(nsc, NCR_TCL) |
+ (NCR_READ_REG(nsc, NCR_TCM) << 8) |
+ ((nsc->sc_cfg2 & NCRCFG2_FE)
+ ? (NCR_READ_REG(nsc, NCR_TCH) << 16)
+ : 0));
+
+ if (resid == 0 && sc->sc_dmasize == 65536 &&
+ (nsc->sc_cfg2 & NCRCFG2_FE) == 0)
+ /* A transfer of 64K is encoded as `TCL=TCM=0' */
+ resid = 65536;
+ }
+
+ trans = sc->sc_dmasize - resid;
+ if (trans < 0) { /* transferred < 0 ? */
+#if 0
+ /*
+ * This situation can happen in perfectly normal operation
+ * if the ESP is reselected while using DMA to select
+ * another target. As such, don't print the warning.
+ */
+ printf("%s: xfer (%d) > req (%d)\n",
+ sc->sc_dev.dv_xname, trans, sc->sc_dmasize);
+#endif
+ trans = sc->sc_dmasize;
+ }
+
+ NCR_DMA(("dmaintr: tcl=%d, tcm=%d, tch=%d; trans=%d, resid=%d\n",
+ NCR_READ_REG(nsc, NCR_TCL),
+ NCR_READ_REG(nsc, NCR_TCM),
+ (nsc->sc_cfg2 & NCRCFG2_FE)
+ ? NCR_READ_REG(nsc, NCR_TCH) : 0,
+ trans, resid));
+
+ if (csr & D_WRITE) {
+ vm_offset_t va = (vm_offset_t)*sc->sc_dmaaddr;
+ int len = trans;
+
+ va = trunc_page(va);
+ while (len > 0) {
+ flushcache((void *)kvtop((caddr_t)va), NBPG);
+ va += NBPG;
+ len -= NBPG;
+ }
+ }
+
+ *sc->sc_dmalen -= trans;
+ *sc->sc_dmaaddr += trans;
+
+#if 0 /* this is not normal operation just yet */
+ if (*sc->sc_dmalen == 0 ||
+ nsc->sc_phase != nsc->sc_prevphase)
+ return 0;
+
+ /* and again */
+ dma_start(sc, sc->sc_dmaaddr, sc->sc_dmalen, DMACSR(sc) & D_WRITE);
+ return 1;
+#endif
+ return 0;
+}
+
+void
+esp_shutdownhook(arg)
+ void *arg;
+{
+ struct ncr53c9x_softc *sc = arg;
+
+ NCRCMD(sc, NCRCMD_RSTSCSI);
+}
diff --git a/sys/arch/macppc/dev/espvar.h b/sys/arch/macppc/dev/espvar.h
new file mode 100644
index 00000000000..6e14fe97ef7
--- /dev/null
+++ b/sys/arch/macppc/dev/espvar.h
@@ -0,0 +1,62 @@
+/* $NetBSD: espvar.h,v 1.1 1998/05/15 10:15:48 tsubai Exp $ */
+
+/*-
+ * Copyright (c) 1997 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * 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 NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+struct esp_softc {
+ struct ncr53c9x_softc sc_ncr53c9x; /* glue to MI code */
+
+ struct intrhand sc_ih; /* intr handler */
+
+ volatile u_char *sc_reg; /* the registers */
+
+ dbdma_regmap_t *sc_dmareg; /* DMA registers */
+ dbdma_command_t *sc_dmacmd; /* command area for DMA */
+
+ /* openprom stuff */
+ int sc_node; /* PROM node ID */
+ int sc_pri; /* SBUS priority */
+
+ size_t sc_dmasize;
+ caddr_t *sc_dmaaddr;
+ size_t *sc_dmalen;
+ int sc_dmaactive;
+ int sc_dma_direction;
+};
+
+#define D_WRITE 1
+
diff --git a/sys/arch/macppc/dev/font_8x16.c b/sys/arch/macppc/dev/font_8x16.c
new file mode 100644
index 00000000000..4e467acfc96
--- /dev/null
+++ b/sys/arch/macppc/dev/font_8x16.c
@@ -0,0 +1,556 @@
+/* $NetBSD: font_8x16.c,v 1.1 1998/05/15 10:15:48 tsubai Exp $ */
+
+/*
+ * Copyright (c) 1992, 1993, 1994 Hellmuth Michaelis and Joerg Wunsch
+ *
+ * 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
+ * Hellmuth Michaelis and Joerg Wunsch
+ * 4. The name authors 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.
+ */
+
+/*
+ * Translated into compiler and human readable for for the Atari-TT port of
+ * NetBSD by Leo Weppelman.
+ *
+ * Reorganized and edited some chars to fit the iso-8859-1 fontset by
+ * Thomas Gerner
+ */
+
+unsigned char fontdata_8x16[] = {
+/* 0x00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x01 */ 0x00, 0x18, 0x18, 0x3c, 0x3c, 0x7e, 0x7e, 0xff,
+ 0xff, 0x7e, 0x7e, 0x3c, 0x3c, 0x18, 0x18, 0x00,
+/* 0x02 */ 0x42, 0x99, 0x99, 0x42, 0x42, 0x99, 0x99, 0x42,
+ 0x42, 0x99, 0x99, 0x42, 0x42, 0x99, 0x99, 0x42,
+/* 0x03 */ 0x00, 0x00, 0x90, 0x90, 0xf0, 0x90, 0x90, 0x00,
+ 0x3e, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00,
+/* 0x04 */ 0x00, 0x00, 0xf0, 0x80, 0xe0, 0x80, 0x80, 0x00,
+ 0x1e, 0x10, 0x1c, 0x10, 0x10, 0x00, 0x00, 0x00,
+/* 0x05 */ 0x00, 0x00, 0x60, 0x90, 0x80, 0x90, 0x60, 0x00,
+ 0x1c, 0x12, 0x1c, 0x12, 0x12, 0x00, 0x00, 0x00,
+/* 0x06 */ 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0xf0, 0x00,
+ 0x1e, 0x10, 0x1c, 0x10, 0x10, 0x00, 0x00, 0x00,
+/* 0x07 */ 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x08 */ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18,
+ 0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+/* 0x09 */ 0x00, 0x00, 0x88, 0x98, 0xa8, 0xc8, 0x88, 0x00,
+ 0x10, 0x10, 0x10, 0x10, 0x1e, 0x00, 0x00, 0x00,
+/* 0x0a */ 0x00, 0x00, 0x88, 0x88, 0x50, 0x50, 0x20, 0x00,
+ 0x3e, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00,
+/* 0x0b */ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x0c */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+/* 0x0d */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+/* 0x0e */ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x0f */ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+/* 0x10 */ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x11 */ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x12 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x13 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+/* 0x14 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+/* 0x15 */ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+/* 0x16 */ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+/* 0x17 */ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x18 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+/* 0x19 */ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+/* 0x1a */ 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18,
+ 0x0c, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x00, 0x00,
+/* 0x1b */ 0x00, 0x00, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18,
+ 0x30, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x00, 0x00,
+/* 0x1c */ 0x00, 0x00, 0x00, 0x00, 0xfe, 0x6c, 0x6c, 0x6c,
+ 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,
+/* 0x1d */ 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18,
+ 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x1e */ 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60,
+ 0x60, 0x60, 0xe6, 0xfc, 0x00, 0x00, 0x00, 0x00,
+/* 0x1f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* ' ' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* '!' */ 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18,
+ 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+/* '"' */ 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* '#' */ 0x00, 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c,
+ 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,
+/* '$' */ 0x00, 0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c,
+ 0x06, 0x86, 0xc6, 0x7c, 0x18, 0x18, 0x00, 0x00,
+/* '%' */ 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18,
+ 0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00,
+/* '&' */ 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x76, 0xdc,
+ 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+/* ''' */ 0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* '(' */ 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30,
+ 0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00,
+/* ')' */ 0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
+/* '*' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff,
+ 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* '+' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e,
+ 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* ',' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00,
+/* '-' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* '.' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+/* '/' */ 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0c, 0x18,
+ 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00,
+/* '0' */ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xce, 0xde, 0xf6,
+ 0xe6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+/* '1' */ 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
+/* '2' */ 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x0c, 0x18, 0x30,
+ 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+/* '3' */ 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06,
+ 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+/* '4' */ 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe,
+ 0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00,
+/* '5' */ 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xfc, 0x06,
+ 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+/* '6' */ 0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+/* '7' */ 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18,
+ 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00,
+/* '8' */ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+/* '9' */ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06,
+ 0x06, 0x06, 0x0c, 0x78, 0x00, 0x00, 0x00, 0x00,
+/* ':' */ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00,
+ 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* ';' */ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00,
+ 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
+/* '<' */ 0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60,
+ 0x30, 0x18, 0x0c, 0x06, 0x00, 0x00, 0x00, 0x00,
+/* '=' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00,
+ 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* '>' */ 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06,
+ 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00,
+/* '?' */ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18,
+ 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+/* '@' */ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xde, 0xde,
+ 0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00,
+/* 'A' */ 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe,
+ 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+/* 'B' */ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66,
+ 0x66, 0x66, 0x66, 0xfc, 0x00, 0x00, 0x00, 0x00,
+/* 'C' */ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0,
+ 0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
+/* 'D' */ 0x00, 0x00, 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x66,
+ 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00,
+/* 'E' */ 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68,
+ 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
+/* 'F' */ 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68,
+ 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+/* 'G' */ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xde,
+ 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00,
+/* 'H' */ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+/* 'I' */ 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+/* 'J' */ 0x00, 0x00, 0x1e, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
+/* 'K' */ 0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78,
+ 0x6c, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+/* 'L' */ 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60,
+ 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
+/* 'M' */ 0x00, 0x00, 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+/* 'N' */ 0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce,
+ 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+/* 'O' */ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+/* 'P' */ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x60,
+ 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+/* 'Q' */ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+ 0xc6, 0xd6, 0xde, 0x7c, 0x0c, 0x0e, 0x00, 0x00,
+/* 'R' */ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c,
+ 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+/* 'S' */ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x60, 0x38, 0x0c,
+ 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+/* 'T' */ 0x00, 0x00, 0x7e, 0x7e, 0x5a, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+/* 'U' */ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+/* 'V' */ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+ 0xc6, 0x6c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,
+/* 'W' */ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xd6,
+ 0xd6, 0xfe, 0xee, 0x6c, 0x00, 0x00, 0x00, 0x00,
+/* 'X' */ 0x00, 0x00, 0xc6, 0xc6, 0x6c, 0x7c, 0x38, 0x38,
+ 0x7c, 0x6c, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+/* 'Y' */ 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18,
+ 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+/* 'Z' */ 0x00, 0x00, 0xfe, 0xc6, 0x86, 0x0c, 0x18, 0x30,
+ 0x60, 0xc2, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+/* '[' */ 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30,
+ 0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00,
+/* '\' */ 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0x70, 0x38,
+ 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
+/* ']' */ 0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x3c, 0x00, 0x00, 0x00, 0x00,
+/* '^' */ 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* '_' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+/* '`' */ 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 'a' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c,
+ 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+/* 'b' */ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x78, 0x6c, 0x66,
+ 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00,
+/* 'c' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0,
+ 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+/* 'd' */ 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc,
+ 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+/* 'e' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfe,
+ 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+/* 'f' */ 0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60,
+ 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+/* 'g' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc,
+ 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00,
+/* 'h' */ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x6c, 0x76, 0x66,
+ 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+/* 'i' */ 0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+/* 'j' */ 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06,
+ 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00,
+/* 'k' */ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x66, 0x6c, 0x78,
+ 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+/* 'l' */ 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+/* 'm' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0xfe, 0xd6,
+ 0xd6, 0xd6, 0xd6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+/* 'n' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66,
+ 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+/* 'o' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+/* 'p' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66,
+ 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
+/* 'q' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc,
+ 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00,
+/* 'r' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66,
+ 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+/* 's' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60,
+ 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+/* 't' */ 0x00, 0x00, 0x10, 0x30, 0x30, 0xfc, 0x30, 0x30,
+ 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00,
+/* 'u' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc,
+ 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+/* 'v' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6,
+ 0xc6, 0x6c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,
+/* 'w' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xd6,
+ 0xd6, 0xd6, 0xfe, 0x6c, 0x00, 0x00, 0x00, 0x00,
+/* 'x' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x6c, 0x38,
+ 0x38, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
+/* 'y' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00,
+/* 'z' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xcc, 0x18,
+ 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+/* '{' */ 0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18,
+ 0x18, 0x18, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00,
+/* '|' */ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+/* '}' */ 0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x18,
+ 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00,
+/* '~' */ 0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x7f */ 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6,
+ 0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x80 */ 0x00, 0x00, 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,
+/* 0x82 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x83 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x84 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x85 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x86 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x87 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x88 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x89 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x8a */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x8b */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x8c */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x8d */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x8e */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x8f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x90 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x91 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x92 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x93 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x94 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x95 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x96 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x97 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x98 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x99 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x9a */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x9b */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x9c */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x9d */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x9e */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x9f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xa0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xa1 */ 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18,
+ 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+/* 0xa2 */ 0x00, 0x18, 0x18, 0x3c, 0x66, 0x60, 0x60, 0x60,
+ 0x66, 0x3c, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+/* 0xa3 */ 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60,
+ 0x60, 0x60, 0xe6, 0xfc, 0x00, 0x00, 0x00, 0x00,
+/* 0xa4 */ 0xc3, 0x3c, 0x66, 0x42, 0x66, 0x3c, 0xc3, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xa5 */ 0x00, 0x00, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
+ 0x7e, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+/* 0xa6 */ 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00,
+ 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00,
+/* 0xa7 */ 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6,
+ 0x6c, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+/* 0xa8 */ 0x00, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xa9 */ 0x00, 0x7c, 0xc6, 0x82, 0x9a, 0xa6, 0xa2, 0xa6,
+ 0x9a, 0x82, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+/* 0xaa */ 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xab */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8,
+ 0x6c, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xac */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06,
+ 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xad */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xae */ 0x00, 0x7c, 0xc6, 0x82, 0xba, 0xa6, 0xba, 0xaa,
+ 0xa6, 0x82, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+/* 0xaf */ 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xb0 */ 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xb1 */ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18,
+ 0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+/* 0xb2 */ 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xb3 */ 0x00, 0x70, 0xd8, 0x30, 0x30, 0xd8, 0x70, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xb4 */ 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xb5 */ 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66,
+ 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00,
+/* 0xb6 */ 0x00, 0x00, 0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b,
+ 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00,
+/* 0xb7 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xb8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0x00,
+/* 0xb9 */ 0x00, 0x30, 0x70, 0xf0, 0x30, 0x30, 0x78, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xba */ 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xbb */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36,
+ 0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xbc */ 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30,
+ 0x66, 0xce, 0x9e, 0x3e, 0x06, 0x06, 0x00, 0x00,
+/* 0xbd */ 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30,
+ 0x60, 0xdc, 0x86, 0x0c, 0x18, 0x3e, 0x00, 0x00,
+/* 0xbe */ 0x00, 0xc0, 0x60, 0xc2, 0x66, 0xcc, 0x18, 0x30,
+ 0x66, 0xce, 0x9e, 0x3e, 0x06, 0x06, 0x00, 0x00,
+/* 0xbf */ 0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60,
+ 0xc0, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+/* 0xc0 */ 0x18, 0x0c, 0x06, 0x00, 0x38, 0x6c, 0xc6, 0xc6,
+ 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+/* 0xc1 */ 0x18, 0x30, 0x60, 0x00, 0x38, 0x6c, 0xc6, 0xc6,
+ 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+/* 0xc2 */ 0x10, 0x38, 0x6c, 0x00, 0x38, 0x6c, 0xc6, 0xc6,
+ 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+/* 0xc3 */ 0x76, 0xdc, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6,
+ 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+/* 0xc4 */ 0xc6, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6,
+ 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+/* 0xc5 */ 0x38, 0x6c, 0x38, 0x00, 0x38, 0x6c, 0xc6, 0xc6,
+ 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+/* 0xc6 */ 0x00, 0x00, 0x3e, 0x6c, 0xcc, 0xcc, 0xfe, 0xcc,
+ 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00,
+/* 0xc7 */ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0,
+ 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00,
+/* 0xc8 */ 0x18, 0x0c, 0x06, 0x00, 0xfe, 0x66, 0x60, 0x7c,
+ 0x60, 0x60, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
+/* 0xc9 */ 0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c,
+ 0x60, 0x60, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
+/* 0xca */ 0x10, 0x38, 0x6c, 0x00, 0xfe, 0x66, 0x60, 0x7c,
+ 0x60, 0x60, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
+/* 0xcb */ 0x00, 0xc6, 0x00, 0xfe, 0x66, 0x60, 0x60, 0x7c,
+ 0x60, 0x60, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
+/* 0xcc */ 0x18, 0x0c, 0x06, 0x00, 0x3c, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+/* 0xcd */ 0x18, 0x30, 0x60, 0x00, 0x3c, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+/* 0xce */ 0x10, 0x38, 0x6c, 0x00, 0x3c, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+/* 0xcf */ 0x00, 0x66, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+/* 0xd0 */ 0x00, 0x00, 0xf8, 0x6c, 0x66, 0x66, 0xf6, 0x66,
+ 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00,
+/* 0xd1 */ 0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde,
+ 0xce, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+/* 0xd2 */ 0x18, 0x0c, 0x06, 0x00, 0x7c, 0xc6, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+/* 0xd3 */ 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+/* 0xd4 */ 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+/* 0xd5 */ 0x76, 0xdc, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+/* 0xd6 */ 0xc6, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+/* 0xd7 */ 0x00, 0x00, 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x38,
+ 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xd8 */ 0x00, 0x06, 0x7e, 0xce, 0xce, 0xce, 0xd6, 0xd6,
+ 0xe6, 0xe6, 0xe6, 0xfc, 0xc0, 0x00, 0x00, 0x00,
+/* 0xd9 */ 0x18, 0x0c, 0x06, 0x00, 0xc6, 0xc6, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+/* 0xda */ 0x18, 0x30, 0x60, 0x00, 0xc6, 0xc6, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+/* 0xdb */ 0x10, 0x38, 0x6c, 0x00, 0xc6, 0xc6, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+/* 0xdc */ 0xc6, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+/* 0xdd */ 0x18, 0x30, 0x60, 0x00, 0x66, 0x66, 0x66, 0x3c,
+ 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+/* 0xde */ 0x00, 0xf0, 0x60, 0x7c, 0x66, 0x66, 0x66, 0x7c,
+ 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+/* 0xdf */ 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc,
+ 0xc6, 0xc6, 0xc6, 0xcc, 0x00, 0x00, 0x00, 0x00,
+/* 0xe0 */ 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c,
+ 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+/* 0xe1 */ 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c,
+ 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+/* 0xe2 */ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x78, 0x0c, 0x7c,
+ 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+/* 0xe3 */ 0x00, 0x00, 0x76, 0xdc, 0x00, 0x78, 0x0c, 0x7c,
+ 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+/* 0xe4 */ 0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c,
+ 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+/* 0xe5 */ 0x00, 0x38, 0x6c, 0x38, 0x00, 0x78, 0x0c, 0x7c,
+ 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+/* 0xe6 */ 0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xb2, 0x32,
+ 0x7e, 0xd8, 0xd8, 0x6e, 0x00, 0x00, 0x00, 0x00,
+/* 0xe7 */ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60,
+ 0x66, 0x3c, 0x0c, 0x06, 0x3c, 0x00, 0x00, 0x00,
+/* 0xe8 */ 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe,
+ 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+/* 0xe9 */ 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe,
+ 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+/* 0xea */ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe,
+ 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+/* 0xeb */ 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xfe,
+ 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+/* 0xec */ 0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+/* 0xed */ 0x00, 0x0c, 0x18, 0x30, 0x00, 0x38, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+/* 0xee */ 0x00, 0x18, 0x3c, 0x66, 0x00, 0x38, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+/* 0xef */ 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+/* 0xf0 */ 0x00, 0x00, 0x3e, 0x30, 0x18, 0x7c, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+/* 0xf1 */ 0x00, 0x00, 0x76, 0xdc, 0x00, 0xdc, 0x66, 0x66,
+ 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+/* 0xf2 */ 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+/* 0xf3 */ 0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+/* 0xf4 */ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+/* 0xf5 */ 0x00, 0x00, 0x76, 0xdc, 0x00, 0x7c, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+/* 0xf6 */ 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+/* 0xf7 */ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e,
+ 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xf8 */ 0x00, 0x00, 0x00, 0x00, 0x06, 0x7e, 0xce, 0xce,
+ 0xd6, 0xe6, 0xe6, 0xfc, 0xc0, 0x00, 0x00, 0x00,
+/* 0xf9 */ 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc,
+ 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+/* 0xfa */ 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc,
+ 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+/* 0xfb */ 0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc,
+ 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+/* 0xfc */ 0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc,
+ 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+/* 0xfd */ 0x00, 0x18, 0x30, 0x60, 0x00, 0xc6, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00,
+/* 0xfe */ 0x00, 0x00, 0x00, 0xf0, 0x60, 0x7c, 0x66, 0x66,
+ 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
+/* 0xff */ 0x00, 0xc6, 0xc6, 0x00, 0x00, 0xc6, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00
+};
diff --git a/sys/arch/macppc/dev/grf.c b/sys/arch/macppc/dev/grf.c
new file mode 100644
index 00000000000..155b9d5831c
--- /dev/null
+++ b/sys/arch/macppc/dev/grf.c
@@ -0,0 +1,286 @@
+/* $NetBSD: grf.c,v 1.1 1998/05/15 10:15:48 tsubai Exp $ */
+
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: Utah $Hdr: grf.c 1.31 91/01/21$
+ *
+ * @(#)grf.c 7.8 (Berkeley) 5/7/91
+ */
+
+/*
+ * Graphics display driver for the PowerMacintosh.
+ * This is the hardware-independent portion of the driver.
+ * Hardware access is through the grfdev routines below.
+ */
+
+#include <sys/param.h>
+
+#include <sys/device.h>
+#include <sys/ioctl.h>
+#include <sys/file.h>
+#include <sys/malloc.h>
+#include <sys/mman.h>
+#include <sys/poll.h>
+#include <sys/proc.h>
+#include <sys/vnode.h>
+#include <sys/systm.h>
+
+#include <vm/vm.h>
+#include <vm/vm_kern.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/grfioctl.h>
+
+#include <macppc/dev/itevar.h>
+#include <macppc/dev/grfvar.h>
+
+#include "grf.h"
+#include "ite.h"
+
+#if NITE == 0
+#define iteon(u,f)
+#define iteoff(u,f)
+#endif
+
+int grfmatch __P((struct device *, struct cfdata *, void *));
+void grfattach __P((struct device *, struct device *, void *));
+int grfbusprint();
+
+struct cfattach grf_ca = {
+ sizeof(struct grf_softc), grfmatch, grfattach
+};
+
+extern struct cfdriver grf_cd;
+
+#ifdef DEBUG
+#define GRF_DEBUG
+#endif
+
+#ifdef GRF_DEBUG
+#define GDB_DEVNO 0x01
+#define GDB_MMAP 0x02
+#define GDB_IOMAP 0x04
+#define GDB_LOCK 0x08
+int grfdebug = 0;
+#endif
+
+int
+grfmatch(parent, cf, aux)
+ struct device *parent;
+ struct cfdata *cf;
+ void *aux;
+{
+ struct grf_attach_args *ga = aux;
+
+ if (strcmp(ga->ga_name, "grf") != 0)
+ return 0;
+ return 1;
+}
+
+void
+grfattach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct grf_softc *sc = (struct grf_softc *)self;
+ struct grf_attach_args *ga = aux;
+
+ printf("\n");
+
+ /* Load forwarded pointers. */
+ sc->sc_display = ga->ga_display;
+ sc->sc_mode = ga->ga_mode;
+
+ sc->sc_flags = GF_ALIVE; /* XXX bogus */
+
+ /*
+ * Attach ite semantics to the grf. Change the name, forward
+ * everything else.
+ */
+ ga->ga_name = "ite";
+ config_found(self, ga, grfbusprint);
+}
+
+/*ARGSUSED*/
+int
+grfopen(dev, flag, mode, p)
+ dev_t dev;
+ int flag;
+ int mode;
+ struct proc *p;
+{
+ register struct grf_softc *gp;
+ int unit;
+ int error = 0;
+
+ unit = GRFUNIT(dev);
+ gp = grf_cd.cd_devs[unit];
+
+ if (unit >= grf_cd.cd_ndevs || (gp->sc_flags & GF_ALIVE) == 0)
+ return (ENXIO);
+
+ if ((gp->sc_flags & (GF_OPEN | GF_EXCLUDE)) == (GF_OPEN | GF_EXCLUDE))
+ return (EBUSY);
+
+ /*
+ * First open.
+ * XXX: always put in graphics mode.
+ */
+ if ((gp->sc_flags & GF_OPEN) == 0) {
+ gp->sc_flags |= GF_OPEN;
+ /*error = grfon(dev);*/
+ }
+ return (error);
+}
+
+/*ARGSUSED*/
+int
+grfclose(dev, flag, mode, p)
+ dev_t dev;
+ int flag;
+ int mode;
+ struct proc *p;
+{
+ register struct grf_softc *gp;
+
+ gp = grf_cd.cd_devs[GRFUNIT(dev)];
+
+ /*(void)grfoff(dev);*/
+ gp->sc_flags &= GF_ALIVE;
+
+ return (0);
+}
+
+/*ARGSUSED*/
+int
+grfioctl(dev, cmd, data, flag, p)
+ dev_t dev;
+ int cmd;
+ caddr_t data;
+ int flag;
+ struct proc *p;
+{
+ struct grf_softc *gp;
+ struct grfinfo *gm;
+ int error;
+ int unit = GRFUNIT(dev);
+
+ gp = grf_cd.cd_devs[unit];
+ gm = gp->sc_display;
+ error = 0;
+
+ switch (cmd) {
+ case GRFIOCGINFO:
+ bcopy(gm, data, sizeof(struct grfinfo));
+ break;
+ case GRFIOCON:
+ error = grfon(dev);
+ break;
+ case GRFIOCOFF:
+ error = grfoff(dev);
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ return (error);
+}
+
+/*ARGSUSED*/
+int
+grfpoll(dev, events, p)
+ dev_t dev;
+ int events;
+ struct proc *p;
+{
+ return (events & (POLLOUT | POLLWRNORM));
+}
+
+/*ARGSUSED*/
+int
+grfmmap(dev, off, prot)
+ dev_t dev;
+ int off;
+ int prot;
+{
+ struct grf_softc *gp = grf_cd.cd_devs[GRFUNIT(dev)];
+ struct grfinfo *gi = gp->sc_display;
+
+ if (off >= 0 && off < gi->gd_devsize)
+ return (int)gi->gd_devaddr + off;
+
+ return -1;
+}
+
+int
+grfon(dev)
+ dev_t dev;
+{
+ int unit = GRFUNIT(dev);
+ struct grf_softc *gp;
+
+ gp = grf_cd.cd_devs[unit];
+
+ /*
+ * XXX: iteoff call relies on devices being in same order
+ * as ITEs and the fact that iteoff only uses the minor part
+ * of the dev arg.
+ */
+ iteoff(unit, 3);
+
+ return (*gp->sc_mode)(gp, GM_GRFON, NULL);
+}
+
+int
+grfoff(dev)
+ dev_t dev;
+{
+ int unit = GRFUNIT(dev);
+ struct grf_softc *gp;
+ int error;
+
+ gp = grf_cd.cd_devs[unit];
+
+ error = (*gp->sc_mode)(gp, GM_GRFOFF, NULL);
+
+ /* XXX: see comment for iteoff above */
+ iteon(unit, 2);
+
+ return (error);
+}
diff --git a/sys/arch/macppc/dev/grf_ati.c b/sys/arch/macppc/dev/grf_ati.c
new file mode 100644
index 00000000000..c0e10016dde
--- /dev/null
+++ b/sys/arch/macppc/dev/grf_ati.c
@@ -0,0 +1,130 @@
+#include <sys/param.h>
+#include <sys/device.h>
+
+#include <machine/pio.h>
+#include <machine/autoconf.h>
+#include <machine/grfioctl.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcidevs.h>
+#include <dev/ofw/openfirm.h>
+
+#include <macppc/dev/grfvar.h>
+
+caddr_t videoaddr;
+int videorowbytes;
+int videobitdepth;
+int videosize;
+static struct grfinfo ati_display;
+
+static void grf_ati_attach __P((struct device *, struct device *, void *));
+static int grf_ati_match __P((struct device *, struct cfdata *, void *));
+
+static int ati_mode __P((struct grf_softc *, int, void *));
+
+struct grf_ati_softc {
+ struct device sc_dev;
+};
+
+struct cfattach grfati_ca = {
+ sizeof(struct grf_ati_softc), grf_ati_match, grf_ati_attach
+};
+
+int
+grf_ati_match(parent, cf, aux)
+ struct device *parent;
+ struct cfdata *cf;
+ void *aux;
+{
+ struct pci_attach_args *pa = aux;
+
+ if (PCI_CLASS(pa->pa_class) == PCI_CLASS_DISPLAY &&
+ PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_DISPLAY_VGA &&
+ /* PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ATI_MACH64_GX && */
+ PCI_VENDOR(pa->pa_id) == PCI_VENDOR_ATI)
+ return 1;
+
+ return 0;
+}
+
+void
+grf_ati_attach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct pci_attach_args *pa = (struct pci_attach_args *)aux;
+ int csr;
+ int width, height, node;
+ u_int reg[5];
+ caddr_t regaddr;
+ struct grf_attach_args ga;
+ char type[32];
+ extern int console_node;
+
+ printf("\n");
+ csr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
+
+ csr |= PCI_COMMAND_MEM_ENABLE;
+ pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, csr);
+
+ /*
+ * OF_open("/bandit/ATY,mach64") hangs... so we can use
+ * framebuffer when it is specified as a console.
+ */
+
+ node = console_node;
+ if (node == -1)
+ return;
+
+ bzero(type, sizeof(type));
+ OF_getprop(node, "device_type", type, sizeof(type));
+ if (strcmp(type, "display") != 0)
+ return;
+
+ OF_getprop(node, "assigned-addresses", reg, sizeof(reg));
+
+ regaddr = mapiodev(reg[2] + 0x800000 - 0x400, 0x400);
+ videoaddr = mapiodev(reg[2] + 0x400 , reg[4] - 0x400);
+
+
+ /*
+ * set character color to rgb:ff/ff/ff
+ */
+#define DAC_W_INDEX 0xc0
+#define DAC_DATA 0xc1
+
+ out8(regaddr + DAC_W_INDEX, 255);
+ out8(regaddr + DAC_DATA, 255);
+ out8(regaddr + DAC_DATA, 255);
+ out8(regaddr + DAC_DATA, 255);
+
+ ga.ga_name = "grf";
+ ga.ga_mode = ati_mode;
+ ga.ga_display = &ati_display;
+
+ height = videosize >> 16;
+
+ ati_display.gd_regaddr = (caddr_t)reg[2] + 0x800000 - 0x400;
+ ati_display.gd_regsize = 0x400;
+ ati_display.gd_fbaddr = (caddr_t)reg[2] + 0x400;
+ ati_display.gd_fbsize = videorowbytes * height;
+ ati_display.gd_colors = 1 << videobitdepth;
+ ati_display.gd_planes = videobitdepth;
+ ati_display.gd_fbwidth = videorowbytes * 8 / videobitdepth;
+ ati_display.gd_fbheight = height;
+ ati_display.gd_fbrowbytes = videorowbytes;
+ ati_display.gd_devaddr = (caddr_t)reg[2];
+ ati_display.gd_devsize = reg[4];
+
+ config_found(self, &ga, NULL);
+}
+
+int
+ati_mode(sc, cmd, aux)
+ struct grf_softc *sc;
+ int cmd;
+ void *aux;
+{
+ return 0;
+}
diff --git a/sys/arch/macppc/dev/grf_subr.c b/sys/arch/macppc/dev/grf_subr.c
new file mode 100644
index 00000000000..a95a934b60b
--- /dev/null
+++ b/sys/arch/macppc/dev/grf_subr.c
@@ -0,0 +1,59 @@
+/* $NetBSD: grf_subr.c,v 1.1 1998/05/15 10:15:48 tsubai Exp $ */
+
+/*-
+ * Copyright (c) 1996 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe.
+ *
+ * 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 NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+#include <sys/param.h>
+#include <sys/device.h>
+#include <sys/systm.h>
+
+#include <machine/bus.h>
+#include <machine/grfioctl.h>
+
+#include <macppc/dev/grfvar.h>
+
+int
+grfbusprint(aux, name)
+ void *aux;
+ const char *name;
+{
+ struct grf_attach_args *ga = aux;
+
+ if (name)
+ printf("%s at %s", ga->ga_name, name);
+
+ return UNCONF;
+}
diff --git a/sys/arch/macppc/dev/grfvar.h b/sys/arch/macppc/dev/grfvar.h
new file mode 100644
index 00000000000..6638a1496bd
--- /dev/null
+++ b/sys/arch/macppc/dev/grfvar.h
@@ -0,0 +1,82 @@
+/* $NetBSD: grfvar.h,v 1.1 1998/05/15 10:15:48 tsubai Exp $ */
+
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: Utah $Hdr: grfvar.h 1.9 91/01/21$
+ *
+ * @(#)grfvar.h 7.3 (Berkeley) 5/7/91
+ */
+
+/*
+ * State info, per grf instance.
+ */
+struct grf_softc {
+ struct device sc_dev; /* device glue */
+ struct grfinfo *sc_display; /* hardware description (for ioctl) */
+ int sc_flags; /* software flags */
+ int (*sc_mode) __P((struct grf_softc *, int, void *));
+ /* mode-change on/off/mode function */
+};
+
+/*
+ * Attach grf and ite semantics to Mac video hardware.
+ */
+struct grf_attach_args {
+ char *ga_name; /* name of semantics to attach */
+ struct grfinfo *ga_display;
+ int (*ga_mode) __P((struct grf_softc *, int, void *));
+ /* mode-change on/off/mode function */
+};
+
+/* flags */
+#define GF_ALIVE 0x01
+#define GF_OPEN 0x02
+#define GF_EXCLUDE 0x04
+#define GF_WANTED 0x08
+#define GF_BSDOPEN 0x10
+#define GF_HPUXOPEN 0x20
+
+/* requests to mode routine */
+#define GM_GRFON 1
+#define GM_GRFOFF 2
+#define GM_CURRMODE 3
+#define GM_LISTMODES 4
+#define GM_NEWMODE 5
+
+/* minor device interpretation */
+#define GRFUNIT(d) ((d) & 0x7)
diff --git a/sys/arch/macppc/dev/if_mc.c b/sys/arch/macppc/dev/if_mc.c
new file mode 100644
index 00000000000..f3c030404b9
--- /dev/null
+++ b/sys/arch/macppc/dev/if_mc.c
@@ -0,0 +1,404 @@
+/* $NetBSD: if_mc.c,v 1.1 1998/05/15 10:15:48 tsubai Exp $ */
+
+/*-
+ * Copyright (c) 1997 David Huang <khym@bga.com>
+ * All rights reserved.
+ *
+ * Portions of this code are based on code by Denton Gentry <denny1@home.com>
+ * and Yanagisawa Takeshi <yanagisw@aa.ap.titech.ac.jp>.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/*
+ * Bus attachment and DMA routines for the mc driver (Centris/Quadra
+ * 660av and Quadra 840av onboard ethernet, based on the AMD Am79C940
+ * MACE ethernet chip). Also uses the PSC (Peripheral Subsystem
+ * Controller) for DMA to and from the MACE.
+ */
+
+#include <sys/param.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+
+#include <net/if.h>
+#include <net/if_ether.h>
+#include <net/if_media.h>
+
+#include <vm/vm.h>
+
+#include <dev/ofw/openfirm.h>
+
+#include <machine/pio.h>
+#include <machine/bus.h>
+#include <machine/autoconf.h>
+
+#include <macppc/dev/am79c950reg.h>
+#include <macppc/dev/if_mcvar.h>
+
+#define MC_BUFSIZE 0x800
+
+hide int mc_match __P((struct device *, struct cfdata *, void *));
+hide void mc_attach __P((struct device *, struct device *, void *));
+hide void mc_init __P((struct mc_softc *sc));
+hide void mc_putpacket __P((struct mc_softc *sc, u_int len));
+hide int mc_dmaintr __P((void *arg));
+hide void mc_reset_rxdma __P((struct mc_softc *sc));
+hide void mc_reset_txdma __P((struct mc_softc *sc));
+hide void mc_select_utp __P((struct mc_softc *sc));
+hide void mc_select_aui __P((struct mc_softc *sc));
+hide int mc_mediachange __P((struct mc_softc *sc));
+
+int mc_supmedia[] = {
+ IFM_ETHER | IFM_10_T,
+ IFM_ETHER | IFM_10_5,
+ /*IFM_ETHER | IFM_AUTO,*/
+};
+
+#define N_SUPMEDIA (sizeof(mc_supmedia) / sizeof(int));
+
+struct cfattach mc_ca = {
+ sizeof(struct mc_softc), mc_match, mc_attach
+};
+
+hide int
+mc_match(parent, cf, aux)
+ struct device *parent;
+ struct cfdata *cf;
+ void *aux;
+{
+ struct confargs *ca = aux;
+
+ if (strcmp(ca->ca_name, "mace") != 0)
+ return 0;
+
+ /* requires 6 regs */
+ if (ca->ca_nreg / sizeof(int) != 6)
+ return 0;
+
+ /* requires 3 intrs */
+ if (ca->ca_nintr / sizeof(int) != 3)
+ return 0;
+
+ return 1;
+}
+
+hide void
+mc_attach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct confargs *ca = aux;
+ struct mc_softc *sc = (struct mc_softc *)self;
+ u_int8_t myaddr[ETHER_ADDR_LEN];
+ u_int *reg;
+
+ sc->sc_node = ca->ca_node;
+
+ reg = ca->ca_reg;
+ reg[0] += ca->ca_baseaddr;
+ reg[2] += ca->ca_baseaddr;
+ reg[4] += ca->ca_baseaddr;
+
+ sc->sc_txdma = mapiodev(reg[2], reg[3]);
+ sc->sc_rxdma = mapiodev(reg[4], reg[5]);
+ bus_space_map(sc->sc_regt, reg[0], reg[1], 0, &sc->sc_regh);
+ /* XXX sc_regt is uninitialized */
+ sc->sc_tail = 0;
+ sc->sc_txdmacmd = dbdma_alloc(sizeof(dbdma_command_t) * 2);
+ sc->sc_rxdmacmd = (void *)dbdma_alloc(sizeof(dbdma_command_t) * 8);
+ bzero(sc->sc_txdmacmd, sizeof(dbdma_command_t) * 2);
+ bzero(sc->sc_rxdmacmd, sizeof(dbdma_command_t) * 8);
+
+ printf(": irq %d,%d,%d",
+ ca->ca_intr[0], ca->ca_intr[1], ca->ca_intr[2]);
+
+ if (OF_getprop(sc->sc_node, "local-mac-address", myaddr, 6) != 6) {
+ printf(": failed to get MAC address.\n");
+ return;
+ }
+
+ /* allocate memory for transmit buffer and mark it non-cacheable */
+ sc->sc_txbuf = malloc(NBPG, M_DEVBUF, M_WAITOK);
+ sc->sc_txbuf_phys = kvtop(sc->sc_txbuf);
+ bzero(sc->sc_txbuf, NBPG);
+
+ /*
+ * allocate memory for receive buffer and mark it non-cacheable
+ * XXX This should use the bus_dma interface, since the buffer
+ * needs to be physically contiguous. However, it seems that
+ * at least on my system, malloc() does allocate contiguous
+ * memory. If it's not, suggest reducing the number of buffers
+ * to 2, which will fit in one 4K page.
+ */
+ sc->sc_rxbuf = malloc(MC_NPAGES * NBPG, M_DEVBUF, M_WAITOK);
+ sc->sc_rxbuf_phys = kvtop(sc->sc_rxbuf);
+ bzero(sc->sc_rxbuf, MC_NPAGES * NBPG);
+
+ if ((int)sc->sc_txbuf & PGOFSET)
+ printf("txbuf is not page-aligned\n");
+ if ((int)sc->sc_rxbuf & PGOFSET)
+ printf("rxbuf is not page-aligned\n");
+
+ sc->sc_bus_init = mc_init;
+ sc->sc_putpacket = mc_putpacket;
+
+
+ /* disable receive DMA */
+ dbdma_reset(sc->sc_rxdma);
+
+ /* disable transmit DMA */
+ dbdma_reset(sc->sc_txdma);
+
+ /* install interrupt handlers */
+ /*intr_establish(ca->ca_intr[1], IST_LEVEL, IPL_NET, mc_dmaintr, sc);*/
+ intr_establish(ca->ca_intr[2], IST_LEVEL, IPL_NET, mc_dmaintr, sc);
+ intr_establish(ca->ca_intr[0], IST_LEVEL, IPL_NET, mcintr, sc);
+
+ sc->sc_biucc = XMTSP_64;
+ sc->sc_fifocc = XMTFW_16 | RCVFW_64 | XMTFWU | RCVFWU |
+ XMTBRST | RCVBRST;
+ /*sc->sc_plscc = PORTSEL_10BT;*/
+ sc->sc_plscc = PORTSEL_GPSI | ENPLSIO;
+
+ /* mcsetup returns 1 if something fails */
+ if (mcsetup(sc, myaddr)) {
+ printf("mcsetup returns non zero\n");
+ return;
+ }
+#ifdef NOTYET
+ sc->sc_mediachange = mc_mediachange;
+ sc->sc_mediastatus = mc_mediastatus;
+ sc->sc_supmedia = mc_supmedia;
+ sc->sc_nsupmedia = N_SUPMEDIA;
+ sc->sc_defaultmedia = IFM_ETHER | IFM_10_T;
+#endif
+}
+
+/* Bus-specific initialization */
+hide void
+mc_init(sc)
+ struct mc_softc *sc;
+{
+ mc_reset_rxdma(sc);
+ mc_reset_txdma(sc);
+}
+
+hide void
+mc_putpacket(sc, len)
+ struct mc_softc *sc;
+ u_int len;
+{
+ dbdma_command_t *cmd = sc->sc_txdmacmd;
+
+ DBDMA_BUILD(cmd, DBDMA_CMD_OUT_LAST, 0, len, sc->sc_txbuf_phys,
+ DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
+
+ dbdma_start(sc->sc_txdma, sc->sc_txdmacmd);
+}
+
+/*
+ * Interrupt handler for the MACE DMA completion interrupts
+ */
+int
+mc_dmaintr(arg)
+ void *arg;
+{
+ struct mc_softc *sc = arg;
+ int status, offset, statoff;
+ int datalen, resid;
+ int i, n;
+ u_int maccc;
+ dbdma_command_t *cmd;
+
+ /* We've received some packets from the MACE */
+
+ /* Loop through, processing each of the packets */
+ i = sc->sc_tail;
+ for (n = 0; n < MC_RXDMABUFS; n++, i++) {
+ if (i == MC_RXDMABUFS)
+ i = 0;
+
+ cmd = &sc->sc_rxdmacmd[i];
+ status = dbdma_ld16(&cmd->d_status);
+ resid = dbdma_ld16(&cmd->d_resid);
+
+ /*if ((status & D_ACTIVE) == 0)*/
+ if ((status & 0x40) == 0)
+ continue;
+
+#if 1
+ if (dbdma_ld16(&cmd->d_count) != ETHERMTU + 22)
+ printf("bad d_count\n");
+#endif
+
+ datalen = dbdma_ld16(&cmd->d_count) - resid;
+ datalen -= 4; /* 4 == status bytes */
+
+ if (datalen < 4 + sizeof(struct ether_header)) {
+ printf("short packet len=%d\n", datalen);
+ /* continue; */
+ goto next;
+ }
+
+ offset = i * MC_BUFSIZE;
+ statoff = offset + datalen;
+
+ DBDMA_BUILD_CMD(cmd, DBDMA_CMD_STOP, 0, 0, 0, 0);
+ __asm __volatile("eieio");
+
+ sc->sc_rxframe.rx_rcvcnt = sc->sc_rxbuf[statoff + 0];
+ sc->sc_rxframe.rx_rcvsts = sc->sc_rxbuf[statoff + 1];
+ sc->sc_rxframe.rx_rntpc = sc->sc_rxbuf[statoff + 2];
+ sc->sc_rxframe.rx_rcvcc = sc->sc_rxbuf[statoff + 3];
+ sc->sc_rxframe.rx_frame = sc->sc_rxbuf + offset;
+
+ flushcache((char *)sc->sc_rxbuf_phys + offset, datalen + 4);
+ mc_rint(sc);
+
+next:
+ DBDMA_BUILD_CMD(cmd, DBDMA_CMD_IN_LAST, 0, DBDMA_INT_ALWAYS,
+ DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
+ __asm __volatile("eieio");
+ cmd->d_status = 0;
+ cmd->d_resid = 0;
+ sc->sc_tail = i + 1;
+ }
+
+ dbdma_continue(sc->sc_rxdma);
+
+ return 1;
+}
+
+hide void
+mc_reset_rxdma(sc)
+ struct mc_softc *sc;
+{
+ dbdma_command_t *cmd = sc->sc_rxdmacmd;
+ dbdma_regmap_t *dmareg = sc->sc_rxdma;
+ int i;
+ u_int8_t maccc;
+
+ /* Disable receiver, reset the DMA channels */
+ maccc = NIC_GET(sc, MACE_MACCC);
+ NIC_PUT(sc, MACE_MACCC, maccc & ~ENRCV);
+
+ dbdma_reset(dmareg);
+
+ for (i = 0; i < MC_RXDMABUFS; i++) {
+ DBDMA_BUILD(cmd, DBDMA_CMD_IN_LAST, 0, ETHERMTU + 22,
+ sc->sc_rxbuf_phys + MC_BUFSIZE * i, DBDMA_INT_ALWAYS,
+ DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
+ cmd++;
+ }
+
+ DBDMA_BUILD(cmd, DBDMA_CMD_NOP, 0, 0, 0,
+ DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_ALWAYS);
+ dbdma_st32(&cmd->d_cmddep, kvtop((caddr_t)sc->sc_rxdmacmd));
+ cmd++;
+
+ dbdma_start(dmareg, sc->sc_rxdmacmd);
+
+ sc->sc_tail = 0;
+
+ /* Reenable receiver, reenable DMA */
+ NIC_PUT(sc, MACE_MACCC, maccc);
+}
+
+hide void
+mc_reset_txdma(sc)
+ struct mc_softc *sc;
+{
+ dbdma_command_t *cmd = sc->sc_txdmacmd;
+ dbdma_regmap_t *dmareg = sc->sc_txdma;
+ u_int8_t maccc;
+
+ /* disable transmitter */
+ maccc = NIC_GET(sc, MACE_MACCC);
+ NIC_PUT(sc, MACE_MACCC, maccc & ~ENXMT);
+
+ dbdma_reset(dmareg);
+
+ DBDMA_BUILD(cmd, DBDMA_CMD_OUT_LAST, 0, 0, sc->sc_txbuf_phys,
+ DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
+ cmd++;
+ DBDMA_BUILD(cmd, DBDMA_CMD_STOP, 0, 0, 0,
+ DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
+
+ out32rb(&dmareg->d_cmdptrhi, 0);
+ out32rb(&dmareg->d_cmdptrlo, kvtop((caddr_t)sc->sc_txdmacmd));
+
+ /* restore old value */
+ NIC_PUT(sc, MACE_MACCC, maccc);
+}
+
+void
+mc_select_utp(sc)
+ struct mc_softc *sc;
+{
+ sc->sc_plscc = PORTSEL_GPSI | ENPLSIO;
+}
+
+void
+mc_select_aui(sc)
+ struct mc_softc *sc;
+{
+ sc->sc_plscc = PORTSEL_AUI;
+}
+
+int
+mc_mediachange(sc)
+ struct mc_softc *sc;
+{
+ struct ifmedia *ifm = &sc->sc_media;
+
+ if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
+ return EINVAL;
+
+ switch (IFM_SUBTYPE(ifm->ifm_media)) {
+
+ case IFM_10_T:
+ mc_select_utp(sc);
+ break;
+
+ case IFM_10_5:
+ mc_select_aui(sc);
+ break;
+
+ default:
+ return EINVAL;
+ }
+
+ return 0;
+}
+
+void
+mc_mediastatus(sc, ifmr)
+ struct mc_softc *sc;
+ struct ifmediareq *ifmr;
+{
+ if (sc->sc_plscc == PORTSEL_AUI)
+ ifmr->ifm_active = IFM_ETHER | IFM_10_5;
+ else
+ ifmr->ifm_active = IFM_ETHER | IFM_10_T;
+}
diff --git a/sys/arch/macppc/dev/if_mcvar.h b/sys/arch/macppc/dev/if_mcvar.h
new file mode 100644
index 00000000000..a381c18680c
--- /dev/null
+++ b/sys/arch/macppc/dev/if_mcvar.h
@@ -0,0 +1,99 @@
+/* $NetBSD: if_mcvar.h,v 1.1 1998/05/15 10:15:48 tsubai Exp $ */
+
+/*-
+ * Copyright (c) 1997 David Huang <khym@bga.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <macppc/dev/dbdma.h>
+
+#ifdef DDB
+#define integrate
+#define hide
+#else
+#define integrate static /*__inline*/
+#define hide static
+#endif
+
+#define MC_REGSPACING 16
+#define MC_REGSIZE MACE_NREGS * MC_REGSPACING
+#define MACE_REG(x) ((x)*MC_REGSPACING)
+
+#define NIC_GET(sc, reg) (bus_space_read_1((sc)->sc_regt, \
+ (sc)->sc_regh, MACE_REG(reg)))
+#define NIC_PUT(sc, reg, val) (bus_space_write_1((sc)->sc_regt, \
+ (sc)->sc_regh, MACE_REG(reg), (val)))
+
+#ifndef MC_RXDMABUFS
+#define MC_RXDMABUFS 4
+#endif
+#if (MC_RXDMABUFS < 2)
+#error Must have at least two buffers for DMA!
+#endif
+
+#define MC_NPAGES ((MC_RXDMABUFS * 0x800 + NBPG - 1) / NBPG)
+
+struct mc_rxframe {
+ u_int8_t rx_rcvcnt;
+ u_int8_t rx_rcvsts;
+ u_int8_t rx_rntpc;
+ u_int8_t rx_rcvcc;
+ u_char *rx_frame;
+};
+
+struct mc_softc {
+ struct device sc_dev; /* base device glue */
+ struct ethercom sc_ethercom; /* Ethernet common part */
+#define sc_if sc_ethercom.ec_if
+ struct ifmedia sc_media;
+
+ struct mc_rxframe sc_rxframe;
+ u_int8_t sc_biucc;
+ u_int8_t sc_fifocc;
+ u_int8_t sc_plscc;
+ u_int8_t sc_enaddr[6];
+ u_int8_t sc_pad[2];
+ int sc_havecarrier; /* carrier status */
+ void (*sc_bus_init) __P((struct mc_softc *));
+ void (*sc_putpacket) __P((struct mc_softc *, u_int));
+ int (*sc_mediachange) __P((struct mc_softc *));
+ void (*sc_mediastatus) __P((struct mc_softc *,
+ struct ifmediareq *));
+
+ bus_space_tag_t sc_regt;
+ bus_space_handle_t sc_regh;
+
+ u_char *sc_txbuf, *sc_rxbuf;
+ int sc_txbuf_phys, sc_rxbuf_phys;
+ int sc_tail;
+
+ int sc_node;
+ dbdma_regmap_t *sc_txdma;
+ dbdma_command_t *sc_txdmacmd;
+ dbdma_regmap_t *sc_rxdma;
+ dbdma_command_t *sc_rxdmacmd;
+};
+
+int mcsetup __P((struct mc_softc *, u_int8_t *));
+void mcintr __P((void *arg));
+void mc_rint __P((struct mc_softc *sc));
diff --git a/sys/arch/macppc/dev/ite.c b/sys/arch/macppc/dev/ite.c
new file mode 100644
index 00000000000..7c5e60ebd00
--- /dev/null
+++ b/sys/arch/macppc/dev/ite.c
@@ -0,0 +1,1380 @@
+/* $NetBSD: ite.c,v 1.1 1998/05/15 10:15:49 tsubai Exp $ */
+
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: Utah $Hdr: ite.c 1.28 92/12/20$
+ *
+ * @(#)ite.c 8.2 (Berkeley) 1/12/94
+ */
+
+/*
+ * ite.c
+ *
+ * The ite module handles the system console; that is, stuff printed
+ * by the kernel and by user programs while "desktop" and X aren't
+ * running. Some (very small) parts are based on hp300's 4.4 ite.c,
+ * hence the above copyright.
+ *
+ * -- Brad and Lawrence, June 26th, 1994
+ *
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <dev/cons.h>
+#include <sys/conf.h>
+#include <sys/device.h>
+#include <sys/ioctl.h>
+#include <sys/malloc.h>
+#include <sys/proc.h>
+#include <sys/tty.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/frame.h>
+
+#define KEYBOARD_ARRAY
+#include <machine/keyboard.h>
+#include <machine/adbsys.h>
+#include <machine/iteioctl.h>
+#include <machine/grfioctl.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+/*#include <powermac/dev/viareg.h>*/
+#include <macppc/dev/itevar.h>
+#include <macppc/dev/grfvar.h>
+
+/*#include "6x10.h"*/
+extern u_char fontdata_8x16[];
+#define CHARWIDTH 8
+#define CHARHEIGHT 16
+
+/* Local function prototypes */
+static inline void putpixel1 __P((int, int, int *, int));
+static void putpixel2 __P((int, int, int *, int));
+static void putpixel4 __P((int, int, int *, int));
+static void putpixel8 __P((int, int, int *, int));
+static void putpixel16 __P((int, int, int *, int));
+static void putpixel32 __P((int, int, int *, int));
+static void reversepixel1 __P((int, int, int));
+static void writechar __P((char, int, int, int));
+static void drawcursor __P((void));
+static void erasecursor __P((void));
+static void scrollup __P((void));
+static void scrolldown __P((void));
+static void clear_screen __P((int));
+static void clear_line __P((int));
+static void reset_tabs __P((void));
+static void clear_tabs __P((void));
+static void vt100_reset __P((void));
+static void putc_normal __P((char));
+static void putc_esc __P((char));
+static void putc_gotpars __P((char));
+static void putc_getpars __P((char));
+static void putc_square __P((char));
+static void ite_putchar __P((char));
+static int ite_pollforchar __P((void));
+static int itematch __P((struct device *, struct cfdata *, void *));
+static void iteattach __P((struct device *, struct device *, void *));
+
+#define dprintf if (0) printf
+
+#define ATTR_NONE 0
+#define ATTR_BOLD 1
+#define ATTR_UNDER 2
+#define ATTR_REVERSE 4
+
+enum vt100state_e {
+ ESnormal, /* Nothing yet */
+ ESesc, /* Got ESC */
+ ESsquare, /* Got ESC [ */
+ ESgetpars, /* About to get or getting the parameters */
+ ESgotpars, /* Finished getting the parameters */
+ ESfunckey, /* Function key */
+ EShash, /* DEC-specific stuff (screen align, etc.) */
+ ESsetG0, /* Specify the G0 character set */
+ ESsetG1, /* Specify the G1 character set */
+ ESignore /* Ignore this sequence */
+} vt100state = ESnormal;
+
+/* From Booter via locore */
+long videoaddr;
+long videorowbytes;
+long videobitdepth;
+u_long videosize;
+
+/* Calculated by itecninit() */
+static int ite_initted = 0;
+static int width, height; /* width, height in pixels */
+static int scrcols, scrrows; /* width, height in characters */
+static int screenrowbytes; /* number of visible bytes per row */
+
+/* VT100 emulation */
+#define MAXPARS 16 /* max number of VT100 op parameters */
+static int par[MAXPARS], numpars; /* parameter array, # of parameters */
+static int x = 0, y = 0; /* current VT100 cursor location */
+static int savex, savey; /* saved cursor location */
+static int hanging_cursor; /* cursor waiting for more output */
+static int attr; /* current video attribute */
+static char tab_stops[255]; /* tab stops */
+static int scrreg_top; /* scroll region */
+static int scrreg_bottom;
+
+/* Console bell parameters */
+static int bell_freq = 1880; /* frequency */
+static int bell_length = 10; /* duration */
+static int bell_volume = 100; /* volume */
+
+/* For polled ADB mode */
+static int polledkey;
+extern int adb_polling;
+
+struct tty *ite_tty; /* Our tty */
+
+static void (*putpixel) __P((int x, int y, int *c, int num));
+static void (*reversepixel) __P((int x, int y, int num));
+
+/* For capslock key functionality */
+#define isealpha(ch) (((ch)>='A'&&(ch)<='Z')||((ch)>='a'&&(ch)<='z')||((ch)>=0xC0&&(ch)<=0xFF))
+
+/*
+ * Bitmap handling functions
+ */
+
+static inline void
+putpixel1(xx, yy, c, num)
+ int xx, yy;
+ int *c;
+ int num;
+{
+ u_int i, mask;
+ u_char *sc;
+
+ sc = (u_char *)videoaddr;
+
+ i = 7 - (xx & 7);
+ mask = ~(1 << i);
+ sc += yy * videorowbytes + (xx >> 3);
+ while (num--) {
+ *sc &= mask;
+ *sc |= (*c++ & 1) << i;
+ sc += videorowbytes;
+ }
+}
+
+static void
+putpixel2(xx, yy, c, num)
+ int xx, yy;
+ int *c;
+ int num;
+{
+ u_int i, mask;
+ u_char *sc;
+
+ sc = (u_char *)videoaddr;
+
+ i = 6 - ((xx & 3) << 1);
+ mask = ~(3 << i);
+ sc += yy * videorowbytes + (xx >> 2);
+ while (num--) {
+ *sc &= mask;
+ *sc |= (*c++ & 3) << i;
+ sc += videorowbytes;
+ }
+}
+
+static void
+putpixel4(xx, yy, c, num)
+ int xx, yy;
+ int *c;
+ int num;
+{
+ u_int i, mask;
+ u_char *sc;
+
+ sc = (u_char *)videoaddr;
+
+ i = 4 - ((xx & 1) << 2);
+ mask = ~(15 << i);
+ sc += yy * videorowbytes + (xx >> 1);
+ while (num--) {
+ *sc &= mask;
+ *sc |= (*c++ & 15) << i;
+ sc += videorowbytes;
+ }
+}
+
+static void
+putpixel8(xx, yy, c, num)
+ int xx, yy;
+ int *c;
+ int num;
+{
+ u_char *sc;
+
+ sc = (u_char *)videoaddr;
+
+ sc += yy * videorowbytes + xx;
+ while (num--) {
+ *sc = *c++ & 0xff;
+ sc += videorowbytes;
+ }
+}
+
+static void
+putpixel16(xx, yy, c, num)
+ int xx, yy;
+ int *c;
+ int num;
+{
+ u_short *sc;
+ int videorowshorts;
+ u_char uc;
+
+ sc = (u_short *)videoaddr;
+
+ videorowshorts = videorowbytes >> 1;
+ sc += yy * videorowshorts + xx;
+ while (num--) {
+ uc = (*c++ & 0xff);
+ *sc = (uc << 8) | uc;
+ sc += videorowshorts;
+ }
+}
+
+static void
+putpixel32(xx, yy, c, num)
+ int xx, yy;
+ int *c;
+ int num;
+{
+ u_long *sc;
+ int videorowlongs;
+ u_char uc;
+
+ sc = (u_long *)videoaddr;
+
+ videorowlongs = videorowbytes >> 2;
+ sc += yy * videorowlongs + xx;
+ while (num--) {
+ uc = (*c++ & 0xff);
+ *sc = (uc << 24) | (uc << 16) | (uc << 8) | uc;
+ sc += videorowlongs;
+ }
+}
+
+static void
+reversepixel1(xx, yy, num)
+ int xx, yy, num;
+{
+ u_int mask;
+ u_char *sc;
+ u_long *sl;
+ u_short *ss;
+ int videorowshorts;
+ int videorowlongs;
+
+ sc = (u_char *)videoaddr;
+ mask = 0; /* Get rid of warning from compiler */
+
+ switch (videobitdepth) {
+ case 1:
+ mask = 1 << (7 - (xx & 7));
+ sc += yy * videorowbytes + (xx >> 3);
+ break;
+ case 2:
+ mask = 3 << (6 - ((xx & 3) << 1));
+ sc += yy * videorowbytes + (xx >> 2);
+ break;
+ case 4:
+ mask = 15 << (4 - ((xx & 1) << 2));
+ sc += yy * videorowbytes + (xx >> 1);
+ break;
+ case 8:
+ mask = 255;
+ sc += yy * videorowbytes + xx;
+ break;
+ case 16:
+ videorowshorts = videorowbytes >> 1;
+ ss = (u_short *)videoaddr;
+ ss += yy * videorowshorts + xx;
+ while (num--) {
+ *ss ^= 0xffff;
+ ss += videorowshorts;
+ }
+ return;
+ case 32:
+ videorowlongs = videorowbytes >> 2;
+ sl = (u_long *)videoaddr;
+ sl += yy * videorowlongs + xx;
+ while (num--) {
+ *sl ^= 0xffffffff;
+ sl += videorowlongs;
+ }
+ return;
+ default:
+ panic("reversepixel(): unsupported bit depth");
+ }
+
+ while (num--) {
+ *sc ^= mask;
+ sc += videorowbytes;
+ }
+}
+
+static void
+writechar(ch, x, y, attr)
+ char ch;
+ int x, y, attr;
+{
+ int i, j, mask, rev, col[CHARHEIGHT];
+ u_char *c;
+
+ ch &= 0x7F;
+ x *= CHARWIDTH;
+ y *= CHARHEIGHT;
+
+ rev = (attr & ATTR_REVERSE) ? 255 : 0;
+
+ /*c = &Font6x10[ch * CHARHEIGHT];*/
+ c = &fontdata_8x16[ch * CHARHEIGHT];
+
+ switch (videobitdepth) {
+ case 1:
+ for (j = 0; j < CHARWIDTH; j++) {
+ mask = 1 << (CHARWIDTH - 1 - j);
+ for (i = 0; i < CHARHEIGHT; i++)
+ col[i] = ((c[i] & mask) ? 255 : 0) ^ rev;
+ putpixel1(x + j, y, col, CHARHEIGHT);
+ }
+ if (attr & ATTR_UNDER) {
+ col[0] = 255;
+ for (j = 0; j < CHARWIDTH; j++)
+ putpixel1(x + j, y + CHARHEIGHT - 1, col, 1);
+ }
+ break;
+ case 2:
+ case 4:
+ case 8:
+ case 16:
+ case 32:
+ for (j = 0; j < CHARWIDTH; j++) {
+ mask = 1 << (CHARWIDTH - 1 - j);
+ for (i = 0; i < CHARHEIGHT; i++)
+ col[i] = ((c[i] & mask) ? 255 : 0) ^ rev;
+ putpixel(x + j, y, col, CHARHEIGHT);
+ }
+ if (attr & ATTR_UNDER) {
+ col[0] = 255;
+ for (j = 0; j < CHARWIDTH; j++)
+ putpixel(x + j, y + CHARHEIGHT - 1, col, 1);
+ }
+ break;
+ }
+}
+
+static void
+drawcursor()
+{
+ u_int j, X, Y;
+
+ X = x * CHARWIDTH;
+ Y = y * CHARHEIGHT;
+
+ for (j = 0; j < CHARWIDTH; j++)
+ reversepixel(X + j, Y, CHARHEIGHT);
+}
+
+static void
+erasecursor()
+{
+ u_int j, X, Y;
+
+ X = x * CHARWIDTH;
+ Y = y * CHARHEIGHT;
+
+ for (j = 0; j < CHARWIDTH; j++)
+ reversepixel(X + j, Y, CHARHEIGHT);
+}
+
+static void
+scrollup()
+{
+ u_char *from, *to;
+ u_int linebytes;
+ u_short i;
+
+ linebytes = videorowbytes * CHARHEIGHT;
+ to = (u_char *)videoaddr + (scrreg_top * linebytes);
+ from = to + linebytes;
+
+ for (i = (scrreg_bottom - scrreg_top) * CHARHEIGHT; i > 0; i--) {
+ ovbcopy(from, to, screenrowbytes);
+ from += videorowbytes;
+ to += videorowbytes;
+ }
+ for (i = CHARHEIGHT; i > 0; i--) {
+ bzero(to, screenrowbytes);
+ to += videorowbytes;
+ }
+}
+
+static void
+scrolldown()
+{
+ u_char *from, *to;
+ u_int linebytes;
+ u_short i;
+
+ linebytes = videorowbytes * CHARHEIGHT;
+ to = (u_char *)videoaddr + ((scrreg_bottom + 1) * linebytes);
+ from = to - linebytes;
+
+ for (i = (scrreg_bottom - scrreg_top) * CHARHEIGHT; i > 0; i--) {
+ from -= videorowbytes;
+ to -= videorowbytes;
+ ovbcopy(from, to, screenrowbytes);
+ }
+ for (i = CHARHEIGHT; i > 0; i--) {
+ to -= videorowbytes;
+ bzero(to, screenrowbytes);
+ }
+}
+
+static void
+clear_screen(which)
+ int which;
+{
+ u_char *p;
+ u_short len, i;
+
+ p = (u_char *)videoaddr;
+
+ switch (which) {
+ case 0: /* To end of screen */
+ if (x > 0) {
+ clear_line(0);
+ if (y < scrrows)
+ y++;
+ x = 0;
+ }
+ p += y * videorowbytes * CHARHEIGHT;
+ len = scrrows - y;
+ break;
+ case 1: /* To start of screen */
+ if (x > 0) {
+ clear_line(1);
+ if (y > 0)
+ y--;
+ x = 0;
+ }
+ len = y;
+ break;
+ case 2: /* Whole screen */
+ default:
+ len = scrrows;
+ break;
+ }
+
+ for (i = len * CHARHEIGHT; i > 0; i--) {
+ bzero(p, screenrowbytes);
+ p += videorowbytes;
+ }
+}
+
+static void
+clear_line(which)
+ int which;
+{
+ u_char *to;
+ u_int linebytes;
+ int start, end, i;
+
+
+ /*
+ * This routine runs extremely slowly. I don't think it's
+ * used all that often, except for To end of line. I'll go
+ * back and speed this up when I speed up the whole ite
+ * module. --LK
+ */
+
+ switch (which) {
+ default:
+ case 0: /* To end of line */
+ start = x;
+ end = scrcols;
+ break;
+ case 1: /* To start of line */
+ start = 0;
+ end = x;
+ break;
+ case 2: /* Whole line */
+ linebytes = videorowbytes * CHARHEIGHT;
+ to = (u_char *)videoaddr + (y * linebytes);
+
+ for (i = CHARHEIGHT; i > 0; i--) {
+ bzero(to, screenrowbytes);
+ to += videorowbytes;
+ }
+ return;
+ }
+
+ for (i = start; i < end; i++)
+ writechar(' ', i, y, ATTR_NONE);
+}
+
+static void
+reset_tabs()
+{
+ int i;
+
+ for (i = 0; i < scrcols; i++)
+ tab_stops[i] = ((i % 8) == 0);
+}
+
+static void
+clear_tabs()
+{
+ int i;
+
+ for (i = 0; i < scrcols; i++)
+ tab_stops[i] = 0;
+}
+
+static void
+vt100_reset()
+{
+ reset_tabs();
+ scrreg_top = 0;
+ scrreg_bottom = scrrows - 1;
+ attr = ATTR_NONE;
+}
+
+static void
+putc_normal(ch)
+ char ch;
+{
+ switch (ch) {
+ case '\a': /* Beep */
+ /*mac68k_ring_bell(bell_freq, bell_length, bell_volume);*/
+ break;
+ case 127: /* Delete */
+ case '\b': /* Backspace */
+ if (hanging_cursor)
+ hanging_cursor = 0;
+ else if (x > 0)
+ x--;
+ break;
+ case '\t': /* Tab */
+ do
+ x++;
+ while ((tab_stops[x] == 0) && (x < scrcols));
+ break;
+ case '\n': /* Line feed */
+ if (y == scrreg_bottom)
+ scrollup();
+ else
+ y++;
+ break;
+ case '\r': /* Carriage return */
+ x = 0;
+ hanging_cursor = 0;
+ break;
+ case '\e': /* Escape */
+ vt100state = ESesc;
+ hanging_cursor = 0;
+ break;
+ default:
+ if (ch >= ' ') {
+ if (hanging_cursor) {
+ x = 0;
+ if (y == scrreg_bottom)
+ scrollup();
+ else
+ y++;
+ hanging_cursor = 0;
+ }
+
+ writechar(ch, x, y, attr);
+
+ if (x == scrcols - 1)
+ hanging_cursor = 1;
+ else
+ x++;
+ if (x >= scrcols) { /* can we ever get here? */
+ x = 0;
+ y++;
+ }
+ }
+ break;
+ }
+}
+
+static void
+putc_esc(ch)
+ char ch;
+{
+ vt100state = ESnormal;
+
+ switch (ch) {
+ case '[':
+ vt100state = ESsquare;
+ break;
+ case '(':
+ vt100state = ESsetG0;
+ break;
+ case ')':
+ vt100state = ESsetG1;
+ break;
+ case 'E': /* Next line */
+ x = 0;
+ /* FALLTHROUGH */
+ case 'D': /* Line feed */
+ if (y == scrreg_bottom)
+ scrollup();
+ else
+ y++;
+ break;
+ case 'H': /* Set tab stop */
+ tab_stops[x] = 1;
+ break;
+ case 'M': /* Cursor up */
+ if (y == scrreg_top)
+ scrolldown();
+ else
+ y--;
+ break;
+ case '>':
+ vt100_reset();
+ break;
+ case '7': /* Save cursor */
+ savex = x;
+ savey = y;
+ break;
+ case '8': /* Restore cursor */
+ x = savex;
+ y = savey;
+ break;
+ default:
+ /* Rest not supported */
+ break;
+ }
+}
+
+static void
+putc_gotpars(ch)
+ char ch;
+{
+ int i;
+
+ vt100state = ESnormal;
+ switch (ch) {
+ case 'A': /* Up */
+ y -= par[0] ? par[0] : 1;
+ if (y < scrreg_top)
+ y = scrreg_top;
+ break;
+ case 'B': /* Down */
+ y += par[0] ? par[0] : 1;
+ if (y > scrreg_bottom)
+ y = scrreg_bottom;
+ break;
+ case 'C': /* Right */
+ x+= par[0] ? par[0] : 1;
+ break;
+ case 'D': /* Left */
+ x-= par[0] ? par[0] : 1;
+ break;
+ case 'H': /* Set cursor position */
+ case 'f': /* Set cursor position */
+ x = par[1] - 1;
+ y = par[0] - 1;
+ hanging_cursor = 0;
+ break;
+ case 'J': /* Clear part of screen */
+ clear_screen(par[0]);
+ break;
+ case 'K': /* Clear part of line */
+ clear_line(par[0]);
+ break;
+ case 'L': /* Add line */
+ if (scrreg_top < scrreg_bottom) {
+ i = scrreg_top;
+ scrreg_top = y;
+ scrolldown();
+ scrreg_top = i;
+ } else
+ clear_line(0);
+ break;
+ case 'M': /* Delete line */
+ if (scrreg_top < scrreg_bottom) {
+ i = scrreg_top;
+ scrreg_top = y;
+ scrollup();
+ scrreg_top = i;
+ } else
+ clear_line(0);
+ break;
+ case 'g': /* Clear tab stops */
+ if (numpars >= 1) {
+ if (par[0] == 3)
+ clear_tabs();
+ else if (par[0] == 0)
+ tab_stops[x] = 0;
+ }
+ break;
+ case 'm': /* Set attribute */
+ for (i = 0; i < numpars; i++) {
+ switch (par[i]) {
+ case 0:
+ attr = ATTR_NONE;
+ break;
+ case 1:
+ attr |= ATTR_BOLD;
+ break;
+ case 4:
+ attr |= ATTR_UNDER;
+ break;
+ case 7:
+ attr |= ATTR_REVERSE;
+ break;
+ case 21:
+ attr &= ~ATTR_BOLD;
+ break;
+ case 24:
+ attr &= ~ATTR_UNDER;
+ break;
+ case 27:
+ attr &= ~ATTR_REVERSE;
+ break;
+ }
+ }
+ break;
+ case 'r': /* Set scroll region */
+ /* ensure top < bottom, and both within limits */
+ if ((numpars > 0) && (par[0] < scrrows))
+ scrreg_top = par[0] - 1;
+ else
+ scrreg_top = 0;
+ if ((numpars > 1) && (par[1] <= scrrows) && (par[1] > par[0]))
+ scrreg_bottom = par[1] - 1;
+ else
+ scrreg_bottom = scrrows - 1;
+ break;
+ }
+}
+
+static void
+putc_getpars(ch)
+ char ch;
+{
+ switch (ch) {
+ case '?':
+ /* Not supported */
+ return;
+ case '[':
+ vt100state = ESnormal;
+ /* Not supported */
+ return;
+ default:
+ if (ch == ';' && numpars < MAXPARS - 1)
+ numpars++;
+ else if (ch >= '0' && ch <= '9') {
+ par[numpars] *= 10;
+ par[numpars] += ch - '0';
+ } else {
+ numpars++;
+ vt100state = ESgotpars;
+ putc_gotpars(ch);
+ }
+ }
+}
+
+static void
+putc_square(ch)
+ char ch;
+{
+ u_short i;
+
+ for (i = 0; i < MAXPARS; i++)
+ par[i] = 0;
+
+ numpars = 0;
+ vt100state = ESgetpars;
+
+ putc_getpars(ch);
+}
+
+static void
+ite_putchar(ch)
+ char ch;
+{
+ switch (vt100state) {
+ default:
+ vt100state = ESnormal; /* FALLTHROUGH */
+ case ESnormal:
+ putc_normal(ch);
+ break;
+ case ESesc:
+ putc_esc(ch);
+ break;
+ case ESsquare:
+ putc_square(ch);
+ break;
+ case ESgetpars:
+ putc_getpars(ch);
+ break;
+ case ESgotpars:
+ putc_gotpars(ch);
+ break;
+ }
+
+ if (x >= scrcols)
+ x = scrcols - 1;
+ if (x < 0)
+ x = 0;
+ if (y >= scrrows)
+ y = scrrows - 1;
+ if (y < 0)
+ y = 0;
+}
+
+
+/*
+ * Keyboard support functions
+ */
+
+static int
+ite_pollforchar()
+{
+ int s;
+ register int intbits;
+
+ s = splhigh();
+
+ polledkey = -1;
+ adb_polling = 1;
+
+ /* pretend we're VIA interrupt dispatcher */
+ while (polledkey == -1) {
+ adb_intr_cuda();
+#if 0
+ intbits = via_reg(VIA1, vIFR);
+
+ if (intbits & V1IF_ADBRDY) {
+ mrg_adbintr();
+ via_reg(VIA1, vIFR) = V1IF_ADBRDY;
+ }
+ if (intbits & 0x10) {
+ mrg_pmintr();
+ via_reg(VIA1, vIFR) = 0x10;
+ }
+#endif
+ }
+
+ adb_polling = 0;
+
+ splx(s);
+
+ return polledkey;
+}
+
+
+/*
+ * Autoconfig attachment
+ */
+
+struct cfattach ite_ca = {
+ sizeof(struct device), itematch, iteattach
+};
+
+static int
+itematch(parent, cf, aux)
+ struct device *parent;
+ struct cfdata *cf;
+ void *aux;
+{
+ struct grf_attach_args *ga = aux;
+
+ if (strcmp(ga->ga_name, "ite") != 0)
+ return 0;
+
+ return 1;
+}
+
+static void
+iteattach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ printf("\n");
+}
+
+/*
+ * Tty handling functions
+ */
+
+int
+iteopen(dev, mode, devtype, p)
+ dev_t dev;
+ int mode;
+ int devtype;
+ struct proc *p;
+{
+ register struct tty *tp;
+ register int error;
+
+ dprintf("iteopen(): enter(0x%x)\n", (int)dev);
+
+ if (!ite_initted)
+ return (ENXIO);
+
+ if (ite_tty == NULL) {
+ tp = ite_tty = ttymalloc();
+ tty_attach(tp);
+ } else
+ tp = ite_tty;
+ if ((tp->t_state & (TS_ISOPEN | TS_XCLUDE)) == (TS_ISOPEN | TS_XCLUDE)
+ && p->p_ucred->cr_uid != 0)
+ return (EBUSY);
+
+ tp->t_oproc = itestart;
+ tp->t_param = NULL;
+ tp->t_dev = dev;
+ if ((tp->t_state & TS_ISOPEN) == 0) {
+ ttychars(tp);
+ tp->t_iflag = TTYDEF_IFLAG;
+ tp->t_oflag = TTYDEF_OFLAG;
+ tp->t_cflag = CS8 | CREAD;
+ tp->t_lflag = TTYDEF_LFLAG;
+ tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
+ tp->t_state = TS_ISOPEN | TS_CARR_ON;
+ ttsetwater(tp);
+ }
+
+ error = (*linesw[tp->t_line].l_open) (dev, tp);
+ tp->t_winsize.ws_row = scrrows;
+ tp->t_winsize.ws_col = scrcols;
+
+ dprintf("iteopen(): exit(%d)\n", error);
+ return (error);
+}
+
+int
+iteclose(dev, flag, mode, p)
+ dev_t dev;
+ int flag;
+ int mode;
+ struct proc *p;
+{
+ dprintf("iteclose: enter (%d)\n", (int)dev);
+
+ (*linesw[ite_tty->t_line].l_close) (ite_tty, flag);
+ ttyclose(ite_tty);
+#if 0
+ ttyfree(ite_tty);
+ ite_tty = (struct tty *) 0;
+#endif
+
+ dprintf("iteclose: exit\n");
+ return 0;
+}
+
+int
+iteread(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ dprintf("iteread: enter\n");
+ return (*linesw[ite_tty->t_line].l_read) (ite_tty, uio, flag);
+}
+
+int
+itewrite(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ dprintf("itewrite: enter\n");
+ return (*linesw[ite_tty->t_line].l_write) (ite_tty, uio, flag);
+}
+
+struct tty *
+itetty(dev)
+ dev_t dev;
+{
+ return (ite_tty);
+}
+
+int
+iteioctl(dev, cmd, addr, flag, p)
+ dev_t dev;
+ int cmd;
+ caddr_t addr;
+ int flag;
+ struct proc *p;
+{
+ register struct tty *tp = ite_tty;
+ int error;
+
+ dprintf("iteioctl: enter(%d, 0x%x)\n", cmd, cmd);
+
+ error = (*linesw[tp->t_line].l_ioctl) (tp, cmd, addr, flag, p);
+ if (error >= 0) {
+ dprintf("iteioctl: exit(%d)\n", error);
+ return (error);
+ }
+
+ error = ttioctl(tp, cmd, addr, flag, p);
+ if (error >= 0) {
+ dprintf("iteioctl: exit(%d)\n", error);
+ return (error);
+ }
+
+ switch (cmd) {
+ case ITEIOCRINGBELL:
+ /*return mac68k_ring_bell(bell_freq, bell_length, bell_volume);*/
+ case ITEIOCSETBELL:
+ {
+ struct bellparams *bp = (void *)addr;
+
+ /* Do some sanity checks. */
+ if (bp->freq < 10 || bp->freq > 40000)
+ return (EINVAL);
+ if (bp->len < 0 || bp->len > 3600)
+ return (EINVAL);
+ if (bp->vol < 0 || bp->vol > 100)
+ return (EINVAL);
+
+ bell_freq = bp->freq;
+ bell_length = bp->len;
+ bell_volume = bp->vol;
+ return (0);
+ }
+ case ITEIOCGETBELL:
+ {
+ struct bellparams *bp = (void *)addr;
+
+ bell_freq = bp->freq;
+ bell_length = bp->len;
+ bell_volume = bp->vol;
+ return (0);
+ }
+ }
+
+ dprintf("iteioctl: exit(ENOTTY)\n");
+ return (ENOTTY);
+}
+
+void
+itestart(register struct tty * tp)
+{
+ register int cc, s;
+
+ s = spltty();
+ if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) {
+ splx(s);
+ return;
+ }
+ tp->t_state |= TS_BUSY;
+
+ cc = tp->t_outq.c_cc;
+ splx(s);
+ erasecursor();
+ while (cc-- > 0)
+ ite_putchar(getc(&tp->t_outq));
+ drawcursor();
+
+ s = spltty();
+ tp->t_state &= ~TS_BUSY;
+ splx(s);
+}
+
+void
+itestop(struct tty * tp, int flag)
+{
+ int s;
+
+ s = spltty();
+ if (tp->t_state & TS_BUSY)
+ if ((tp->t_state & TS_TTSTOP) == 0)
+ tp->t_state |= TS_FLUSH;
+ splx(s);
+}
+
+int
+ite_intr(adb_event_t * event)
+{
+ static int shift = 0, control = 0, capslock = 0;
+ int key, press, val, state;
+ char str[10], *s;
+
+ key = event->u.k.key;
+ press = ADBK_PRESS(key);
+ val = ADBK_KEYVAL(key);
+
+/*printf("ite_intr: (%x %x ", press, val);*/
+ if (val == ADBK_SHIFT)
+ shift = press;
+ else if (val == ADBK_CAPSLOCK)
+ capslock = !capslock;
+ else if (val == ADBK_CONTROL)
+ control = press;
+ else if (press) {
+ switch (val) {
+ case ADBK_UP:
+ str[0] = '\e';
+ str[1] = 'O';
+ str[2] = 'A';
+ str[3] = '\0';
+ break;
+ case ADBK_DOWN:
+ str[0] = '\e';
+ str[1] = 'O';
+ str[2] = 'B';
+ str[3] = '\0';
+ break;
+ case ADBK_RIGHT:
+ str[0] = '\e';
+ str[1] = 'O';
+ str[2] = 'C';
+ str[3] = '\0';
+ break;
+ case ADBK_LEFT:
+ str[0] = '\e';
+ str[1] = 'O';
+ str[2] = 'D';
+ str[3] = '\0';
+ break;
+ default:
+ state = 0;
+ if (capslock && isealpha(keyboard[val][1]))
+ state = 1;
+ if (shift)
+ state = 1;
+ if (control)
+ state = 2;
+ str[0] = keyboard[val][state];
+ str[1] = '\0';
+ break;
+ }
+ if (adb_polling)
+ polledkey = str[0];
+ else
+ for (s = str; *s; s++)
+ (*linesw[ite_tty->t_line].l_rint)(*s, ite_tty);
+ }
+/*printf("%x) ", str[0]);*/
+ return 0;
+}
+/*
+ * Console functions
+ */
+
+void
+itecnprobe(struct consdev * cp)
+{
+ int maj, unit;
+ int l;
+ char type[32];
+ extern int console_node;
+
+ if (console_node == -1)
+ return;
+
+ l = OF_getprop(console_node, "device_type", type, sizeof(type));
+ if (l == -1 || l >= sizeof(type) - 1)
+ return;
+
+ if (strcmp(type, "display") != 0)
+ return;
+
+ /* locate the major number */
+ for (maj = 0; maj < nchrdev; maj++)
+ if (cdevsw[maj].d_open == iteopen)
+ break;
+
+ if (maj == nchrdev)
+ panic("itecnprobe(): did not find iteopen().");
+
+ unit = 0; /* hardcode first device as console. */
+
+ /* initialize required fields */
+ cp->cn_dev = makedev(maj, unit);
+ cp->cn_pri = CN_INTERNAL;
+}
+
+void
+itereset()
+{
+ width = videosize & 0xffff;
+ height = (videosize >> 16) & 0xffff;
+ scrrows = height / CHARHEIGHT;
+ scrcols = width / CHARWIDTH;
+
+ switch (videobitdepth) {
+ default:
+ case 1:
+ putpixel = putpixel1;
+ reversepixel = reversepixel1;
+ screenrowbytes = (width + 7) >> 3;
+ break;
+ case 2:
+ putpixel = putpixel2;
+ reversepixel = reversepixel1;
+ screenrowbytes = (width + 3) >> 2;
+ break;
+ case 4:
+ putpixel = putpixel4;
+ reversepixel = reversepixel1;
+ screenrowbytes = (width + 1) >> 1;
+ break;
+ case 8:
+ putpixel = putpixel8;
+ reversepixel = reversepixel1;
+ screenrowbytes = width;
+ break;
+ case 16:
+ putpixel = putpixel16;
+ reversepixel = reversepixel1;
+ screenrowbytes = width*2;
+ break;
+ case 32:
+ putpixel = putpixel32;
+ reversepixel = reversepixel1;
+ screenrowbytes = width*4;
+ break;
+ }
+
+ vt100_reset();
+}
+
+void
+itecninit(struct consdev * cp)
+{
+ int node, options;
+ int len;
+ vm_offset_t pa;
+ u_int reg[5];
+ extern int console_node;
+
+ if (ite_initted)
+ return;
+
+ node = console_node;
+ if (node == -1)
+ return;
+
+ OF_getprop(node, "width", &width, sizeof(width));
+ OF_getprop(node, "height", &height, sizeof(height));
+ OF_getprop(node, "depth", &videobitdepth, sizeof(videobitdepth));
+ OF_getprop(node, "linebytes", &videorowbytes, sizeof(videorowbytes));
+ OF_getprop(node, "assigned-addresses", reg, sizeof(reg));
+
+ /*
+ * XXX This should not be here.
+ *
+ * we cannot use kmem_alloc_...
+ */
+ len = videorowbytes * height;
+ pa = reg[2];
+ while (len > 0) {
+ pmap_enter(pmap_kernel(), pa, pa,
+ VM_PROT_READ|VM_PROT_WRITE, 1);
+ pa += NBPG;
+ len -= NBPG;
+ }
+
+ videoaddr = reg[2] + 0x400; /* XXX ATI only */
+
+ videosize = width | (height << 16);
+
+ ite_initted = 1;
+ itereset();
+ iteon(cp->cn_dev, 0);
+}
+
+int
+iteon(dev_t dev, int flags)
+{
+ if (!ite_initted)
+ return (-1);
+
+ erasecursor();
+ clear_screen(2);
+ drawcursor();
+ return 0;
+}
+
+int
+iteoff(dev_t dev, int flags)
+{
+ if (!ite_initted)
+ return (-1);
+
+ erasecursor();
+ clear_screen(2);
+ return 0;
+}
+
+int
+itecngetc(dev_t dev)
+{
+ /* Oh, man... */
+
+ return ite_pollforchar();
+}
+
+void
+itecnputc(dev_t dev, int c)
+{
+ erasecursor();
+ ite_putchar(c);
+ drawcursor();
+}
+
+struct consdev consdev_ite = {
+ itecnprobe,
+ itecninit,
+ itecngetc,
+ itecnputc,
+ nullcnpollc,
+};
diff --git a/sys/arch/macppc/dev/itevar.h b/sys/arch/macppc/dev/itevar.h
new file mode 100644
index 00000000000..d3412dd1576
--- /dev/null
+++ b/sys/arch/macppc/dev/itevar.h
@@ -0,0 +1,55 @@
+/* $NetBSD: itevar.h,v 1.1 1998/05/15 10:15:49 tsubai Exp $ */
+
+/*
+ * Copyright (c) 1995 Allen Briggs. 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 Allen Briggs.
+ * 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 <machine/adbsys.h>
+
+int ite_intr __P((adb_event_t *event));
+int iteon __P((dev_t dev, int flags));
+int iteoff __P((dev_t dev, int flags));
+void itereset __P((void));
+
+#ifndef CN_DEAD
+#include <dev/cons.h>
+#endif
+
+void itestop __P((struct tty * tp, int flag));
+void itestart __P((register struct tty * tp));
+int iteopen __P((dev_t dev, int mode, int devtype, struct proc * p));
+int iteclose __P((dev_t dev, int flag, int mode, struct proc * p));
+int iteread __P((dev_t dev, struct uio * uio, int flag));
+int itewrite __P((dev_t dev, struct uio * uio, int flag));
+int iteioctl __P((dev_t, int, caddr_t, int, struct proc *));
+struct tty *itetty __P((dev_t dev));
+
+void itecnprobe __P((struct consdev * cp));
+void itecninit __P((struct consdev * cp));
+int itecngetc __P((dev_t dev));
+void itecnputc __P((dev_t dev, int c));
diff --git a/sys/arch/macppc/dev/obio.c b/sys/arch/macppc/dev/obio.c
new file mode 100644
index 00000000000..6509076171f
--- /dev/null
+++ b/sys/arch/macppc/dev/obio.c
@@ -0,0 +1,102 @@
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcidevs.h>
+
+#include <dev/ofw/openfirm.h>
+
+#include <machine/autoconf.h>
+
+static void obio_attach __P((struct device *, struct device *, void *));
+static int obio_match __P((struct device *, struct cfdata *, void *));
+static int obio_print __P((void *, const char *));
+
+struct obio_softc {
+ struct device sc_dev;
+ int sc_node;
+};
+
+
+struct cfattach obio_ca = {
+ sizeof(struct obio_softc), obio_match, obio_attach
+};
+
+int
+obio_match(parent, cf, aux)
+ struct device *parent;
+ struct cfdata *cf;
+ void *aux;
+{
+ struct pci_attach_args *pa = aux;
+
+ if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_APPLE &&
+ PCI_PRODUCT(pa->pa_id) == 2)
+ return 1;
+
+ return 0;
+}
+
+/*
+ * Attach all the sub-devices we can find
+ */
+void
+obio_attach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct obio_softc *sc = (struct obio_softc *)self;
+ struct confargs ca;
+ int node, child, namelen;
+ u_int reg[20];
+ int intr[5];
+ char name[32];
+
+ node = OF_finddevice("/bandit/gc"); /* XXX */
+ sc->sc_node = node;
+
+ if (OF_getprop(node, "assigned-addresses", reg, sizeof(reg)) < 12)
+ return;
+ ca.ca_baseaddr = reg[2];
+
+ printf(": addr 0x%x\n", ca.ca_baseaddr);
+
+ for (child = OF_child(node); child; child = OF_peer(child)) {
+ namelen = OF_getprop(child, "name", name, sizeof(name));
+ if (namelen < 0)
+ continue;
+ if (namelen >= sizeof(name))
+ continue;
+
+ name[namelen] = 0;
+ ca.ca_name = name;
+ ca.ca_node = child;
+
+ ca.ca_nreg = OF_getprop(child, "reg", reg, sizeof(reg));
+ ca.ca_nintr = OF_getprop(child, "AAPL,interrupts", intr,
+ sizeof(intr));
+ ca.ca_reg = reg;
+ ca.ca_intr = intr;
+
+ config_found(self, &ca, obio_print);
+ }
+}
+
+int
+obio_print(aux, obio)
+ void *aux;
+ const char *obio;
+{
+ struct confargs *ca = aux;
+
+ if (obio)
+ printf("%s at %s", ca->ca_name, obio);
+
+ if (ca->ca_nreg > 0)
+ printf(" offset 0x%x", ca->ca_reg[0]);
+
+ return UNCONF;
+}
diff --git a/sys/arch/macppc/dev/viareg.h b/sys/arch/macppc/dev/viareg.h
new file mode 100644
index 00000000000..0cbc1f450f4
--- /dev/null
+++ b/sys/arch/macppc/dev/viareg.h
@@ -0,0 +1,250 @@
+/* $NetBSD: viareg.h,v 1.1 1998/05/15 10:15:49 tsubai Exp $ */
+
+/*-
+ * Copyright (C) 1993 Allen K. Briggs, Chris P. Caputo,
+ * Michael L. Finch, Bradley A. Grantham, and
+ * Lawrence A. Kesteloot
+ * 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 Alice Group.
+ * 4. The names of the Alice Group or any of its members may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE ALICE GROUP ``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 ALICE GROUP 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.
+ *
+ */
+/*
+
+ Prototype VIA control definitions
+
+ 06/04/92,22:33:57 BG Let's see what I can do.
+
+*/
+
+
+ /* VIA1 data register A */
+#define DA1I_vSCCWrReq 0x80
+#define DA1O_vPage2 0x40
+#define DA1I_CPU_ID1 0x40
+#define DA1O_vHeadSel 0x20
+#define DA1O_vOverlay 0x10
+#define DA1O_vSync 0x08
+#define DA1O_RESERVED2 0x04
+#define DA1O_RESERVED1 0x02
+#define DA1O_RESERVED0 0x01
+
+ /* VIA1 data register B */
+#define DB1I_Par_Err 0x80
+#define DB1O_vSndEnb 0x80
+#define DB1O_Par_Enb 0x40
+#define DB1O_vFDesk2 0x20
+#define DB1O_vFDesk1 0x10
+#define DB1I_vFDBInt 0x08
+#define DB1O_rTCEnb 0x04
+#define DB1O_rTCCLK 0x02
+#define DB1O_rTCData 0x01
+#define DB1I_rTCData 0x01
+
+ /* VIA2 data register A */
+#define DA2O_v2Ram1 0x80
+#define DA2O_v2Ram0 0x40
+#define DA2I_v2IRQ0 0x40
+#define DA2I_v2IRQE 0x20
+#define DA2I_v2IRQD 0x10
+#define DA2I_v2IRQC 0x08
+#define DA2I_v2IRQB 0x04
+#define DA2I_v2IRQA 0x02
+#define DA2I_v2IRQ9 0x01
+
+ /* VIA2 data register B */
+#define DB2O_v2VBL 0x80
+#define DB2O_Par_Test 0x80
+#define DB2I_v2SNDEXT 0x40
+#define DB2I_v2TM0A 0x20
+#define DB2I_v2TM1A 0x10
+#define DB2I_vFC3 0x08
+#define DB2O_vFC3 0x08
+#define DB2O_v2PowerOff 0x04
+#define DB2O_v2BusLk 0x02
+#define DB2O_vCDis 0x01
+#define DB2O_CEnable 0x01
+
+/*
+ * VIA1 interrupts
+ */
+#define VIA1_T1 6
+#define VIA1_T2 5
+#define VIA1_ADBCLK 4
+#define VIA1_ADBDATA 3
+#define VIA1_ADBRDY 2
+#define VIA1_VBLNK 1
+#define VIA1_ONESEC 0
+
+/* VIA1 interrupt bits */
+#define V1IF_IRQ 0x80
+#define V1IF_T1 (1 << VIA1_T1)
+#define V1IF_T2 (1 << VIA1_T2)
+#define V1IF_ADBCLK (1 << VIA1_ADBCLK)
+#define V1IF_ADBDATA (1 << VIA1_ADBDATA)
+#define V1IF_ADBRDY (1 << VIA1_ADBRDY)
+#define V1IF_VBLNK (1 << VIA1_VBLNK)
+#define V1IF_ONESEC (1 << VIA1_ONESEC)
+
+/*
+ * VIA2 interrupts
+ */
+#define VIA2_T1 6
+#define VIA2_T2 5
+#define VIA2_ASC 4
+#define VIA2_SCSIIRQ 3
+#define VIA2_EXPIRQ 2
+#define VIA2_SLOTINT 1
+#define VIA2_SCSIDRQ 0
+
+/* VIA2 interrupt bits */
+#define V2IF_IRQ 0x80
+#define V2IF_T1 (1 << VIA2_T1)
+#define V2IF_T2 (1 << VIA2_T2)
+#define V2IF_ASC (1 << VIA2_ASC)
+#define V2IF_SCSIIRQ (1 << VIA2_SCSIIRQ)
+#define V2IF_EXPIRQ (1 << VIA2_EXPIRQ)
+#define V2IF_SLOTINT (1 << VIA2_SLOTINT)
+#define V2IF_SCSIDRQ (1 << VIA2_SCSIDRQ)
+
+#define VIA1_INTS (V1IF_T1 | V1IF_ADBRDY)
+#define VIA2_INTS (V2IF_T1 | V2IF_ASC | V2IF_SCSIIRQ | V2IF_SLOTINT | \
+ V2IF_SCSIDRQ)
+
+#define RBV_INTS (V2IF_T1 | V2IF_ASC | V2IF_SCSIIRQ | V2IF_SLOTINT | \
+ V2IF_SCSIDRQ | V1IF_ADBRDY)
+
+#define ACR_T1LATCH 0x40
+
+extern volatile unsigned char *Via1Base;
+#define VIA1_addr Via1Base /* at PA 0x50f00000 */
+#define VIA2OFF 1 /* VIA2 addr = VIA1_addr * 0x2000 */
+#define RBVOFF 0x13 /* RBV addr = VIA1_addr * 0x13000 */
+
+#define VIA1 0
+extern int VIA2;
+
+ /* VIA interface registers */
+#define vBufA 0x1e00 /* register A */
+#define vBufB 0 /* register B */
+#define vDirA 0x0600 /* data direction register */
+#define vDirB 0x0400 /* data direction register */
+#define vT1C 0x0800
+#define vT1CH 0x0a00
+#define vT1L 0x0c00
+#define vT1LH 0x0e00
+#define vT2C 0x1000
+#define vT2CH 0x1200
+#define vSR 0x1400 /* shift register */
+#define vACR 0x1600 /* aux control register */
+#define vPCR 0x1800 /* peripheral control register */
+#define vIFR 0x1a00 /* interrupt flag register */
+#define vIER 0x1c00 /* interrupt enable register */
+
+ /* RBV interface registers */
+#define rBufB 0 /* register B */
+#define rBufA 2 /* register A */
+#define rIFR 0x3 /* interrupt flag register (writes?) */
+#define rIER 0x13 /* interrupt enable register */
+#define rMonitor 0x10 /* Monitor type */
+#define rSlotInt 0x12 /* Slot interrupt */
+
+ /* RBV monitor type flags and masks */
+#define RBVDepthMask 0x07 /* depth in bits */
+#define RBVMonitorMask 0x38 /* Type numbers */
+#define RBVOff 0x40 /* monitor turn off */
+#define RBVMonIDNone 0x38 /* What RBV actually has for no video */
+#define RBVMonIDOff 0x0 /* What rbv_vidstatus() returns for no video */
+#define RBVMonID15BWP 0x08 /* BW portrait */
+#define RBVMonIDRGB 0x10 /* color monitor */
+#define RBVMonIDRGB15 0x28 /* 15 inch RGB */
+#define RBVMonIDBW 0x30 /* No internal video */
+
+#define via_reg(v, r) (*(Via1Base + (r)))
+
+#include <machine/pio.h>
+
+static __inline void
+via_reg_and(ign, reg, val)
+ int ign, reg, val;
+{
+ volatile unsigned char *addr = Via1Base + reg;
+
+ out8(addr, in8(addr) & val);
+}
+
+static __inline void
+via_reg_or(ign, reg, val)
+ int ign, reg, val;
+{
+ volatile unsigned char *addr = Via1Base + reg;
+
+ out8(addr, in8(addr) | val);
+}
+
+static __inline void
+via_reg_xor(ign, reg, val)
+ int ign, reg, val;
+{
+ volatile unsigned char *addr = Via1Base + reg;
+
+ out8(addr, in8(addr) ^ val);
+}
+
+static __inline int
+read_via_reg(ign, reg)
+ int ign, reg;
+{
+ volatile unsigned char *addr = Via1Base + reg;
+
+ return in8(addr);
+}
+
+static __inline void
+write_via_reg(ign, reg, val)
+ int ign, reg, val;
+{
+ volatile unsigned char *addr = Via1Base + reg;
+
+ out8(addr, val);
+}
+
+
+
+#define vDirA_ADBState 0x30
+
+void via_init __P((void));
+int rbv_vidstatus __P((void));
+void via_shutdown __P((void));
+void via_set_modem __P((int));
+int add_nubus_intr __P((int, void (*) __P((void *, int)), void *));
+void enable_nubus_intr __P((void));
+void via1_register_irq __P((int, void (*)(void *), void *));
+void via2_register_irq __P((int, void (*)(void *), void *));
+
+extern void (*via1itab[7]) __P((void *));
+extern void (*via2itab[7]) __P((void *));
diff --git a/sys/arch/macppc/dev/z8530tty.c b/sys/arch/macppc/dev/z8530tty.c
new file mode 100644
index 00000000000..77d04b576be
--- /dev/null
+++ b/sys/arch/macppc/dev/z8530tty.c
@@ -0,0 +1,1463 @@
+/* $NetBSD: z8530tty.c,v 1.1 1998/05/15 10:15:49 tsubai Exp $ */
+
+/*-
+ * Copyright (c) 1993, 1994, 1995, 1996, 1997, 1998
+ * Charles M. Hannum. 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 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.
+ */
+
+/*
+ * Copyright (c) 1994 Gordon W. Ross
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * 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, Lawrence Berkeley Laboratory.
+ *
+ * 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.
+ *
+ * @(#)zs.c 8.1 (Berkeley) 7/19/93
+ */
+
+/*
+ * Zilog Z8530 Dual UART driver (tty interface)
+ *
+ * This is the "slave" driver that will be attached to
+ * the "zsc" driver for plain "tty" async. serial lines.
+ *
+ * Credits, history:
+ *
+ * The original version of this code was the sparc/dev/zs.c driver
+ * as distributed with the Berkeley 4.4 Lite release. Since then,
+ * Gordon Ross reorganized the code into the current parent/child
+ * driver scheme, separating the Sun keyboard and mouse support
+ * into independent child drivers.
+ *
+ * RTS/CTS flow-control support was a collaboration of:
+ * Gordon Ross <gwr@netbsd.org>,
+ * Bill Studenmund <wrstuden@loki.stanford.edu>
+ * Ian Dall <Ian.Dall@dsto.defence.gov.au>
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/device.h>
+#include <sys/conf.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/malloc.h>
+#include <sys/tty.h>
+#include <sys/time.h>
+#include <sys/kernel.h>
+#include <sys/syslog.h>
+
+#include <dev/ic/z8530reg.h>
+#include <machine/z8530var.h>
+
+#include "locators.h"
+
+/*
+ * How many input characters we can buffer.
+ * The port-specific var.h may override this.
+ * Note: must be a power of two!
+ */
+#ifndef ZSTTY_RING_SIZE
+#define ZSTTY_RING_SIZE 2048
+#endif
+
+/*
+ * Make this an option variable one can patch.
+ * But be warned: this must be a power of 2!
+ */
+u_int zstty_rbuf_size = ZSTTY_RING_SIZE;
+
+/* Stop input when 3/4 of the ring is full; restart when only 1/4 is full. */
+u_int zstty_rbuf_hiwat = (ZSTTY_RING_SIZE * 1) / 4;
+u_int zstty_rbuf_lowat = (ZSTTY_RING_SIZE * 3) / 4;
+
+struct zstty_softc {
+ struct device zst_dev; /* required first: base device */
+ struct tty *zst_tty;
+ struct zs_chanstate *zst_cs;
+
+ u_int zst_overflows,
+ zst_floods,
+ zst_errors;
+
+ int zst_hwflags, /* see z8530var.h */
+ zst_swflags; /* TIOCFLAG_SOFTCAR, ... <ttycom.h> */
+
+ u_int zst_r_hiwat,
+ zst_r_lowat;
+ u_char *volatile zst_rbget,
+ *volatile zst_rbput;
+ volatile u_int zst_rbavail;
+ u_char *zst_rbuf,
+ *zst_ebuf;
+
+ /*
+ * The transmit byte count and address are used for pseudo-DMA
+ * output in the hardware interrupt code. PDMA can be suspended
+ * to get pending changes done; heldtbc is used for this. It can
+ * also be stopped for ^S; this sets TS_TTSTOP in tp->t_state.
+ */
+ u_char *zst_tba; /* transmit buffer address */
+ u_int zst_tbc, /* transmit byte count */
+ zst_heldtbc; /* held tbc while xmission stopped */
+
+ /* Flags to communicate with zstty_softint() */
+ volatile u_char zst_rx_flags, /* receiver blocked */
+#define RX_TTY_BLOCKED 0x01
+#define RX_TTY_OVERFLOWED 0x02
+#define RX_IBUF_BLOCKED 0x04
+#define RX_IBUF_OVERFLOWED 0x08
+#define RX_ANY_BLOCK 0x0f
+ zst_tx_busy, /* working on an output chunk */
+ zst_tx_done, /* done with one output chunk */
+ zst_tx_stopped, /* H/W level stop (lost CTS) */
+ zst_st_check, /* got a status interrupt */
+ zst_rx_ready;
+};
+
+/* Macros to clear/set/test flags. */
+#define SET(t, f) (t) |= (f)
+#define CLR(t, f) (t) &= ~(f)
+#define ISSET(t, f) ((t) & (f))
+
+/* Definition of the driver for autoconfig. */
+#ifdef __BROKEN_INDIRECT_CONFIG
+static int zstty_match(struct device *, void *, void *);
+#else
+static int zstty_match(struct device *, struct cfdata *, void *);
+#endif
+static void zstty_attach(struct device *, struct device *, void *);
+
+struct cfattach zstty_ca = {
+ sizeof(struct zstty_softc), zstty_match, zstty_attach
+};
+
+extern struct cfdriver zstty_cd;
+
+struct zsops zsops_tty;
+
+/* Routines called from other code. */
+cdev_decl(zs); /* open, close, read, write, ioctl, stop, ... */
+
+static void zs_shutdown __P((struct zstty_softc *));
+static void zsstart __P((struct tty *));
+static int zsparam __P((struct tty *, struct termios *));
+static void zs_modem __P((struct zstty_softc *zst, int onoff));
+static int zshwiflow __P((struct tty *, int));
+static void zs_hwiflow __P((struct zstty_softc *));
+
+#define ZSUNIT(x) (minor(x) & 0x7ffff)
+#define ZSDIALOUT(x) (minor(x) & 0x80000)
+
+/*
+ * zstty_match: how is this zs channel configured?
+ */
+#ifdef __BROKEN_INDIRECT_CONFIG
+int
+zstty_match(parent, vcf, aux)
+ struct device *parent;
+ void *vcf, *aux;
+{
+ struct cfdata *cf = vcf;
+ struct zsc_attach_args *args = aux;
+
+ /* Exact match is better than wildcard. */
+ if (cf->cf_loc[ZSCCF_CHANNEL] == args->channel)
+ return 2;
+
+ /* This driver accepts wildcard. */
+ if (cf->cf_loc[ZSCCF_CHANNEL] == ZSCCF_CHANNEL_DEFAULT)
+ return 1;
+
+ return 0;
+}
+#else /* __BROKEN_INDIRECT_CONFIG */
+int
+zstty_match(parent, cf, aux)
+ struct device *parent;
+ struct cfdata *cf;
+ void *aux;
+{
+ struct zsc_attach_args *args = aux;
+
+ /* Exact match is better than wildcard. */
+ if (cf->cf_loc[ZSCCF_CHANNEL] == args->channel)
+ return 2;
+
+ /* This driver accepts wildcard. */
+ if (cf->cf_loc[ZSCCF_CHANNEL] == ZSCCF_CHANNEL_DEFAULT)
+ return 1;
+
+ return 0;
+}
+#endif /* __BROKEN_INDIRECT_CONFIG */
+
+void
+zstty_attach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+
+{
+ struct zsc_softc *zsc = (void *) parent;
+ struct zstty_softc *zst = (void *) self;
+ struct cfdata *cf = self->dv_cfdata;
+ struct zsc_attach_args *args = aux;
+ struct zs_chanstate *cs;
+ struct tty *tp;
+ int channel, s, tty_unit;
+ dev_t dev;
+
+ tty_unit = zst->zst_dev.dv_unit;
+ channel = args->channel;
+ cs = zsc->zsc_cs[channel];
+ cs->cs_private = zst;
+ cs->cs_ops = &zsops_tty;
+
+ zst->zst_cs = cs;
+ zst->zst_swflags = cf->cf_flags; /* softcar, etc. */
+ zst->zst_hwflags = args->hwflags;
+ dev = makedev(zs_major, tty_unit);
+
+ if (zst->zst_swflags)
+ printf(" flags 0x%x", zst->zst_swflags);
+
+ if (ISSET(zst->zst_hwflags, ZS_HWFLAG_CONSOLE))
+ printf(" (console)");
+ else {
+#ifdef KGDB
+ /*
+ * Allow kgdb to "take over" this port. Returns true
+ * if this serial port is in-use by kgdb.
+ */
+ if (zs_check_kgdb(cs, dev)) {
+ printf(" (kgdb)\n");
+ /*
+ * This is the kgdb port (exclusive use)
+ * so skip the normal attach code.
+ */
+ return;
+ }
+#endif
+ }
+ printf("\n");
+
+ tp = ttymalloc();
+ tp->t_oproc = zsstart;
+ tp->t_param = zsparam;
+ tp->t_hwiflow = zshwiflow;
+ tty_attach(tp);
+
+ zst->zst_tty = tp;
+ zst->zst_rbuf = malloc(zstty_rbuf_size << 1, M_DEVBUF, M_WAITOK);
+ zst->zst_ebuf = zst->zst_rbuf + (zstty_rbuf_size << 1);
+ /* Disable the high water mark. */
+ zst->zst_r_hiwat = 0;
+ zst->zst_r_lowat = 0;
+ zst->zst_rbget = zst->zst_rbput = zst->zst_rbuf;
+ zst->zst_rbavail = zstty_rbuf_size;
+
+ /* XXX - Do we need an MD hook here? */
+
+ /*
+ * Hardware init
+ */
+ if (ISSET(zst->zst_hwflags, ZS_HWFLAG_CONSOLE)) {
+ /* Call zsparam similar to open. */
+ struct termios t;
+
+ s = splzs();
+
+ /* Turn on interrupts. */
+ cs->cs_creg[1] = cs->cs_preg[1] = ZSWR1_RIE | ZSWR1_SIE;
+ zs_write_reg(cs, 1, cs->cs_creg[1]);
+
+ /* Fetch the current modem control status, needed later. */
+ cs->cs_rr0 = zs_read_csr(cs);
+
+ splx(s);
+
+ /* Setup the "new" parameters in t. */
+ t.c_ispeed = 0;
+ t.c_ospeed = cs->cs_defspeed;
+ t.c_cflag = cs->cs_defcflag;
+ /* Make sure zsparam will see changes. */
+ tp->t_ospeed = 0;
+ (void) zsparam(tp, &t);
+
+ s = splzs();
+
+ /* Make sure DTR is on now. */
+ zs_modem(zst, 1);
+
+ splx(s);
+ } else {
+ /* Not the console; may need reset. */
+ int reset;
+
+ reset = (channel == 0) ? ZSWR9_A_RESET : ZSWR9_B_RESET;
+
+ s = splzs();
+
+ zs_write_reg(cs, 9, reset);
+
+ /* Will raise DTR in open. */
+ zs_modem(zst, 0);
+
+ splx(s);
+ }
+}
+
+
+/*
+ * Return pointer to our tty.
+ */
+struct tty *
+zstty(dev)
+ dev_t dev;
+{
+ struct zstty_softc *zst;
+ int unit = ZSUNIT(dev);
+
+#ifdef DIAGNOSTIC
+ if (unit >= zstty_cd.cd_ndevs)
+ panic("zstty");
+#endif
+ zst = zstty_cd.cd_devs[unit];
+ return (zst->zst_tty);
+}
+
+
+void
+zs_shutdown(zst)
+ struct zstty_softc *zst;
+{
+ struct zs_chanstate *cs = zst->zst_cs;
+ struct tty *tp = zst->zst_tty;
+ int s;
+
+ s = splzs();
+
+ /* If we were asserting flow control, then deassert it. */
+ SET(zst->zst_rx_flags, RX_IBUF_BLOCKED);
+ zs_hwiflow(zst);
+
+ /* Clear any break condition set with TIOCSBRK. */
+ zs_break(cs, 0);
+
+ /*
+ * Hang up if necessary. Wait a bit, so the other side has time to
+ * notice even if we immediately open the port again.
+ */
+ if (ISSET(tp->t_cflag, HUPCL)) {
+ zs_modem(zst, 0);
+ (void) tsleep(cs, TTIPRI, ttclos, hz);
+ }
+
+ /* Turn off interrupts if not the console. */
+ if (ISSET(zst->zst_hwflags, ZS_HWFLAG_CONSOLE))
+ cs->cs_creg[1] = cs->cs_preg[1] = ZSWR1_RIE | ZSWR1_SIE;
+ else
+ cs->cs_creg[1] = cs->cs_preg[1] = 0;
+ zs_write_reg(cs, 1, cs->cs_creg[1]);
+
+ splx(s);
+}
+
+/*
+ * Open a zs serial (tty) port.
+ */
+int
+zsopen(dev, flags, mode, p)
+ dev_t dev;
+ int flags;
+ int mode;
+ struct proc *p;
+{
+ int unit = ZSUNIT(dev);
+ struct zstty_softc *zst;
+ struct zs_chanstate *cs;
+ struct tty *tp;
+ int s, s2;
+ int error;
+
+ if (unit >= zstty_cd.cd_ndevs)
+ return (ENXIO);
+ zst = zstty_cd.cd_devs[unit];
+ if (zst == 0)
+ return (ENXIO);
+ tp = zst->zst_tty;
+ cs = zst->zst_cs;
+
+ /* If KGDB took the line, then tp==NULL */
+ if (tp == NULL)
+ return (EBUSY);
+
+ if (ISSET(tp->t_state, TS_ISOPEN) &&
+ ISSET(tp->t_state, TS_XCLUDE) &&
+ p->p_ucred->cr_uid != 0)
+ return (EBUSY);
+
+ s = spltty();
+
+ /*
+ * Do the following iff this is a first open.
+ */
+ if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
+ struct termios t;
+
+ tp->t_dev = dev;
+
+ s2 = splzs();
+
+ /* Turn on interrupts. */
+ cs->cs_creg[1] = cs->cs_preg[1] = ZSWR1_RIE | ZSWR1_SIE;
+ zs_write_reg(cs, 1, cs->cs_creg[1]);
+
+ /* Fetch the current modem control status, needed later. */
+ cs->cs_rr0 = zs_read_csr(cs);
+
+ splx(s2);
+
+ /*
+ * Initialize the termios status to the defaults. Add in the
+ * sticky bits from TIOCSFLAGS.
+ */
+ t.c_ispeed = 0;
+ t.c_ospeed = cs->cs_defspeed;
+ t.c_cflag = cs->cs_defcflag;
+ if (ISSET(zst->zst_swflags, TIOCFLAG_CLOCAL))
+ SET(t.c_cflag, CLOCAL);
+ if (ISSET(zst->zst_swflags, TIOCFLAG_CRTSCTS))
+ SET(t.c_cflag, CRTSCTS);
+ if (ISSET(zst->zst_swflags, TIOCFLAG_CDTRCTS))
+ SET(t.c_cflag, CDTRCTS);
+ if (ISSET(zst->zst_swflags, TIOCFLAG_MDMBUF))
+ SET(t.c_cflag, MDMBUF);
+ /* Make sure zsparam will see changes. */
+ tp->t_ospeed = 0;
+ (void) zsparam(tp, &t);
+ /*
+ * Note: zsparam has done: cflag, ispeed, ospeed
+ * so we just need to do: iflag, oflag, lflag, cc
+ * For "raw" mode, just leave all zeros.
+ */
+ if (!ISSET(zst->zst_hwflags, ZS_HWFLAG_RAW)) {
+ tp->t_iflag = TTYDEF_IFLAG;
+ tp->t_oflag = TTYDEF_OFLAG;
+ tp->t_lflag = TTYDEF_LFLAG;
+ } else {
+ tp->t_iflag = 0;
+ tp->t_oflag = 0;
+ tp->t_lflag = 0;
+ }
+ ttychars(tp);
+ ttsetwater(tp);
+
+ s2 = splzs();
+
+ /*
+ * Turn on DTR. We must always do this, even if carrier is not
+ * present, because otherwise we'd have to use TIOCSDTR
+ * immediately after setting CLOCAL, which applications do not
+ * expect. We always assert DTR while the device is open
+ * unless explicitly requested to deassert it.
+ */
+ zs_modem(zst, 1);
+
+ /* Clear the input ring, and unblock. */
+ zst->zst_rbget = zst->zst_rbput = zst->zst_rbuf;
+ zst->zst_rbavail = zstty_rbuf_size;
+ zs_iflush(cs);
+ CLR(zst->zst_rx_flags, RX_ANY_BLOCK);
+ zs_hwiflow(zst);
+
+ splx(s2);
+ }
+
+ splx(s);
+
+ error = ttyopen(tp, ZSDIALOUT(dev), ISSET(flags, O_NONBLOCK));
+ if (error)
+ goto bad;
+
+ error = (*linesw[tp->t_line].l_open)(dev, tp);
+ if (error)
+ goto bad;
+
+ return (0);
+
+bad:
+ if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
+ /*
+ * We failed to open the device, and nobody else had it opened.
+ * Clean up the state as appropriate.
+ */
+ zs_shutdown(zst);
+ }
+
+ return (error);
+}
+
+/*
+ * Close a zs serial port.
+ */
+int
+zsclose(dev, flags, mode, p)
+ dev_t dev;
+ int flags;
+ int mode;
+ struct proc *p;
+{
+ struct zstty_softc *zst = zstty_cd.cd_devs[ZSUNIT(dev)];
+ struct tty *tp = zst->zst_tty;
+
+ /* XXX This is for cons.c. */
+ if (!ISSET(tp->t_state, TS_ISOPEN))
+ return 0;
+
+ (*linesw[tp->t_line].l_close)(tp, flags);
+ ttyclose(tp);
+
+ if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
+ /*
+ * Although we got a last close, the device may still be in
+ * use; e.g. if this was the dialout node, and there are still
+ * processes waiting for carrier on the non-dialout node.
+ */
+ zs_shutdown(zst);
+ }
+
+ return (0);
+}
+
+/*
+ * Read/write zs serial port.
+ */
+int
+zsread(dev, uio, flags)
+ dev_t dev;
+ struct uio *uio;
+ int flags;
+{
+ struct zstty_softc *zst = zstty_cd.cd_devs[ZSUNIT(dev)];
+ struct tty *tp = zst->zst_tty;
+
+ return ((*linesw[tp->t_line].l_read)(tp, uio, flags));
+}
+
+int
+zswrite(dev, uio, flags)
+ dev_t dev;
+ struct uio *uio;
+ int flags;
+{
+ struct zstty_softc *zst = zstty_cd.cd_devs[ZSUNIT(dev)];
+ struct tty *tp = zst->zst_tty;
+
+ return ((*linesw[tp->t_line].l_write)(tp, uio, flags));
+}
+
+int
+zsioctl(dev, cmd, data, flag, p)
+ dev_t dev;
+ u_long cmd;
+ caddr_t data;
+ int flag;
+ struct proc *p;
+{
+ struct zstty_softc *zst = zstty_cd.cd_devs[ZSUNIT(dev)];
+ struct zs_chanstate *cs = zst->zst_cs;
+ struct tty *tp = zst->zst_tty;
+ int error;
+ int s;
+
+ 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);
+
+#ifdef ZS_MD_IOCTL
+ error = ZS_MD_IOCTL;
+ if (error >= 0)
+ return (error);
+#endif /* ZS_MD_IOCTL */
+
+ error = 0;
+
+ s = splzs();
+
+ switch (cmd) {
+ case TIOCSBRK:
+ zs_break(cs, 1);
+ break;
+
+ case TIOCCBRK:
+ zs_break(cs, 0);
+ break;
+
+ case TIOCGFLAGS:
+ *(int *)data = zst->zst_swflags;
+ break;
+
+ case TIOCSFLAGS:
+ error = suser(p->p_ucred, &p->p_acflag);
+ if (error)
+ break;
+ zst->zst_swflags = *(int *)data;
+ break;
+
+ case TIOCSDTR:
+ zs_modem(zst, 1);
+ break;
+
+ case TIOCCDTR:
+ zs_modem(zst, 0);
+ break;
+
+ case TIOCMSET:
+ case TIOCMBIS:
+ case TIOCMBIC:
+ case TIOCMGET:
+ default:
+ error = ENOTTY;
+ break;
+ }
+
+ splx(s);
+
+ return (error);
+}
+
+/*
+ * Start or restart transmission.
+ */
+static void
+zsstart(tp)
+ struct tty *tp;
+{
+ struct zstty_softc *zst = zstty_cd.cd_devs[ZSUNIT(tp->t_dev)];
+ struct zs_chanstate *cs = zst->zst_cs;
+ int s;
+
+ s = spltty();
+ if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP))
+ goto out;
+ if (zst->zst_tx_stopped)
+ 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((caddr_t)&tp->t_outq);
+ }
+ selwakeup(&tp->t_wsel);
+ if (tp->t_outq.c_cc == 0)
+ goto out;
+ }
+
+ /* Grab the first contiguous region of buffer space. */
+ {
+ u_char *tba;
+ int tbc;
+
+ tba = tp->t_outq.c_cf;
+ tbc = ndqb(&tp->t_outq, 0);
+
+ (void) splzs();
+
+ zst->zst_tba = tba;
+ zst->zst_tbc = tbc;
+ }
+
+ SET(tp->t_state, TS_BUSY);
+ zst->zst_tx_busy = 1;
+
+#ifdef ZS_TXDMA
+ zs_dma_setup(cs, zst->zst_tba, zst->zst_tbc);
+#else
+ /* Enable transmit completion interrupts if necessary. */
+ if (!ISSET(cs->cs_preg[1], ZSWR1_TIE)) {
+ SET(cs->cs_preg[1], ZSWR1_TIE);
+ cs->cs_creg[1] = cs->cs_preg[1];
+ zs_write_reg(cs, 1, cs->cs_creg[1]);
+ }
+
+ /* Output the first character of the contiguous buffer. */
+ {
+ zs_write_data(cs, *zst->zst_tba);
+ zst->zst_tbc--;
+ zst->zst_tba++;
+ }
+#endif
+out:
+ splx(s);
+ return;
+}
+
+/*
+ * Stop output, e.g., for ^S or output flush.
+ */
+void
+zsstop(tp, flag)
+ struct tty *tp;
+ int flag;
+{
+ struct zstty_softc *zst = zstty_cd.cd_devs[ZSUNIT(tp->t_dev)];
+ int s;
+
+ s = splzs();
+ if (ISSET(tp->t_state, TS_BUSY)) {
+ /* Stop transmitting at the next chunk. */
+ zst->zst_tbc = 0;
+ zst->zst_heldtbc = 0;
+ if (!ISSET(tp->t_state, TS_TTSTOP))
+ SET(tp->t_state, TS_FLUSH);
+ }
+ splx(s);
+}
+
+/*
+ * Set ZS tty parameters from termios.
+ * XXX - Should just copy the whole termios after
+ * making sure all the changes could be done.
+ */
+static int
+zsparam(tp, t)
+ struct tty *tp;
+ struct termios *t;
+{
+ struct zstty_softc *zst = zstty_cd.cd_devs[ZSUNIT(tp->t_dev)];
+ struct zs_chanstate *cs = zst->zst_cs;
+ int ospeed, cflag;
+ u_char tmp3, tmp4, tmp5, tmp15;
+ int s, error;
+
+ ospeed = t->c_ospeed;
+ cflag = t->c_cflag;
+
+ /* Check requested parameters. */
+ if (ospeed < 0)
+ return (EINVAL);
+ if (t->c_ispeed && t->c_ispeed != ospeed)
+ return (EINVAL);
+
+ /*
+ * For the console, always force CLOCAL and !HUPCL, so that the port
+ * is always active.
+ */
+ if (ISSET(zst->zst_swflags, TIOCFLAG_SOFTCAR) ||
+ ISSET(zst->zst_hwflags, ZS_HWFLAG_CONSOLE)) {
+ SET(cflag, CLOCAL);
+ CLR(cflag, HUPCL);
+ }
+
+ /*
+ * Only whack the UART when params change.
+ * Some callers need to clear tp->t_ospeed
+ * to make sure initialization gets done.
+ */
+ if (tp->t_ospeed == ospeed &&
+ tp->t_cflag == cflag)
+ return (0);
+
+ /*
+ * Call MD functions to deal with changed
+ * clock modes or H/W flow control modes.
+ * The BRG divisor is set now. (reg 12,13)
+ */
+ error = zs_set_speed(cs, ospeed);
+ if (error)
+ return (error);
+ error = zs_set_modes(cs, cflag);
+ if (error)
+ return (error);
+
+ /*
+ * Block interrupts so that state will not
+ * be altered until we are done setting it up.
+ *
+ * Initial values in cs_preg are set before
+ * our attach routine is called. The master
+ * interrupt enable is handled by zsc.c
+ *
+ */
+ s = splzs();
+
+ cs->cs_rr0_mask = cs->cs_rr0_cts | cs->cs_rr0_dcd;
+ tmp15 = cs->cs_preg[15];
+#if 0
+ if (ISSET(cs->cs_rr0_mask, ZSRR0_DCD))
+ SET(tmp15, ZSWR15_DCD_IE);
+ else
+ CLR(tmp15, ZSWR15_DCD_IE);
+ if (ISSET(cs->cs_rr0_mask, ZSRR0_CTS))
+ SET(tmp15, ZSWR15_CTS_IE);
+ else
+ CLR(tmp15, ZSWR15_CTS_IE);
+#else
+ SET(tmp15, ZSWR15_DCD_IE | ZSWR15_CTS_IE);
+#endif
+ cs->cs_preg[15] = tmp15;
+
+ /* Recompute character size bits. */
+ tmp3 = cs->cs_preg[3];
+ tmp5 = cs->cs_preg[5];
+ CLR(tmp3, ZSWR3_RXSIZE);
+ CLR(tmp5, ZSWR5_TXSIZE);
+ switch (ISSET(cflag, CSIZE)) {
+ case CS5:
+ SET(tmp3, ZSWR3_RX_5);
+ SET(tmp5, ZSWR5_TX_5);
+ break;
+ case CS6:
+ SET(tmp3, ZSWR3_RX_6);
+ SET(tmp5, ZSWR5_TX_6);
+ break;
+ case CS7:
+ SET(tmp3, ZSWR3_RX_7);
+ SET(tmp5, ZSWR5_TX_7);
+ break;
+ case CS8:
+ SET(tmp3, ZSWR3_RX_8);
+ SET(tmp5, ZSWR5_TX_8);
+ break;
+ }
+ cs->cs_preg[3] = tmp3;
+ cs->cs_preg[5] = tmp5;
+
+ /*
+ * Recompute the stop bits and parity bits. Note that
+ * zs_set_speed() may have set clock selection bits etc.
+ * in wr4, so those must preserved.
+ */
+ tmp4 = cs->cs_preg[4];
+ CLR(tmp4, ZSWR4_SBMASK | ZSWR4_PARMASK);
+ if (ISSET(cflag, CSTOPB))
+ SET(tmp4, ZSWR4_TWOSB);
+ else
+ SET(tmp4, ZSWR4_ONESB);
+ if (!ISSET(cflag, PARODD))
+ SET(tmp4, ZSWR4_EVENP);
+ if (ISSET(cflag, PARENB))
+ SET(tmp4, ZSWR4_PARENB);
+ cs->cs_preg[4] = tmp4;
+
+ /* And copy to tty. */
+ tp->t_ispeed = 0;
+ tp->t_ospeed = ospeed;
+ tp->t_cflag = cflag;
+
+ /*
+ * If nothing is being transmitted, set up new current values,
+ * else mark them as pending.
+ */
+ if (!cs->cs_heldchange) {
+ if (zst->zst_tx_busy) {
+ zst->zst_heldtbc = zst->zst_tbc;
+ zst->zst_tbc = 0;
+ cs->cs_heldchange = 1;
+ } else
+ zs_loadchannelregs(cs);
+ }
+
+ if (!ISSET(cflag, CHWFLOW)) {
+ /* Disable the high water mark. */
+ zst->zst_r_hiwat = 0;
+ zst->zst_r_lowat = 0;
+ if (ISSET(zst->zst_rx_flags, RX_TTY_OVERFLOWED)) {
+ CLR(zst->zst_rx_flags, RX_TTY_OVERFLOWED);
+ zst->zst_rx_ready = 1;
+ cs->cs_softreq = 1;
+ }
+ if (ISSET(zst->zst_rx_flags, RX_TTY_BLOCKED|RX_IBUF_BLOCKED)) {
+ CLR(zst->zst_rx_flags, RX_TTY_BLOCKED|RX_IBUF_BLOCKED);
+ zs_hwiflow(zst);
+ }
+ } else {
+ zst->zst_r_hiwat = zstty_rbuf_hiwat;
+ zst->zst_r_lowat = zstty_rbuf_lowat;
+ }
+
+ splx(s);
+
+ /*
+ * Update the tty layer's idea of the carrier bit, in case we changed
+ * CLOCAL or MDMBUF. We don't hang up here; we only do that by
+ * explicit request.
+ */
+ (void) (*linesw[tp->t_line].l_modem)(tp, ISSET(cs->cs_rr0, ZSRR0_DCD));
+
+ if (!ISSET(cflag, CHWFLOW)) {
+ if (zst->zst_tx_stopped) {
+ zst->zst_tx_stopped = 0;
+ zsstart(tp);
+ }
+ }
+
+ return (0);
+}
+
+/*
+ * Raise or lower modem control (DTR/RTS) signals. If a character is
+ * in transmission, the change is deferred.
+ */
+static void
+zs_modem(zst, onoff)
+ struct zstty_softc *zst;
+ int onoff;
+{
+ struct zs_chanstate *cs = zst->zst_cs;
+
+ if (cs->cs_wr5_dtr == 0)
+ return;
+
+ if (onoff)
+ SET(cs->cs_preg[5], cs->cs_wr5_dtr);
+ else
+ CLR(cs->cs_preg[5], cs->cs_wr5_dtr);
+
+ if (!cs->cs_heldchange) {
+ if (zst->zst_tx_busy) {
+ zst->zst_heldtbc = zst->zst_tbc;
+ zst->zst_tbc = 0;
+ cs->cs_heldchange = 1;
+ } else
+ zs_loadchannelregs(cs);
+ }
+}
+
+/*
+ * Try to block or unblock input using hardware flow-control.
+ * This is called by kern/tty.c if MDMBUF|CRTSCTS is set, and
+ * if this function returns non-zero, the TS_TBLOCK flag will
+ * be set or cleared according to the "block" arg passed.
+ */
+int
+zshwiflow(tp, block)
+ struct tty *tp;
+ int block;
+{
+ struct zstty_softc *zst = zstty_cd.cd_devs[ZSUNIT(tp->t_dev)];
+ struct zs_chanstate *cs = zst->zst_cs;
+ int s;
+
+ if (cs->cs_wr5_rts == 0)
+ return (0);
+
+ s = splzs();
+ if (block) {
+ if (!ISSET(zst->zst_rx_flags, RX_TTY_BLOCKED)) {
+ SET(zst->zst_rx_flags, RX_TTY_BLOCKED);
+ zs_hwiflow(zst);
+ }
+ } else {
+ if (ISSET(zst->zst_rx_flags, RX_TTY_OVERFLOWED)) {
+ CLR(zst->zst_rx_flags, RX_TTY_OVERFLOWED);
+ zst->zst_rx_ready = 1;
+ cs->cs_softreq = 1;
+ }
+ if (ISSET(zst->zst_rx_flags, RX_TTY_BLOCKED)) {
+ CLR(zst->zst_rx_flags, RX_TTY_BLOCKED);
+ zs_hwiflow(zst);
+ }
+ }
+ splx(s);
+ return (1);
+}
+
+/*
+ * Internal version of zshwiflow
+ * called at splzs
+ */
+static void
+zs_hwiflow(zst)
+ struct zstty_softc *zst;
+{
+ struct zs_chanstate *cs = zst->zst_cs;
+
+ if (cs->cs_wr5_rts == 0)
+ return;
+
+ if (ISSET(zst->zst_rx_flags, RX_ANY_BLOCK)) {
+ CLR(cs->cs_preg[5], cs->cs_wr5_rts);
+ CLR(cs->cs_creg[5], cs->cs_wr5_rts);
+ } else {
+ SET(cs->cs_preg[5], cs->cs_wr5_rts);
+ SET(cs->cs_creg[5], cs->cs_wr5_rts);
+ }
+ zs_write_reg(cs, 5, cs->cs_creg[5]);
+}
+
+
+/****************************************************************
+ * Interface to the lower layer (zscc)
+ ****************************************************************/
+
+static void zstty_rxint __P((struct zs_chanstate *));
+static void zstty_txint __P((struct zs_chanstate *));
+static void zstty_stint __P((struct zs_chanstate *));
+
+#define integrate static inline
+static void zstty_softint __P((struct zs_chanstate *));
+integrate void zstty_rxsoft __P((struct zstty_softc *, struct tty *));
+integrate void zstty_txsoft __P((struct zstty_softc *, struct tty *));
+integrate void zstty_stsoft __P((struct zstty_softc *, struct tty *));
+static void zstty_diag __P((void *));
+
+/*
+ * receiver ready interrupt.
+ * called at splzs
+ */
+static void
+zstty_rxint(cs)
+ struct zs_chanstate *cs;
+{
+ struct zstty_softc *zst = cs->cs_private;
+ u_char *put, *end;
+ u_int cc;
+ u_char rr0, rr1, c;
+
+ end = zst->zst_ebuf;
+ put = zst->zst_rbput;
+ cc = zst->zst_rbavail;
+
+ while (cc > 0) {
+ /*
+ * First read the status, because reading the received char
+ * destroys the status of this char.
+ */
+ rr1 = zs_read_reg(cs, 1);
+ c = zs_read_data(cs);
+
+ if (ISSET(rr1, ZSRR1_FE | ZSRR1_DO | ZSRR1_PE)) {
+ /* Clear the receive error. */
+ zs_write_csr(cs, ZSWR0_RESET_ERRORS);
+ }
+
+ put[0] = c;
+ put[1] = rr1;
+ put += 2;
+ if (put >= end)
+ put = zst->zst_rbuf;
+ cc--;
+
+ rr0 = zs_read_csr(cs);
+ if (!ISSET(rr0, ZSRR0_RX_READY))
+ break;
+ }
+
+ /*
+ * Current string of incoming characters ended because
+ * no more data was available or we ran out of space.
+ * Schedule a receive event if any data was received.
+ * If we're out of space, turn off receive interrupts.
+ */
+ zst->zst_rbput = put;
+ zst->zst_rbavail = cc;
+ if (!ISSET(zst->zst_rx_flags, RX_TTY_OVERFLOWED)) {
+ zst->zst_rx_ready = 1;
+ cs->cs_softreq = 1;
+ }
+
+ /*
+ * See if we are in danger of overflowing a buffer. If
+ * so, use hardware flow control to ease the pressure.
+ */
+ if (!ISSET(zst->zst_rx_flags, RX_IBUF_BLOCKED) &&
+ cc < zst->zst_r_hiwat) {
+ SET(zst->zst_rx_flags, RX_IBUF_BLOCKED);
+ zs_hwiflow(zst);
+ }
+
+ /*
+ * If we're out of space, disable receive interrupts
+ * until the queue has drained a bit.
+ */
+ if (!cc) {
+ SET(zst->zst_rx_flags, RX_IBUF_OVERFLOWED);
+ CLR(cs->cs_preg[1], ZSWR1_RIE);
+ cs->cs_creg[1] = cs->cs_preg[1];
+ zs_write_reg(cs, 1, cs->cs_creg[1]);
+ }
+
+#if 0
+ printf("%xH%04d\n", zst->zst_rx_flags, zst->zst_rbavail);
+#endif
+}
+
+/*
+ * transmitter ready interrupt. (splzs)
+ */
+static void
+zstty_txint(cs)
+ struct zs_chanstate *cs;
+{
+ struct zstty_softc *zst = cs->cs_private;
+
+ /*
+ * If we've delayed a parameter change, do it now, and restart
+ * output.
+ */
+ if (cs->cs_heldchange) {
+ zs_loadchannelregs(cs);
+ cs->cs_heldchange = 0;
+ zst->zst_tbc = zst->zst_heldtbc;
+ zst->zst_heldtbc = 0;
+ }
+
+ /* Output the next character in the buffer, if any. */
+ if (zst->zst_tbc > 0) {
+ zs_write_data(cs, *zst->zst_tba);
+ zst->zst_tbc--;
+ zst->zst_tba++;
+ } else {
+ /* Disable transmit completion interrupts if necessary. */
+ if (ISSET(cs->cs_preg[1], ZSWR1_TIE)) {
+ CLR(cs->cs_preg[1], ZSWR1_TIE);
+ cs->cs_creg[1] = cs->cs_preg[1];
+ zs_write_reg(cs, 1, cs->cs_creg[1]);
+ }
+ if (zst->zst_tx_busy) {
+ zst->zst_tx_busy = 0;
+ zst->zst_tx_done = 1;
+ cs->cs_softreq = 1;
+ }
+ }
+}
+
+/*
+ * status change interrupt. (splzs)
+ */
+static void
+zstty_stint(cs)
+ struct zs_chanstate *cs;
+{
+ struct zstty_softc *zst = cs->cs_private;
+ u_char rr0, delta;
+
+ rr0 = zs_read_csr(cs);
+ zs_write_csr(cs, ZSWR0_RESET_STATUS);
+
+ /*
+ * Check here for console break, so that we can abort
+ * even when interrupts are locking up the machine.
+ */
+ if (ISSET(rr0, ZSRR0_BREAK) &&
+ ISSET(zst->zst_hwflags, ZS_HWFLAG_CONSOLE)) {
+ zs_abort(cs);
+ return;
+ }
+
+ delta = rr0 ^ cs->cs_rr0;
+ cs->cs_rr0 = rr0;
+ if (ISSET(delta, cs->cs_rr0_mask)) {
+ SET(cs->cs_rr0_delta, delta);
+
+ /*
+ * Stop output immediately if we lose the output
+ * flow control signal or carrier detect.
+ */
+ if (ISSET(~rr0, cs->cs_rr0_mask)) {
+ zst->zst_tbc = 0;
+ zst->zst_heldtbc = 0;
+ }
+
+ zst->zst_st_check = 1;
+ cs->cs_softreq = 1;
+ }
+}
+
+void
+zstty_diag(arg)
+ void *arg;
+{
+ struct zstty_softc *zst = arg;
+ int overflows, floods;
+ int s;
+
+ s = splzs();
+ overflows = zst->zst_overflows;
+ zst->zst_overflows = 0;
+ floods = zst->zst_floods;
+ zst->zst_floods = 0;
+ zst->zst_errors = 0;
+ splx(s);
+
+ log(LOG_WARNING, "%s: %d silo overflow%s, %d ibuf flood%s\n",
+ zst->zst_dev.dv_xname,
+ overflows, overflows == 1 ? "" : "s",
+ floods, floods == 1 ? "" : "s");
+}
+
+integrate void
+zstty_rxsoft(zst, tp)
+ struct zstty_softc *zst;
+ struct tty *tp;
+{
+ struct zs_chanstate *cs = zst->zst_cs;
+ int (*rint) __P((int c, struct tty *tp)) = linesw[tp->t_line].l_rint;
+ u_char *get, *end;
+ u_int cc, scc;
+ u_char rr1;
+ int code;
+ int s;
+
+ end = zst->zst_ebuf;
+ get = zst->zst_rbget;
+ scc = cc = zstty_rbuf_size - zst->zst_rbavail;
+
+ if (cc == zstty_rbuf_size) {
+ zst->zst_floods++;
+ if (zst->zst_errors++ == 0)
+ timeout(zstty_diag, zst, 60 * hz);
+ }
+
+ while (cc) {
+ code = get[0];
+ rr1 = get[1];
+ if (ISSET(rr1, ZSRR1_DO | ZSRR1_FE | ZSRR1_PE)) {
+ if (ISSET(rr1, ZSRR1_DO)) {
+ zst->zst_overflows++;
+ if (zst->zst_errors++ == 0)
+ timeout(zstty_diag, zst, 60 * hz);
+ }
+ if (ISSET(rr1, ZSRR1_FE))
+ SET(code, TTY_FE);
+ if (ISSET(rr1, ZSRR1_PE))
+ SET(code, TTY_PE);
+ }
+ if ((*rint)(code, tp) == -1) {
+ /*
+ * The line discipline's buffer is out of space.
+ */
+ if (!ISSET(zst->zst_rx_flags, RX_TTY_BLOCKED)) {
+ /*
+ * We're either not using flow control, or the
+ * line discipline didn't tell us to block for
+ * some reason. Either way, we have no way to
+ * know when there's more space available, so
+ * just drop the rest of the data.
+ */
+ get += cc << 1;
+ if (get >= end)
+ get -= zstty_rbuf_size << 1;
+ cc = 0;
+ } else {
+ /*
+ * Don't schedule any more receive processing
+ * until the line discipline tells us there's
+ * space available (through comhwiflow()).
+ * Leave the rest of the data in the input
+ * buffer.
+ */
+ SET(zst->zst_rx_flags, RX_TTY_OVERFLOWED);
+ }
+ break;
+ }
+ get += 2;
+ if (get >= end)
+ get = zst->zst_rbuf;
+ cc--;
+ }
+
+ if (cc != scc) {
+ zst->zst_rbget = get;
+ s = splzs();
+ cc = zst->zst_rbavail += scc - cc;
+ /* Buffers should be ok again, release possible block. */
+ if (cc >= zst->zst_r_lowat) {
+ if (ISSET(zst->zst_rx_flags, RX_IBUF_OVERFLOWED)) {
+ CLR(zst->zst_rx_flags, RX_IBUF_OVERFLOWED);
+ SET(cs->cs_preg[1], ZSWR1_RIE);
+ cs->cs_creg[1] = cs->cs_preg[1];
+ zs_write_reg(cs, 1, cs->cs_creg[1]);
+ }
+ if (ISSET(zst->zst_rx_flags, RX_IBUF_BLOCKED)) {
+ CLR(zst->zst_rx_flags, RX_IBUF_BLOCKED);
+ zs_hwiflow(zst);
+ }
+ }
+ splx(s);
+ }
+
+#if 0
+ printf("%xS%04d\n", zst->zst_rx_flags, zst->zst_rbavail);
+#endif
+}
+
+integrate void
+zstty_txsoft(zst, tp)
+ struct zstty_softc *zst;
+ struct tty *tp;
+{
+
+ CLR(tp->t_state, TS_BUSY);
+ if (ISSET(tp->t_state, TS_FLUSH))
+ CLR(tp->t_state, TS_FLUSH);
+ else
+ ndflush(&tp->t_outq, (int)(zst->zst_tba - tp->t_outq.c_cf));
+ (*linesw[tp->t_line].l_start)(tp);
+}
+
+integrate void
+zstty_stsoft(zst, tp)
+ struct zstty_softc *zst;
+ struct tty *tp;
+{
+ struct zs_chanstate *cs = zst->zst_cs;
+ u_char rr0, delta;
+ int s;
+
+ s = splzs();
+ rr0 = cs->cs_rr0;
+ delta = cs->cs_rr0_delta;
+ cs->cs_rr0_delta = 0;
+ splx(s);
+
+ if (ISSET(delta, cs->cs_rr0_dcd)) {
+ /*
+ * Inform the tty layer that carrier detect changed.
+ */
+ (void) (*linesw[tp->t_line].l_modem)(tp, ISSET(rr0, ZSRR0_DCD));
+ }
+
+ if (ISSET(delta, cs->cs_rr0_cts)) {
+ /* Block or unblock output according to flow control. */
+ if (ISSET(rr0, cs->cs_rr0_cts)) {
+ zst->zst_tx_stopped = 0;
+ (*linesw[tp->t_line].l_start)(tp);
+ } else {
+ zst->zst_tx_stopped = 1;
+ }
+ }
+}
+
+/*
+ * Software interrupt. Called at zssoft
+ *
+ * The main job to be done here is to empty the input ring
+ * by passing its contents up to the tty layer. The ring is
+ * always emptied during this operation, therefore the ring
+ * must not be larger than the space after "high water" in
+ * the tty layer, or the tty layer might drop our input.
+ *
+ * Note: an "input blockage" condition is assumed to exist if
+ * EITHER the TS_TBLOCK flag or zst_rx_blocked flag is set.
+ */
+static void
+zstty_softint(cs)
+ struct zs_chanstate *cs;
+{
+ struct zstty_softc *zst = cs->cs_private;
+ struct tty *tp = zst->zst_tty;
+ int s;
+
+ s = spltty();
+
+ if (zst->zst_rx_ready) {
+ zst->zst_rx_ready = 0;
+ zstty_rxsoft(zst, tp);
+ }
+
+ if (zst->zst_st_check) {
+ zst->zst_st_check = 0;
+ zstty_stsoft(zst, tp);
+ }
+
+ if (zst->zst_tx_done) {
+ zst->zst_tx_done = 0;
+ zstty_txsoft(zst, tp);
+ }
+
+ splx(s);
+}
+
+struct zsops zsops_tty = {
+ zstty_rxint, /* receive char available */
+ zstty_stint, /* external/status */
+ zstty_txint, /* xmit buffer empty */
+ zstty_softint, /* process software interrupt */
+};
+
+#ifdef ZS_TXDMA
+void
+zstty_txdma_int(arg)
+ void *arg;
+{
+ struct zs_chanstate *cs = arg;
+ struct zstty_softc *zst = cs->cs_private;
+
+ zst->zst_tba += zst->zst_tbc;
+ zst->zst_tbc = 0;
+
+ if (zst->zst_tx_busy) {
+ zst->zst_tx_busy = 0;
+ zst->zst_tx_done = 1;
+ cs->cs_softreq = 1;
+ }
+}
+#endif
diff --git a/sys/arch/macppc/dev/zs.c b/sys/arch/macppc/dev/zs.c
new file mode 100644
index 00000000000..6e2ba794bf7
--- /dev/null
+++ b/sys/arch/macppc/dev/zs.c
@@ -0,0 +1,1156 @@
+/* $NetBSD: zs.c,v 1.1 1998/05/15 10:15:49 tsubai Exp $ */
+
+/*
+ * Copyright (c) 1996 Bill Studenmund
+ * Copyright (c) 1995 Gordon W. Ross
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ * 4. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Gordon Ross
+ *
+ * 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.
+ */
+
+/*
+ * Zilog Z8530 Dual UART driver (machine-dependent part)
+ *
+ * Runs two serial lines per chip using slave drivers.
+ * Plain tty/async lines use the zs_async slave.
+ * Sun keyboard/mouse uses the zs_kbd/zs_ms slaves.
+ * Other ports use their own mice & keyboard slaves.
+ *
+ * Credits & history:
+ *
+ * With NetBSD 1.1, port-mac68k started using a port of the port-sparc
+ * (port-sun3?) zs.c driver (which was in turn based on code in the
+ * Berkeley 4.4 Lite release). Bill Studenmund did the port, with
+ * help from Allen Briggs and Gordon Ross <gwr@netbsd.org>. Noud de
+ * Brouwer field-tested the driver at a local ISP.
+ *
+ * Bill Studenmund and Gordon Ross then ported the machine-independant
+ * z8530 driver to work with port-mac68k. NetBSD 1.2 contained an
+ * intermediate version (mac68k using a local, patched version of
+ * the m.i. drivers), with NetBSD 1.3 containing a full version.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/device.h>
+#include <sys/conf.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/tty.h>
+#include <sys/time.h>
+#include <sys/kernel.h>
+#include <sys/syslog.h>
+
+#include <dev/cons.h>
+#include <dev/ofw/openfirm.h>
+#include <dev/ic/z8530reg.h>
+
+#include <machine/z8530var.h>
+#include <machine/autoconf.h>
+#include <machine/cpu.h>
+#include <machine/pio.h>
+
+/* Are these in a header file anywhere? */
+/* Booter flags interface */
+#define ZSMAC_RAW 0x01
+#define ZSMAC_LOCALTALK 0x02
+#define ZS_STD_BRG (57600*4)
+
+#include "zsc.h" /* get the # of zs chips defined */
+
+/*
+ * Some warts needed by z8530tty.c -
+ */
+int zs_def_cflag = (CREAD | CS8 | HUPCL);
+int zs_major = 12;
+
+/*
+ * abort detection on console will now timeout after iterating on a loop
+ * the following # of times. Cheep hack. Also, abort detection is turned
+ * off after a timeout (i.e. maybe there's not a terminal hooked up).
+ */
+#define ZSABORT_DELAY 3000000
+
+/* The layout of this is hardware-dependent (padding, order). */
+struct zschan {
+ volatile u_char zc_csr; /* ctrl,status, and indirect access */
+ u_char zc_xxx0[15];
+ volatile u_char zc_data; /* data */
+ u_char zc_xxx1[15];
+};
+struct zsdevice {
+ /* Yes, they are backwards. */
+ struct zschan zs_chan_b;
+ struct zschan zs_chan_a;
+};
+
+/* Saved PROM mappings */
+static struct zsdevice *zsaddr[2];
+
+/* Flags from cninit() */
+static int zs_hwflags[NZSC][2];
+/* Default speed for each channel */
+static int zs_defspeed[NZSC][2] = {
+ { 38400, /* tty00 */
+ 38400 }, /* tty01 */
+};
+/* console stuff */
+void *zs_conschan = 0;
+int zs_consunit;
+#ifdef ZS_CONSOLE_ABORT
+int zs_cons_canabort = 1;
+#else
+int zs_cons_canabort = 0;
+#endif /* ZS_CONSOLE_ABORT*/
+
+/* device to which the console is attached--if serial. */
+/* Mac stuff */
+
+static struct zschan *zs_get_chan_addr __P((int zsc_unit, int channel));
+void zs_init __P((void));
+int zs_cn_check_speed __P((int bps));
+
+/*
+ * Even though zsparam will set up the clock multiples, etc., we
+ * still set them here as: 1) mice & keyboards don't use zsparam,
+ * and 2) the console stuff uses these defaults before device
+ * attach.
+ */
+
+static u_char zs_init_reg[16] = {
+ 0, /* 0: CMD (reset, etc.) */
+ 0, /* 1: No interrupts yet. */
+ 0, /* IVECT */
+ ZSWR3_RX_8 | ZSWR3_RX_ENABLE,
+ ZSWR4_CLK_X16 | ZSWR4_ONESB | ZSWR4_EVENP,
+ ZSWR5_TX_8 | ZSWR5_TX_ENABLE,
+ 0, /* 6: TXSYNC/SYNCLO */
+ 0, /* 7: RXSYNC/SYNCHI */
+ 0, /* 8: alias for data port */
+ ZSWR9_MASTER_IE,
+ 0, /*10: Misc. TX/RX control bits */
+ ZSWR11_TXCLK_BAUD | ZSWR11_RXCLK_BAUD,
+ 1, /*12: BAUDLO (default=38400) */
+ 0, /*13: BAUDHI (default=38400) */
+ ZSWR14_BAUD_ENA,
+ ZSWR15_BREAK_IE | ZSWR15_DCD_IE,
+};
+
+struct zschan *
+zs_get_chan_addr(zs_unit, channel)
+ int zs_unit, channel;
+{
+ struct zsdevice *addr;
+ struct zschan *zc;
+
+ if (zs_unit >= 1)
+ return NULL;
+ addr = zsaddr[zs_unit];
+ if (addr == NULL)
+ return NULL;
+ if (channel == 0) {
+ zc = &addr->zs_chan_a;
+ } else {
+ zc = &addr->zs_chan_b;
+ }
+ return (zc);
+}
+
+
+/****************************************************************
+ * Autoconfig
+ ****************************************************************/
+
+/* Definition of the driver for autoconfig. */
+static int zsc_match __P((struct device *, struct cfdata *, void *));
+static void zsc_attach __P((struct device *, struct device *, void *));
+static int zsc_print __P((void *, const char *name));
+
+struct cfattach zsc_ca = {
+ sizeof(struct zsc_softc), zsc_match, zsc_attach
+};
+
+extern struct cfdriver zsc_cd;
+
+int zshard __P((void *));
+int zssoft __P((void *));
+#ifdef ZS_TXDMA
+static int zs_txdma_int __P((void *));
+#endif
+
+void zscnprobe __P((struct consdev *));
+void zscninit __P((struct consdev *));
+int zscngetc __P((dev_t));
+void zscnputc __P((dev_t, int));
+void zscnpollc __P((dev_t, int));
+
+/*
+ * Is the zs chip present?
+ */
+static int
+zsc_match(parent, cf, aux)
+ struct device *parent;
+ struct cfdata *cf;
+ void *aux;
+{
+ struct confargs *ca = aux;
+ int unit = cf->cf_unit;
+
+ if (strcmp(ca->ca_name, "escc") != 0)
+ return 0;
+
+ if (unit > 1)
+ return 0;
+
+ return 1;
+}
+
+/*
+ * Attach a found zs.
+ *
+ * Match slave number to zs unit number, so that misconfiguration will
+ * not set up the keyboard as ttya, etc.
+ */
+static void
+zsc_attach(parent, self, aux)
+ struct device *parent;
+ struct device *self;
+ void *aux;
+{
+ struct zsc_softc *zsc = (void *)self;
+ struct confargs *ca = aux;
+ struct zsc_attach_args zsc_args;
+ volatile struct zschan *zc;
+ struct xzs_chanstate *xcs;
+ struct zs_chanstate *cs;
+ int zsc_unit, channel;
+ int s, chip, theflags;
+ int node, intr[2][3];
+ u_int regs[6];
+
+ zsc_unit = zsc->zsc_dev.dv_unit;
+ node = ca->ca_node;
+
+ node = OF_child(node); /* ch-a */
+
+ for (channel = 0; channel < 2; channel++) {
+ OF_getprop(node, "AAPL,interrupts",
+ intr[channel], sizeof(intr[channel]));
+ OF_getprop(node, "reg", regs, sizeof(regs));
+ regs[0] += ca->ca_baseaddr;
+ regs[2] += ca->ca_baseaddr;
+ regs[4] += ca->ca_baseaddr;
+#ifdef ZS_TXDMA
+ zsc->zsc_txdmareg[channel] = mapiodev(regs[2], regs[3]);
+ zsc->zsc_txdmacmd[channel] =
+ dbdma_alloc(sizeof(dbdma_command_t) * 3);
+ bzero(zsc->zsc_txdmacmd[channel], sizeof(dbdma_command_t) * 3);
+ dbdma_reset(zsc->zsc_txdmareg[channel]);
+#endif
+ node = OF_peer(node); /* ch-b */
+ }
+ zsaddr[0] = mapiodev(regs[0], regs[1]);
+
+ printf(": irq %d,%d\n", intr[0][0], intr[1][0]);
+
+ /* Make sure everything's inited ok. */
+ if (zsaddr[zsc_unit] == NULL)
+ panic("zs_attach: zs%d not mapped\n", zsc_unit);
+
+ if ((zs_hwflags[zsc_unit][0] | zs_hwflags[zsc_unit][1]) &
+ ZS_HWFLAG_CONSOLE) {
+
+ zs_conschan = zs_get_chan_addr(zsc_unit, minor(cn_tab->cn_dev));
+ cn_tab->cn_getc = zscngetc;
+ cn_tab->cn_putc = zscnputc;
+ }
+
+ /*
+ * Initialize software state for each channel.
+ */
+ for (channel = 0; channel < 2; channel++) {
+ zsc_args.channel = channel;
+ zsc_args.hwflags = zs_hwflags[zsc_unit][channel];
+ xcs = &zsc->xzsc_xcs_store[channel];
+ cs = &xcs->xzs_cs;
+ zsc->zsc_cs[channel] = cs;
+
+ cs->cs_channel = channel;
+ cs->cs_private = NULL;
+ cs->cs_ops = &zsops_null;
+
+ zc = zs_get_chan_addr(zsc_unit, channel);
+ cs->cs_reg_csr = &zc->zc_csr;
+ cs->cs_reg_data = &zc->zc_data;
+
+ bcopy(zs_init_reg, cs->cs_creg, 16);
+ bcopy(zs_init_reg, cs->cs_preg, 16);
+
+ /* Current BAUD rate generator clock. */
+ cs->cs_brg_clk = ZS_STD_BRG; /* RTxC is 230400*16, so use 230400 */
+ cs->cs_defspeed = zs_defspeed[zsc_unit][channel];
+ cs->cs_defcflag = zs_def_cflag;
+
+ /* Make these correspond to cs_defcflag (-crtscts) */
+ cs->cs_rr0_dcd = ZSRR0_DCD;
+ cs->cs_rr0_cts = 0;
+ cs->cs_wr5_dtr = ZSWR5_DTR;
+ cs->cs_wr5_rts = 0;
+
+#ifdef __notyet__
+ cs->cs_slave_type = ZS_SLAVE_NONE;
+#endif
+
+ /* Define BAUD rate stuff. */
+ xcs->cs_clocks[0].clk = ZS_STD_BRG * 16;
+ xcs->cs_clocks[0].flags = ZSC_RTXBRG;
+ xcs->cs_clocks[1].flags =
+ ZSC_RTXBRG | ZSC_RTXDIV | ZSC_VARIABLE | ZSC_EXTERN;
+ xcs->cs_clocks[2].flags = ZSC_TRXDIV | ZSC_VARIABLE;
+ xcs->cs_clock_count = 3;
+ if (channel == 0) {
+ theflags = 0; /*mac68k_machine.modem_flags;*/
+ /*xcs->cs_clocks[1].clk = mac68k_machine.modem_dcd_clk;*/
+ /*xcs->cs_clocks[2].clk = mac68k_machine.modem_cts_clk;*/
+ xcs->cs_clocks[1].clk = 0;
+ xcs->cs_clocks[2].clk = 0;
+ } else {
+ theflags = 0; /*mac68k_machine.print_flags;*/
+ xcs->cs_clocks[1].flags = ZSC_VARIABLE;
+ /*
+ * Yes, we aren't defining ANY clock source enables for the
+ * printer's DCD clock in. The hardware won't let us
+ * use it. But a clock will freak out the chip, so we
+ * let you set it, telling us to bar interrupts on the line.
+ */
+ /*xcs->cs_clocks[1].clk = mac68k_machine.print_dcd_clk;*/
+ /*xcs->cs_clocks[2].clk = mac68k_machine.print_cts_clk;*/
+ xcs->cs_clocks[1].clk = 0;
+ xcs->cs_clocks[2].clk = 0;
+ }
+ if (xcs->cs_clocks[1].clk)
+ zsc_args.hwflags |= ZS_HWFLAG_NO_DCD;
+ if (xcs->cs_clocks[2].clk)
+ zsc_args.hwflags |= ZS_HWFLAG_NO_CTS;
+
+ /* Set defaults in our "extended" chanstate. */
+ xcs->cs_csource = 0;
+ xcs->cs_psource = 0;
+ xcs->cs_cclk_flag = 0; /* Nothing fancy by default */
+ xcs->cs_pclk_flag = 0;
+
+ if (theflags & ZSMAC_RAW) {
+ zsc_args.hwflags |= ZS_HWFLAG_RAW;
+ printf(" (raw defaults)");
+ }
+
+ /*
+ * XXX - This might be better done with a "stub" driver
+ * (to replace zstty) that ignores LocalTalk for now.
+ */
+ if (theflags & ZSMAC_LOCALTALK) {
+ printf(" shielding from LocalTalk");
+ cs->cs_defspeed = 1;
+ cs->cs_creg[ZSRR_BAUDLO] = cs->cs_preg[ZSRR_BAUDLO] = 0xff;
+ cs->cs_creg[ZSRR_BAUDHI] = cs->cs_preg[ZSRR_BAUDHI] = 0xff;
+ zs_write_reg(cs, ZSRR_BAUDLO, 0xff);
+ zs_write_reg(cs, ZSRR_BAUDHI, 0xff);
+ /*
+ * If we might have LocalTalk, then make sure we have the
+ * Baud rate low-enough to not do any damage.
+ */
+ }
+
+ /*
+ * We used to disable chip interrupts here, but we now
+ * do that in zscnprobe, just in case MacOS left the chip on.
+ */
+
+ xcs->cs_chip = chip;
+
+ /* Stash away a copy of the final H/W flags. */
+ xcs->cs_hwflags = zsc_args.hwflags;
+
+ /*
+ * Look for a child driver for this channel.
+ * The child attach will setup the hardware.
+ */
+ if (!config_found(self, (void *)&zsc_args, zsc_print)) {
+ /* No sub-driver. Just reset it. */
+ u_char reset = (channel == 0) ?
+ ZSWR9_A_RESET : ZSWR9_B_RESET;
+ s = splzs();
+ zs_write_reg(cs, 9, reset);
+ splx(s);
+ }
+ }
+
+ /* XXX - Now safe to install interrupt handlers. */
+ intr_establish(intr[0][0], IST_LEVEL, IPL_TTY, zshard, NULL);
+ intr_establish(intr[1][0], IST_LEVEL, IPL_TTY, zshard, NULL);
+#ifdef ZS_TXDMA
+ intr_establish(intr[0][1], IST_LEVEL, IPL_TTY, zs_txdma_int, (void *)0);
+ intr_establish(intr[1][1], IST_LEVEL, IPL_TTY, zs_txdma_int, (void *)1);
+#endif
+
+ /*
+ * Set the master interrupt enable and interrupt vector.
+ * (common to both channels, do it on A)
+ */
+ cs = zsc->zsc_cs[0];
+ s = splzs();
+ /* interrupt vector */
+ zs_write_reg(cs, 2, zs_init_reg[2]);
+ /* master interrupt control (enable) */
+ zs_write_reg(cs, 9, zs_init_reg[9]);
+ splx(s);
+}
+
+static int
+zsc_print(aux, name)
+ void *aux;
+ const char *name;
+{
+ struct zsc_attach_args *args = aux;
+
+ if (name != NULL)
+ printf("%s: ", name);
+
+ if (args->channel != -1)
+ printf(" channel %d", args->channel);
+
+ return UNCONF;
+}
+
+int
+zsmdioctl(cs, cmd, data)
+ struct zs_chanstate *cs;
+ u_long cmd;
+ caddr_t data;
+{
+ switch (cmd) {
+ default:
+ return (-1);
+ }
+ return (0);
+}
+
+void
+zsmd_setclock(cs)
+ struct zs_chanstate *cs;
+{
+ struct xzs_chanstate *xcs = (void *)cs;
+
+ if (cs->cs_channel != 0)
+ return;
+
+ /*
+ * If the new clock has the external bit set, then select the
+ * external source.
+ */
+ /*via_set_modem((xcs->cs_pclk_flag & ZSC_EXTERN) ? 1 : 0);*/
+}
+
+static int zssoftpending;
+
+/*
+ * Our ZS chips all share a common, autovectored interrupt,
+ * so we have to look at all of them on each interrupt.
+ */
+int
+zshard(arg)
+ void *arg;
+{
+ register struct zsc_softc *zsc;
+ register int unit, rval;
+
+ rval = 0;
+ for (unit = 0; unit < zsc_cd.cd_ndevs; unit++) {
+ zsc = zsc_cd.cd_devs[unit];
+ if (zsc == NULL)
+ continue;
+ rval |= zsc_intr_hard(zsc);
+ if ((zsc->zsc_cs[0]->cs_softreq) ||
+ (zsc->zsc_cs[1]->cs_softreq))
+ {
+ /* zsc_req_softint(zsc); */
+ /* We are at splzs here, so no need to lock. */
+ if (zssoftpending == 0) {
+ zssoftpending = 1;
+ setsoftserial();
+ }
+ }
+ }
+ return (rval);
+}
+
+/*
+ * Similar scheme as for zshard (look at all of them)
+ */
+int
+zssoft(arg)
+ void *arg;
+{
+ register struct zsc_softc *zsc;
+ register int unit;
+
+ /* This is not the only ISR on this IPL. */
+ if (zssoftpending == 0)
+ return (0);
+
+ /*
+ * The soft intr. bit will be set by zshard only if
+ * the variable zssoftpending is zero.
+ */
+ zssoftpending = 0;
+
+ for (unit = 0; unit < zsc_cd.cd_ndevs; ++unit) {
+ zsc = zsc_cd.cd_devs[unit];
+ if (zsc == NULL)
+ continue;
+ (void) zsc_intr_soft(zsc);
+ }
+ return (1);
+}
+
+#ifdef ZS_TXDMA
+int
+zs_txdma_int(arg)
+ void *arg;
+{
+ int ch = (int)arg;
+ struct zsc_softc *zsc;
+ struct zs_chanstate *cs;
+ int unit = 0; /* XXX */
+ extern int zstty_txdma_int();
+
+ zsc = zsc_cd.cd_devs[unit];
+ if (zsc == NULL)
+ panic("zs_txdma_int");
+
+ cs = zsc->zsc_cs[ch];
+ zstty_txdma_int(cs);
+
+ if (cs->cs_softreq) {
+ if (zssoftpending == 0) {
+ zssoftpending = 1;
+ setsoftserial();
+ }
+ }
+ return 1;
+}
+
+void
+zs_dma_setup(cs, pa, len)
+ struct zs_chanstate *cs;
+ caddr_t pa;
+ int len;
+{
+ struct zsc_softc *zsc;
+ dbdma_command_t *cmdp;
+ int ch = cs->cs_channel;
+
+ zsc = zsc_cd.cd_devs[ch];
+ cmdp = zsc->zsc_txdmacmd[ch];
+
+ DBDMA_BUILD(cmdp, DBDMA_CMD_OUT_LAST, 0, len, kvtop(pa),
+ DBDMA_INT_ALWAYS, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
+ cmdp++;
+ DBDMA_BUILD(cmdp, DBDMA_CMD_STOP, 0, 0, 0,
+ DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
+
+ __asm __volatile("eieio");
+
+ dbdma_start(zsc->zsc_txdmareg[ch], zsc->zsc_txdmacmd[ch]);
+}
+#endif
+
+#ifndef ZS_TOLERANCE
+#define ZS_TOLERANCE 51
+/* 5% in tenths of a %, plus 1 so that exactly 5% will be ok. */
+#endif
+
+/*
+ * check out a rate for acceptability from the internal clock
+ * source. Used in console config to validate a requested
+ * default speed. Placed here so that all the speed checking code is
+ * in one place.
+ *
+ * != 0 means ok.
+ */
+int
+zs_cn_check_speed(bps)
+ int bps; /* target rate */
+{
+ int tc, rate;
+
+ tc = BPS_TO_TCONST(ZS_STD_BRG, bps);
+ if (tc < 0)
+ return 0;
+ rate = TCONST_TO_BPS(ZS_STD_BRG, tc);
+ if (ZS_TOLERANCE > abs(((rate - bps)*1000)/bps))
+ return 1;
+ else
+ return 0;
+}
+
+/*
+ * Search through the signal sources in the channel, and
+ * pick the best one for the baud rate requested. Return
+ * a -1 if not achievable in tolerance. Otherwise return 0
+ * and fill in the values.
+ *
+ * This routine draws inspiration from the Atari port's zs.c
+ * driver in NetBSD 1.1 which did the same type of source switching.
+ * Tolerance code inspired by comspeed routine in isa/com.c.
+ *
+ * By Bill Studenmund, 1996-05-12
+ */
+int
+zs_set_speed(cs, bps)
+ struct zs_chanstate *cs;
+ int bps; /* bits per second */
+{
+ struct xzs_chanstate *xcs = (void *) cs;
+ int i, tc, tc0 = 0, tc1, s, sf = 0;
+ int src, rate0, rate1, err, tol;
+
+ if (bps == 0)
+ return (0);
+
+ src = -1; /* no valid source yet */
+ tol = ZS_TOLERANCE;
+
+ /*
+ * Step through all the sources and see which one matches
+ * the best. A source has to match BETTER than tol to be chosen.
+ * Thus if two sources give the same error, the first one will be
+ * chosen. Also, allow for the possability that one source might run
+ * both the BRG and the direct divider (i.e. RTxC).
+ */
+ for (i = 0; i < xcs->cs_clock_count; i++) {
+ if (xcs->cs_clocks[i].clk <= 0)
+ continue; /* skip non-existant or bad clocks */
+ if (xcs->cs_clocks[i].flags & ZSC_BRG) {
+ /* check out BRG at /16 */
+ tc1 = BPS_TO_TCONST(xcs->cs_clocks[i].clk >> 4, bps);
+ if (tc1 >= 0) {
+ rate1 = TCONST_TO_BPS(xcs->cs_clocks[i].clk >> 4, tc1);
+ err = abs(((rate1 - bps)*1000)/bps);
+ if (err < tol) {
+ tol = err;
+ src = i;
+ sf = xcs->cs_clocks[i].flags & ~ZSC_DIV;
+ tc0 = tc1;
+ rate0 = rate1;
+ }
+ }
+ }
+ if (xcs->cs_clocks[i].flags & ZSC_DIV) {
+ /*
+ * Check out either /1, /16, /32, or /64
+ * Note: for /1, you'd better be using a synchronized
+ * clock!
+ */
+ int b0 = xcs->cs_clocks[i].clk, e0 = abs(b0-bps);
+ int b1 = b0 >> 4, e1 = abs(b1-bps);
+ int b2 = b1 >> 1, e2 = abs(b2-bps);
+ int b3 = b2 >> 1, e3 = abs(b3-bps);
+
+ if (e0 < e1 && e0 < e2 && e0 < e3) {
+ err = e0;
+ rate1 = b0;
+ tc1 = ZSWR4_CLK_X1;
+ } else if (e0 > e1 && e1 < e2 && e1 < e3) {
+ err = e1;
+ rate1 = b1;
+ tc1 = ZSWR4_CLK_X16;
+ } else if (e0 > e2 && e1 > e2 && e2 < e3) {
+ err = e2;
+ rate1 = b2;
+ tc1 = ZSWR4_CLK_X32;
+ } else {
+ err = e3;
+ rate1 = b3;
+ tc1 = ZSWR4_CLK_X64;
+ }
+
+ err = (err * 1000)/bps;
+ if (err < tol) {
+ tol = err;
+ src = i;
+ sf = xcs->cs_clocks[i].flags & ~ZSC_BRG;
+ tc0 = tc1;
+ rate0 = rate1;
+ }
+ }
+ }
+#ifdef ZSMACDEBUG
+ zsprintf("Checking for rate %d. Found source #%d.\n",bps, src);
+#endif
+ if (src == -1)
+ return (EINVAL); /* no can do */
+
+ /*
+ * The M.I. layer likes to keep cs_brg_clk current, even though
+ * we are the only ones who should be touching the BRG's rate.
+ *
+ * Note: we are assuming that any ZSC_EXTERN signal source comes in
+ * on the RTxC pin. Correct for the mac68k obio zsc.
+ */
+ if (sf & ZSC_EXTERN)
+ cs->cs_brg_clk = xcs->cs_clocks[i].clk >> 4;
+ else
+ cs->cs_brg_clk = ZS_STD_BRG;
+
+ /*
+ * Now we have a source, so set it up.
+ */
+ s = splzs();
+ xcs->cs_psource = src;
+ xcs->cs_pclk_flag = sf;
+ bps = rate0;
+ if (sf & ZSC_BRG) {
+ cs->cs_preg[4] = ZSWR4_CLK_X16;
+ cs->cs_preg[11]= ZSWR11_RXCLK_BAUD | ZSWR11_TXCLK_BAUD;
+ if (sf & ZSC_PCLK) {
+ cs->cs_preg[14] = ZSWR14_BAUD_ENA | ZSWR14_BAUD_FROM_PCLK;
+ } else {
+ cs->cs_preg[14] = ZSWR14_BAUD_ENA;
+ }
+ tc = tc0;
+ } else {
+ cs->cs_preg[4] = tc0;
+ if (sf & ZSC_RTXDIV) {
+ cs->cs_preg[11] = ZSWR11_RXCLK_RTXC | ZSWR11_TXCLK_RTXC;
+ } else {
+ cs->cs_preg[11] = ZSWR11_RXCLK_TRXC | ZSWR11_TXCLK_TRXC;
+ }
+ cs->cs_preg[14]= 0;
+ tc = 0xffff;
+ }
+ /* Set the BAUD rate divisor. */
+ cs->cs_preg[12] = tc;
+ cs->cs_preg[13] = tc >> 8;
+ splx(s);
+
+#ifdef ZSMACDEBUG
+ zsprintf("Rate is %7d, tc is %7d, source no. %2d, flags %4x\n", \
+ bps, tc, src, sf);
+ zsprintf("Registers are: 4 %x, 11 %x, 14 %x\n\n",
+ cs->cs_preg[4], cs->cs_preg[11], cs->cs_preg[14]);
+#endif
+
+ cs->cs_preg[5] |= ZSWR5_RTS; /* Make sure the drivers are on! */
+
+ /* Caller will stuff the pending registers. */
+ return (0);
+}
+
+int
+zs_set_modes(cs, cflag)
+ struct zs_chanstate *cs;
+ int cflag; /* bits per second */
+{
+ struct xzs_chanstate *xcs = (void*)cs;
+ int s;
+
+ /*
+ * Make sure we don't enable hfc on a signal line we're ignoring.
+ * As we enable CTS interrupts only if we have CRTSCTS or CDTRCTS,
+ * this code also effectivly turns off ZSWR15_CTS_IE.
+ *
+ * Also, disable DCD interrupts if we've been told to ignore
+ * the DCD pin. Happens on mac68k because the input line for
+ * DCD can also be used as a clock input. (Just set CLOCAL.)
+ *
+ * If someone tries to turn an invalid flow mode on, Just Say No
+ * (Suggested by gwr)
+ */
+ if ((cflag & CDTRCTS) && (cflag & (CRTSCTS | MDMBUF)))
+ return (EINVAL);
+ if (xcs->cs_hwflags & ZS_HWFLAG_NO_DCD) {
+ if (cflag & MDMBUF)
+ return (EINVAL);
+ cflag |= CLOCAL;
+ }
+ if ((xcs->cs_hwflags & ZS_HWFLAG_NO_CTS) && (cflag & (CRTSCTS | CDTRCTS)))
+ return (EINVAL);
+
+ /*
+ * Output hardware flow control on the chip is horrendous:
+ * if carrier detect drops, the receiver is disabled, and if
+ * CTS drops, the transmitter is stoped IN MID CHARACTER!
+ * Therefore, NEVER set the HFC bit, and instead use the
+ * status interrupt to detect CTS changes.
+ */
+ s = splzs();
+ if ((cflag & (CLOCAL | MDMBUF)) != 0)
+ cs->cs_rr0_dcd = 0;
+ else
+ cs->cs_rr0_dcd = ZSRR0_DCD;
+ /*
+ * The mac hardware only has one output, DTR (HSKo in Mac
+ * parlance). In HFC mode, we use it for the functions
+ * typically served by RTS and DTR on other ports, so we
+ * have to fake the upper layer out some.
+ *
+ * CRTSCTS we use CTS as an input which tells us when to shut up.
+ * We make no effort to shut up the other side of the connection.
+ * DTR is used to hang up the modem.
+ *
+ * In CDTRCTS, we use CTS to tell us to stop, but we use DTR to
+ * shut up the other side.
+ */
+ if ((cflag & CRTSCTS) != 0) {
+ cs->cs_wr5_dtr = ZSWR5_DTR;
+ cs->cs_wr5_rts = 0;
+ cs->cs_rr0_cts = ZSRR0_CTS;
+ } else if ((cflag & CDTRCTS) != 0) {
+ cs->cs_wr5_dtr = 0;
+ cs->cs_wr5_rts = ZSWR5_DTR;
+ cs->cs_rr0_cts = ZSRR0_CTS;
+ } else if ((cflag & MDMBUF) != 0) {
+ cs->cs_wr5_dtr = 0;
+ cs->cs_wr5_rts = ZSWR5_DTR;
+ cs->cs_rr0_cts = ZSRR0_DCD;
+ } else {
+ cs->cs_wr5_dtr = ZSWR5_DTR;
+ cs->cs_wr5_rts = 0;
+ cs->cs_rr0_cts = 0;
+ }
+ splx(s);
+
+ /* Caller will stuff the pending registers. */
+ return (0);
+}
+
+
+/*
+ * Read or write the chip with suitable delays.
+ * MacII hardware has the delay built in.
+ * No need for extra delay. :-) However, some clock-chirped
+ * macs, or zsc's on serial add-on boards might need it.
+ */
+#define ZS_DELAY()
+
+u_char
+zs_read_reg(cs, reg)
+ struct zs_chanstate *cs;
+ u_char reg;
+{
+ u_char val;
+
+ out8(cs->cs_reg_csr, reg);
+ ZS_DELAY();
+ val = in8(cs->cs_reg_csr);
+ ZS_DELAY();
+ return val;
+}
+
+void
+zs_write_reg(cs, reg, val)
+ struct zs_chanstate *cs;
+ u_char reg, val;
+{
+ out8(cs->cs_reg_csr, reg);
+ ZS_DELAY();
+ out8(cs->cs_reg_csr, val);
+ ZS_DELAY();
+}
+
+u_char zs_read_csr(cs)
+ struct zs_chanstate *cs;
+{
+ register u_char val;
+
+ val = in8(cs->cs_reg_csr);
+ ZS_DELAY();
+ /* make up for the fact CTS is wired backwards */
+ val ^= ZSRR0_CTS;
+ return val;
+}
+
+void zs_write_csr(cs, val)
+ struct zs_chanstate *cs;
+ u_char val;
+{
+ /* Note, the csr does not write CTS... */
+ out8(cs->cs_reg_csr, val);
+ ZS_DELAY();
+}
+
+u_char zs_read_data(cs)
+ struct zs_chanstate *cs;
+{
+ register u_char val;
+
+ val = in8(cs->cs_reg_data);
+ ZS_DELAY();
+ return val;
+}
+
+void zs_write_data(cs, val)
+ struct zs_chanstate *cs;
+ u_char val;
+{
+ out8(cs->cs_reg_data, val);
+ ZS_DELAY();
+}
+
+/****************************************************************
+ * Console support functions (powermac specific!)
+ * Note: this code is allowed to know about the layout of
+ * the chip registers, and uses that to keep things simple.
+ * XXX - I think I like the mvme167 code better. -gwr
+ * XXX - Well :-P :-) -wrs
+ ****************************************************************/
+
+#define zscnpollc nullcnpollc
+cons_decl(zs);
+
+static void zs_putc __P((register volatile struct zschan *, int));
+static int zs_getc __P((register volatile struct zschan *));
+extern int zsopen __P(( dev_t dev, int flags, int mode, struct proc *p));
+
+/*
+ * Console functions.
+ */
+
+/*
+ * zscnprobe is the routine which gets called as the kernel is trying to
+ * figure out where the console should be. Each io driver which might
+ * be the console (as defined in mac68k/conf.c) gets probed. The probe
+ * fills in the consdev structure. Important parts are the device #,
+ * and the console priority. Values are CN_DEAD (don't touch me),
+ * CN_NORMAL (I'm here, but elsewhere might be better), CN_INTERNAL
+ * (the video, better than CN_NORMAL), and CN_REMOTE (pick me!)
+ *
+ * As the mac's a bit different, we do extra work here. We mainly check
+ * to see if we have serial echo going on. Also chould check for default
+ * speeds.
+ */
+
+/*
+ * Polled input char.
+ */
+int
+zs_getc(zc)
+ register volatile struct zschan *zc;
+{
+ register int s, c, rr0;
+
+ s = splhigh();
+ /* Wait for a character to arrive. */
+ do {
+ rr0 = in8(&zc->zc_csr);
+ ZS_DELAY();
+ } while ((rr0 & ZSRR0_RX_READY) == 0);
+
+ c = in8(&zc->zc_data);
+ ZS_DELAY();
+ splx(s);
+
+ /*
+ * This is used by the kd driver to read scan codes,
+ * so don't translate '\r' ==> '\n' here...
+ */
+ return (c);
+}
+
+/*
+ * Polled output char.
+ */
+void
+zs_putc(zc, c)
+ register volatile struct zschan *zc;
+ int c;
+{
+ register int s, rr0;
+ register long wait = 0;
+
+ s = splhigh();
+ /* Wait for transmitter to become ready. */
+ do {
+ rr0 = in8(&zc->zc_csr);
+ ZS_DELAY();
+ } while (((rr0 & ZSRR0_TX_READY) == 0) && (wait++ < 1000000));
+
+ if ((rr0 & ZSRR0_TX_READY) != 0) {
+ out8(&zc->zc_data, c);
+ ZS_DELAY();
+ }
+ splx(s);
+}
+
+
+/*
+ * Polled console input putchar.
+ */
+int
+zscngetc(dev)
+ dev_t dev;
+{
+ register volatile struct zschan *zc = zs_conschan;
+ register int c;
+
+ c = zs_getc(zc);
+ return (c);
+}
+
+/*
+ * Polled console output putchar.
+ */
+void
+zscnputc(dev, c)
+ dev_t dev;
+ int c;
+{
+ register volatile struct zschan *zc = zs_conschan;
+
+ zs_putc(zc, c);
+}
+
+/*
+ * Handle user request to enter kernel debugger.
+ */
+void
+zs_abort(cs)
+ struct zs_chanstate *cs;
+{
+ volatile struct zschan *zc = zs_conschan;
+ int rr0;
+ register long wait = 0;
+
+ if (zs_cons_canabort == 0)
+ return;
+
+ /* Wait for end of break to avoid PROM abort. */
+ do {
+ rr0 = in8(&zc->zc_csr);
+ ZS_DELAY();
+ } while ((rr0 & ZSRR0_BREAK) && (wait++ < ZSABORT_DELAY));
+
+ if (wait > ZSABORT_DELAY) {
+ zs_cons_canabort = 0;
+ /* If we time out, turn off the abort ability! */
+ }
+
+#ifdef DDB
+ Debugger();
+#endif
+}
+
+static int ofccngetc __P((dev_t));
+static void ofccnputc __P((dev_t, int));
+
+struct consdev consdev_zs = {
+ zscnprobe,
+ zscninit,
+ ofccngetc,
+ ofccnputc,
+ zscnpollc,
+};
+
+struct consdev *cn_tab = &consdev_zs;
+
+void
+zscnprobe(struct consdev * cp)
+{
+ int l;
+ char type[32];
+ extern int console_node;
+
+ if (console_node == -1)
+ return;
+
+ l = OF_getprop(console_node, "device_type", type, sizeof(type));
+ if (l == -1 || l >= sizeof(type) - 1)
+ return;
+
+ if (strcmp(type, "serial") == 0)
+ cp->cn_pri = CN_REMOTE;
+}
+
+
+static int stdin, stdout;
+
+void
+zscninit(cd)
+ struct consdev *cd;
+{
+ int chosen;
+ int sz;
+ int unit = 0;
+ char name[32];
+
+ chosen = OF_finddevice("/chosen");
+ if (chosen == -1)
+ return;
+
+ sz = OF_getprop(chosen, "stdin", &stdin, sizeof(stdin));
+ if (sz != sizeof(stdin))
+ return;
+
+ sz = OF_getprop(chosen, "stdout", &stdout, sizeof(stdout));
+ if (sz != sizeof(stdout))
+ return;
+
+ bzero(name, sizeof(name));
+ OF_getprop(stdout, "name", name, sizeof(name));
+
+ if (strcmp(name, "ch-b") == 0)
+ unit = 1;
+
+ zs_hwflags[0][unit] = ZS_HWFLAG_CONSOLE;
+
+ cd->cn_dev = makedev(zs_major, unit);
+}
+
+static int
+ofccngetc(dev)
+ dev_t dev;
+{
+ u_char ch;
+ int sz;
+
+ sz = OF_read(stdin, &ch, 1);
+ if (sz <= 0)
+ return -1;
+
+ return ch;
+}
+
+static void
+ofccnputc(dev, c)
+ dev_t dev;
+ int c;
+{
+ u_char ch = c;
+
+ OF_write(stdout, &ch, 1);
+}