Subject: maple driver
To: None <port-dreamcast@netbsd.org>
From: ITOH Yasufumi <itohy@netbsd.org>
List: port-dreamcast
Date: 10/05/2002 00:01:58
------- =_aaaaaaaaaa0
Content-Type: text/plain; charset="us-ascii"
Content-ID: <11441.1033743417.1@fmv.my.domain>
Content-Transfer-Encoding: 7bit

  Hello,

I'm now working on Maple (controller port) device drivers.
Any sort of comments and suggestions are welcome.
(Probably this needs more work.)

Some keywords are:
 - interrupt driven
 - support hot swapping
 - offer command interface to sub-drivers, not just periodic GETCOND

No function is added for now (but I'm working on memory card driver).
This patch also includes changes to sysasic driver.

Since the autoconfiguration framework is frequently changed recently,
the patch may not cleanly applied.

Regards,
-- 
ITOH Yasufumi

------- =_aaaaaaaaaa0
Content-Type: text/plain; name="maple.diff"; charset="us-ascii"
Content-ID: <11441.1033743417.2@fmv.my.domain>
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="maple.diff"

Index: conf/GENERIC
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/dreamcast/conf/GENERIC,v
retrieving revision 1.26
diff -u -r1.26 GENERIC
--- conf/GENERIC	2002/09/18 02:43:57	1.26
+++ conf/GENERIC	2002/10/04 14:32:46
@@ -39,10 +39,10 @@
 options 	HZ=100		# clock interrupt generates every 1/HZ sec
 #options 	NTP		# NTP phase/frequency locked loop
 
-#options 	KTRACE		# system call tracing via ktrace(1)
+options 	KTRACE		# system call tracing via ktrace(1)
 
 options 	USERCONF	# userconf(4) support
-#options	PIPE_SOCKETPAIR	# smaller, but slower pipe(2)
+#options 	PIPE_SOCKETPAIR	# smaller, but slower pipe(2)
 
 #options 	SYSVMSG		# System V-like message queues
 #options 	SYSVSEM		# System V-like semaphores
@@ -112,7 +112,7 @@
 shb*		at mainbus?
 
 # Serial Devices
-#options		SCIFCONSOLE
+#options 	SCIFCONSOLE
 options 	SCIFCN_SPEED=57600
 scif0		at shb?
 
@@ -120,8 +120,12 @@
 wsdisplay*	at pvr? console ?
 
 maple0		at shb?
+
 mkbd*		at maple? port ? subunit ?
-wskbd*		at mkbd? console ?
+wskbd*		at mkbd? mux 1 console ?
+
+mms*		at maple? port ? subunit ?
+wsmouse*	at mms? mux 0
 
 gdrom0		at shb?
 
@@ -143,3 +147,4 @@
 pseudo-device	rnd			# /dev/random and in-kernel generator
 pseudo-device	md		1	# memory disk device (ramdisk)
 pseudo-device	clockctl		# user control of clock subsystem
+pseudo-device	wsmux			# mouse & keyboard multiplexor
Index: dev/gdrom.c
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/dreamcast/dev/gdrom.c,v
retrieving revision 1.13
diff -u -r1.13 gdrom.c
--- dev/gdrom.c	2002/10/02 05:11:19	1.13
+++ dev/gdrom.c	2002/10/04 14:32:47
@@ -196,7 +196,7 @@
 	}
 
 	splx(s);
-	return (0);
+	return (1);
 }
 
 
@@ -381,8 +381,6 @@
 
 	sc = (struct gdrom_softc *)self;
 
-	printf(": SH4 IRL 9\n");
-
 	/*
 	 * Initialize and attach the disk structure.
 	 */
@@ -397,7 +395,8 @@
 	for (p = 0; p < 0x200000 / 4; p++)
 		x = ((__volatile u_int32_t *)0xa0000000)[p];
 
-	sysasic_intr_establish(SYSASIC_EVENT_GDROM, gdrom_intr, sc);
+	printf(": %s\n", sysasic_intr_string(IPL_BIO));
+	sysasic_intr_establish(SYSASIC_EVENT_GDROM, IPL_BIO, gdrom_intr, sc);
 }
 
 int
Index: dev/g2/gapspci_pci.c
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/dreamcast/dev/g2/gapspci_pci.c,v
retrieving revision 1.4
diff -u -r1.4 gapspci_pci.c
--- dev/g2/gapspci_pci.c	2002/05/15 17:09:04	1.4
+++ dev/g2/gapspci_pci.c	2002/10/04 14:32:47
@@ -199,7 +199,7 @@
 gaps_intr_string(void *v, pci_intr_handle_t ih)
 {
 
-	return ("SH4 IRL 11");
+	return sysasic_intr_string(IPL_NET);
 }
 
 void *
@@ -207,7 +207,7 @@
     int (*func)(void *), void *arg)
 {
 
-	return (sysasic_intr_establish(ih, func, arg));
+	return (sysasic_intr_establish(ih, IPL_NET, func, arg));
 }
 
 void
Index: dev/maple/maple.c
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/dreamcast/dev/maple/maple.c,v
retrieving revision 1.19
diff -u -r1.19 maple.c
--- dev/maple/maple.c	2002/10/02 15:45:16	1.19
+++ dev/maple/maple.c	2002/10/04 14:32:49
@@ -1,6 +1,42 @@
 /*	$NetBSD: maple.c,v 1.19 2002/10/02 15:45:16 thorpej Exp $	*/
 
 /*-
+ * Copyright (c) 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by ITOH Yasufumi.
+ *
+ * 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) 2001 Marcus Comstedt
  * All rights reserved.
  *
@@ -35,6 +71,8 @@
 #include <sys/param.h>
 #include <sys/device.h>
 #include <sys/fcntl.h>
+#include <sys/kernel.h>
+#include <sys/kthread.h>
 #include <sys/poll.h>
 #include <sys/select.h>
 #include <sys/proc.h>
@@ -46,6 +84,7 @@
 
 #include <machine/cpu.h>
 #include <machine/bus.h>
+#include <machine/sysasicvar.h>
 #include <sh3/pmap.h>
 
 #include <dreamcast/dev/maple/maple.h>
@@ -69,17 +108,38 @@
  */
 static int	maplematch(struct device *, struct cfdata *, void *);
 static void	mapleattach(struct device *, struct device *, void *);
+static void	maple_create_event_thread(void *);
+static void	maple_event_thread(void *);
 static int	mapleprint(void *, const char *);
 static int	maplesubmatch(struct device *, struct cfdata *, void *);
-static void	maple_attach_dev(struct maple_softc *, int, int);
+static char *	maple_unit_name(char *, int port, int subunit);
 static void	maple_begin_txbuf(struct maple_softc *);
 static int	maple_end_txbuf(struct maple_softc *);
-static void	maple_write_command(struct maple_softc *, int, int,
+static void	maple_queue_command(struct maple_softc *, struct maple_unit *,
+		    int command, int datalen, void *dataaddr);
+static void	maple_start(struct maple_softc *sc);
+static void	maple_start_poll(struct maple_softc *);
+static void	maple_write_command(struct maple_softc *, struct maple_unit *,
 		    int, int, void *);
+static void	maple_queue_cmds(struct maple_softc *,
+		    struct maple_cmdq_head *);
+struct maple_unit *maple_unit_probe(struct maple_softc *);
+static void	maple_unit_ping(struct maple_softc *);
 static void	maple_scanbus(struct maple_softc *);
+static int	maple_send_defered_periodic(struct maple_softc *);
+static void	maple_send_periodic(struct maple_softc *);
 static void	maple_callout(void *);
-static void	maple_send_commands(struct maple_softc *);
+static void	maple_remove_from_queues(struct maple_softc *,
+		    struct maple_unit *);
+static void	maple_check_unit_change(struct maple_softc *,
+		    struct maple_unit *);
+static int	maple_print(void *, const char *);
+static void	maple_attach_unit(struct maple_softc *, struct maple_unit *);
+static void	maple_detach_unit_nofix(struct maple_softc *,
+		    struct maple_unit *);
+static void	maple_detach_unit(struct maple_softc *, struct maple_unit *);
 static void	maple_check_responses(struct maple_softc *);
+static int	maple_intr(void *);
 
 int	maple_alloc_dma(size_t, vaddr_t *, paddr_t *);
 void	maple_free_dma(paddr_t, size_t);
@@ -90,7 +150,7 @@
 /*
  * Global variables.
  */
-int	maple_polling = 0;	/* Are we polling?  (Debugger mode) */
+int	maple_polling;		/* Are we polling?  (Debugger mode) */
 
 CFATTACH_DECL(maple, sizeof(struct maple_softc),
     maplematch, mapleattach, NULL, NULL);
@@ -113,32 +173,15 @@
 	return (1);
 }
 
-static void
-maple_attach_dev(struct maple_softc *sc, int port, int subunit)
+static char *
+maple_unit_name(char *buf, int port, int subunit)
 {
-	struct maple_attach_args ma;
-	u_int32_t func;
-	int f;
-	char oldxname[16];
-	
-	ma.ma_port = port;
-	ma.ma_subunit = subunit;
-	ma.ma_devinfo = &sc->sc_unit[port][subunit].devinfo;
-	ma.ma_function = 1;
-	func = ma.ma_devinfo->di_func;
 
-	mapleprint(&ma, sc->sc_dev.dv_xname);
-	printf("\n");
-	strcpy(oldxname, sc->sc_dev.dv_xname);
-	sprintf(sc->sc_dev.dv_xname, "maple%c", port+'A');
+	sprintf(buf, "maple%c", port + 'A');
 	if (subunit)
-		sprintf(sc->sc_dev.dv_xname+6, "%d", subunit);
+		sprintf(buf+6, "%d", subunit);
 
-	for (f = 0; f < 32; f++, ma.ma_function <<= 1)
-		if (func & ma.ma_function)
-			(void)config_found_sm(&sc->sc_dev, &ma,
-			    NULL, maplesubmatch);
-	strcpy(sc->sc_dev.dv_xname, oldxname);
+	return buf;
 }
 
 static void
@@ -146,6 +189,7 @@
 {
 
 	sc->sc_txlink = sc->sc_txpos = sc->sc_txbuf;
+	SIMPLEQ_INIT(&sc->sc_dmaq);
 }
 
 static int
@@ -153,7 +197,7 @@
 {
 	/* if no frame have been written, we can't mark the
 	   list end, and so the DMA must not be activated   */
-  	if (sc->sc_txpos == sc->sc_txbuf)
+	if (sc->sc_txpos == sc->sc_txbuf)
 		return (0);
 
 	*sc->sc_txlink |= 0x80000000;
@@ -161,37 +205,33 @@
 	return (1);
 }
 
-static int8_t subunit_code[] = { 0x20, 0x01, 0x02, 0x04, 0x08, 0x10 };
+static const int8_t subunit_code[] = { 0x20, 0x01, 0x02, 0x04, 0x08, 0x10 };
 
 static void
-maple_write_command(struct maple_softc *sc, int port, int subunit, int command,
-    int datalen, void *dataaddr)
+maple_queue_command(struct maple_softc *sc, struct maple_unit *u,
+	int command, int datalen, void *dataaddr)
 {
 	int to, from;
 	u_int32_t *p = sc->sc_txpos;
 
-	if ((port & ~(MAPLE_PORTS-1)) != 0 ||
-	    subunit < 0 || subunit >= MAPLE_SUBUNITS)
-		return;
-
-	/* Compute sender and recipient address */
-	from = port << 6;
-	to = from | subunit_code[subunit];
-
 	/* Max data length = 255 longs = 1020 bytes */
 	if (datalen > 255)
 		datalen = 255;
 	else if (datalen < 0)
 		datalen = 0;
 
+	/* Compute sender and recipient address */
+	from = u->port << 6;
+	to = from | subunit_code[u->subunit];
+
 	sc->sc_txlink = p;
 
 	/* Set length of packet and destination port (A-D) */
-	*p++ = datalen | (port << 16);
+	*p++ = datalen | (u->port << 16);
 
 	/* Write address to receive buffer where the response
 	   frame should be put */
-	*p++ = sc->sc_rxbuf_phys[port][subunit];
+	*p++ = u->u_rxbuf_phys;
 
 	/* Create the frame header.  The fields are assembled "backwards"
 	   because of the Maple Bus big-endianness.                       */
@@ -206,154 +246,779 @@
 	}
 
 	sc->sc_txpos = p;
+
+#if 0
+	u->u_rxbuf[0] = MAPLE_RESPONSE_NONE;
+#endif
+	SIMPLEQ_INSERT_TAIL(&sc->sc_dmaq, u, u_dmaq);
 }
 
 static void
-maple_scanbus(struct maple_softc *sc)
+maple_write_command(struct maple_softc *sc, struct maple_unit *u, int command,
+	int datalen, void *dataaddr)
 {
-	int p, s;
 
-	maple_polling = 1;
+	u->u_resendcnt = 0;		/* XXX */
+	u->u_command = command;
+	u->u_datalen = datalen;
+	u->u_dataaddr = dataaddr;
 
-	maple_begin_txbuf(sc);
+	maple_queue_command(sc, u, command, datalen, dataaddr);
+}
 
-	for (p = 0; p < MAPLE_PORTS; p++) {
-		maple_write_command(sc, p, 0, MAPLE_COMMAND_DEVINFO, 0, NULL);
+/*
+ * Called by drivers, including by callback functions.
+ * The "cataaddr" must not point at temporary storage like stack.
+ * Only one command (per function) is valid at a time.
+ */
+void
+maple_command(struct device *dev, struct maple_unit *u, int func,
+	int command, int datalen, void *dataaddr, int flags)
+{
+	struct maple_softc *sc = (void *) dev;
+	struct maple_func *fn;
+	int s;
+
+	KASSERT(func >= 0 && func < 32);
+	KASSERT(command);
+
+	KASSERT((flags & ~MAPLE_FLAG_CMD_PERIODIC_TIMING) == 0);
+
+	s = splmaple();
+#if 0	/* possibly improve performance? */
+	if (u->u_dma_stat == MAPLE_DMA_IDLE) {
+		maple_write_command(sc, u, command, datalen, dataaddr);
+		u->u_dma_stat = MAPLE_DMA_CMD;
+		u->u_dma_func = func;
+		splx(s);
+		return;
 	}
+#endif
 
-	if (maple_end_txbuf(sc)) {
+	fn = &u->u_func[func];
+#if 1 /*def DIAGNOSTIC*/
+	{char buf[16];
+	if (fn->f_cmdstat != MAPLE_CMDSTAT_NONE)
+		panic("maple_command: %s func %d: requesting more than one commands",
+		    maple_unit_name(buf, u->port, u->subunit), func);
+	}
+#endif
+	fn->f_command = command;
+	fn->f_datalen = datalen;
+	fn->f_dataaddr = dataaddr;
+	if (flags & MAPLE_FLAG_CMD_PERIODIC_TIMING) {
+		fn->f_cmdstat = MAPLE_CMDSTAT_PERIODIC;
+		TAILQ_INSERT_TAIL(&sc->sc_pcmdq, fn, f_cmdq);
+	} else {
+		fn->f_cmdstat = MAPLE_CMDSTAT_ASYNC;
+		TAILQ_INSERT_TAIL(&sc->sc_acmdq, fn, f_cmdq);
+		wakeup(&sc->sc_event);	/* wake for async event */
+	}
+	splx(s);
+}
 
-		MAPLE_DMAADDR = sc->sc_txbuf_phys;
-		MAPLE_STATE = 1;
-		while (MAPLE_STATE != 0)
-			;
-
-		for (p = 0; p < MAPLE_PORTS; p++)
-			if ((sc->sc_rxbuf[p][0][0] & 0xff) ==
-			    MAPLE_RESPONSE_DEVINFO)
-				sc->sc_port_units[p] =
-				    ((sc->sc_rxbuf[p][0][0] >> 15) & 0x3e) | 1;
-			else
-				sc->sc_port_units[p] = 0;
+/*
+ * Called by kernel thread.
+ */
+static void
+maple_queue_cmds(struct maple_softc *sc,
+	struct maple_cmdq_head *head)
+{
+	struct maple_func *fn, *nextfn;
+	struct maple_unit *u;
 
+	/*
+	 * Note: since the queue element may be queued immediately,
+	 *	 we can't use SIMPLE_FOREACH.
+	 */
+	fn = TAILQ_FIRST(head);
+	TAILQ_INIT(head);
+	for ( ; fn; fn = nextfn) {
+		nextfn = TAILQ_NEXT(fn, f_cmdq);
+
+		KASSERT(fn->f_cmdstat != MAPLE_CMDSTAT_NONE);
+		u = fn->f_unit;
+		if (u->u_dma_stat == MAPLE_DMA_IDLE) {
+			maple_write_command(sc, u,
+			    fn->f_command, fn->f_datalen, fn->f_dataaddr);
+			u->u_dma_stat = (fn->f_cmdstat == MAPLE_CMDSTAT_ASYNC)?
+			    MAPLE_DMA_ACMD : MAPLE_DMA_PCMD;
+			u->u_dma_func = fn->f_funcno;
+			fn->f_cmdstat = MAPLE_CMDSTAT_NONE;
+		} else {
+			/* try again */
+			if (fn->f_cmdstat == MAPLE_CMDSTAT_PERIODIC)
+				fn->f_cmdstat = MAPLE_CMDSTAT_PERIODIC_DEFERED;
+			/*
+			 * always add to async command queue
+			 * (process immediately)
+			 */
+			TAILQ_INSERT_TAIL(&sc->sc_acmdq, fn, f_cmdq);
+		}
+	}
+}
 
-		maple_begin_txbuf(sc);
+/* start DMA */
+static void
+maple_start(struct maple_softc *sc)
+{
+
+	MAPLE_DMAADDR = sc->sc_txbuf_phys;
+	MAPLE_STATE = 1;
+}
+
+/*
+ * start DMA -- wait until DMA done
+ * interrupt must be disabled beforehand
+ */
+static void
+maple_start_poll(struct maple_softc *sc)
+{
+
+	MAPLE_DMAADDR = sc->sc_txbuf_phys;
+	MAPLE_STATE = 1;
+	while (MAPLE_STATE != 0)
+		;
+}
 
-		for (p = 0; p < MAPLE_PORTS; p++) {
-			for (s = 0; s < MAPLE_SUBUNITS; s++) {
-				if (sc->sc_port_units[p] & (1 << s))
-					maple_write_command(sc, p, s,
-					    MAPLE_COMMAND_DEVINFO, 0, NULL);
+/* schedule probing a device */
+struct maple_unit *
+maple_unit_probe(struct maple_softc *sc)
+{
+	struct maple_unit *u;
+
+	if ((u = TAILQ_FIRST(&sc->sc_probeq)) != NULL) {
+		KASSERT(u->u_queuestat == MAPLE_QUEUE_PROBE);
+		maple_remove_from_queues(sc, u);
+		maple_write_command(sc, u, MAPLE_COMMAND_DEVINFO, 0, NULL);
+		u->u_dma_stat = MAPLE_DMA_PROBE;
+		/* u->u_dma_func = ignored; */
+	}
+	return u;
+}
+
+/* ARGSUSED */
+void
+maple_enable_unit_ping(struct device *dev, struct maple_unit *u,
+	int func, int enable)
+{
+#if 0	/* currently unused */
+	struct maple_softc *sc = dev;
+#endif
+
+	if (enable)
+		u->u_noping &= ~MAPLE_FUNC(func);
+	else
+		u->u_noping |= MAPLE_FUNC(func);
+}
+
+/* schedule pinging a device */
+static void
+maple_unit_ping(struct maple_softc *sc)
+{
+	struct maple_unit *u;
+	struct maple_func *fn;
+
+	if ((u = TAILQ_FIRST(&sc->sc_pingq)) != NULL) {
+		KASSERT(u->u_queuestat == MAPLE_QUEUE_PING);
+		maple_remove_from_queues(sc, u);
+		if (u->u_dma_stat == MAPLE_DMA_IDLE && u->u_noping == 0) {
+			if (u->subunit == 0) {
+				maple_write_command(sc, u,
+				    MAPLE_COMMAND_DEVINFO, 0, NULL);
+			} else {
+				fn = &u->u_func[u->u_ping_func];
+				fn->f_work = htonl(1 << u->u_ping_func);
+				maple_write_command(sc, u,
+				    MAPLE_COMMAND_GETCOND, 1, &fn->f_work);
 			}
+			u->u_dma_stat = MAPLE_DMA_PING;
+			/* u->u_dma_func = XXX; */
+		} else {
+			/* no need if periodic */
+			TAILQ_INSERT_TAIL(&sc->sc_pingq, u, u_q);
+			u->u_queuestat = MAPLE_QUEUE_PING;
 		}
+	}
+}
 
-		if (maple_end_txbuf(sc)) {
-			MAPLE_DMAADDR = sc->sc_txbuf_phys;
-			MAPLE_STATE = 1;
-			while (MAPLE_STATE != 0)
-				;
-
-			for (p = 0; p < MAPLE_PORTS; p++)
-				for (s = 0; s < MAPLE_SUBUNITS; s++)
-					if (sc->sc_port_units[p] & (1 << s)) {
-
-						if ((sc->sc_rxbuf[p][s][0] &
-						    0xff) ==
-						    MAPLE_RESPONSE_DEVINFO) {
-
-							u_int32_t *to_swap;
-							int i;
-		    
-							memcpy((to_swap =
-							    &sc->sc_unit[p][s].
-							    devinfo.di_func),
-							    sc->sc_rxbuf[p][s] +
-							    1,
-							    sizeof(struct
-								maple_devinfo));
-		    
-							for (i = 0; i < 4; i++,
-							    to_swap++)
-								*to_swap =
-								    ntohl
-								    (*to_swap);
-							maple_attach_dev(sc, p,
-							    s);
-						} else {
-
-							printf("%s: no response"
-							    " from port %d "
-							    " subunit %d\n",
-							    sc->sc_dev.dv_xname,
-							    p, s);
-							sc->sc_port_units[p] &=
-							    ~(1 << s);
-						}
-					}
-	    
+/*
+ * initial device attach
+ */
+static void
+maple_scanbus(struct maple_softc *sc)
+{
+	struct maple_unit *u;
+	int port;
+	int last_port, last_subunit;
+
+	KASSERT(cold && maple_polling);
+
+	/* probe all ports */
+	for (port = 0; port < MAPLE_PORTS; port++) {
+		u = &sc->sc_unit[port][0];
+#if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 2
+		{
+			char buf[16];
+			printf("%s: queued to probe 1\n",
+			    maple_unit_name(buf, u->port, u->subunit));
 		}
+#endif
+		TAILQ_INSERT_TAIL(&sc->sc_probeq, u, u_q);
+		u->u_queuestat = MAPLE_QUEUE_PROBE;
+	}
 
+	last_port = last_subunit = -1;
+	while ((u = TAILQ_FIRST(&sc->sc_probeq)) != NULL) {
+		/*
+		 * Check wrap condition
+		 */
+		if (u->port < last_port || u->subunit <= last_subunit)
+			break;
+		last_port = u->port;
+		if (u->port == MAPLE_PORTS - 1)
+			last_subunit = u->subunit;
+
+		maple_begin_txbuf(sc);
+		maple_unit_probe(sc);
+		maple_end_txbuf(sc);
+		maple_start_poll(sc);
+		maple_check_responses(sc);
 	}
+}
 
-	maple_polling = 0;
+void
+maple_enable_periodic(struct device *dev, struct maple_unit *u,
+	int func, int on)
+{
+	struct maple_softc *sc = (void *) dev;
+	struct maple_func *fn;
+
+	KASSERT(func >= 0 && func < 32);
 
+	fn = &u->u_func[func];
+
+	if (on) {
+		if (fn->f_periodic_stat == MAPLE_PERIODIC_NONE) {
+			TAILQ_INSERT_TAIL(&sc->sc_periodicq, fn, f_periodicq);
+			fn->f_periodic_stat = MAPLE_PERIODIC_INQ;
+			u->getcond_func_set |= MAPLE_FUNC(func);
+		}
+	} else {
+		if (fn->f_periodic_stat == MAPLE_PERIODIC_INQ)
+			TAILQ_REMOVE(&sc->sc_periodicq, fn, f_periodicq);
+		else if (fn->f_periodic_stat == MAPLE_PERIODIC_DEFERED)
+			TAILQ_REMOVE(&sc->sc_periodicdeferq, fn, f_periodicq);
+		fn->f_periodic_stat = MAPLE_PERIODIC_NONE;
+		u->getcond_func_set &= ~MAPLE_FUNC(func);
+	}
 }
 
+/*
+ * queue periodic GETCOND
+ */
+static int
+maple_send_defered_periodic(struct maple_softc *sc)
+{
+	struct maple_unit *u;
+	struct maple_func *fn, *nextfn;
+	int defer_remain = 0;
+
+	for (fn = TAILQ_FIRST(&sc->sc_periodicdeferq); fn; fn = nextfn) {
+		KASSERT(fn->f_periodic_stat == MAPLE_PERIODIC_DEFERED);
+
+		nextfn = TAILQ_NEXT(fn, f_periodicq);
+
+		u = fn->f_unit;
+		if (u->u_dma_stat != MAPLE_DMA_IDLE) {
+			defer_remain = 1;
+		} else {
+			TAILQ_REMOVE(&sc->sc_periodicdeferq, fn, f_periodicq);
+			TAILQ_INSERT_TAIL(&sc->sc_periodicq, fn, f_periodicq);
+			fn->f_periodic_stat = MAPLE_PERIODIC_INQ;
+
+			/*
+			 * queue periodic command
+			 */
+			fn->f_work = htonl(1 << fn->f_funcno);
+			maple_write_command(sc, u, MAPLE_COMMAND_GETCOND,
+			    1, &fn->f_work);
+			u->u_dma_stat = MAPLE_DMA_PERIODIC;
+			u->u_dma_func = fn->f_funcno;
+		}
+	}
+
+	return defer_remain;
+}
+
 static void
-maple_send_commands(struct maple_softc *sc)
+maple_send_periodic(struct maple_softc *sc)
 {
-	int p, s;
+	struct maple_unit *u;
+	struct maple_func *fn, *nextfn;
 
-	if (sc->maple_commands_pending || MAPLE_STATE != 0)
-		return;
+	for (fn = TAILQ_FIRST(&sc->sc_periodicq); fn; fn = nextfn) {
+		KASSERT(fn->f_periodic_stat == MAPLE_PERIODIC_INQ);
 
-	maple_begin_txbuf(sc);
+		nextfn = TAILQ_NEXT(fn, f_periodicq);
 
-	for (p = 0; p < MAPLE_PORTS; p++) {
-		for (s = 0; s < MAPLE_SUBUNITS; s++) {
-			if (sc->sc_unit[p][s].getcond_callback != NULL) {
-				u_int32_t func =
-				    ntohl(sc->sc_unit[p][s].getcond_func);
-	      
-				maple_write_command(sc, p, s,
-				    MAPLE_COMMAND_GETCOND, 1, &func);
-			}
+		u = fn->f_unit;
+		if (u->u_dma_stat != MAPLE_DMA_IDLE) {
+			/*
+			 * this can't be queued --- move to defered queue
+			 */
+			TAILQ_REMOVE(&sc->sc_periodicq, fn, f_periodicq);
+			TAILQ_INSERT_TAIL(&sc->sc_periodicdeferq, fn,
+			    f_periodicq);
+			fn->f_periodic_stat = MAPLE_PERIODIC_DEFERED;
+		} else {
+			/*
+			 * queue periodic command
+			 */
+			fn->f_work = htonl(1 << fn->f_funcno);
+			maple_write_command(sc, u, MAPLE_COMMAND_GETCOND,
+			    1, &fn->f_work);
+			u->u_dma_stat = MAPLE_DMA_PERIODIC;
+			u->u_dma_func = fn->f_funcno;
 		}
 	}
+}
 
-	if (!maple_end_txbuf(sc))
-		return;
+static void
+maple_remove_from_queues(struct maple_softc *sc, struct maple_unit *u)
+{
 
-	MAPLE_DMAADDR = sc->sc_txbuf_phys;
-	MAPLE_STATE = 1;
+	/* remove from queues */
+	if (u->u_queuestat == MAPLE_QUEUE_PROBE)
+		TAILQ_REMOVE(&sc->sc_probeq, u, u_q);
+	else if (u->u_queuestat == MAPLE_QUEUE_PING)
+		TAILQ_REMOVE(&sc->sc_pingq, u, u_q);
+#ifdef DIAGNOSTIC
+	else if (u->u_queuestat != MAPLE_QUEUE_NONE)
+		panic("maple_remove_from_queues: queuestat %d", u->u_queuestat);
+#endif
+#if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 2
+	if (u->u_queuestat != MAPLE_QUEUE_NONE) {
+		char buf[16];
+		printf("%s: dequeued\n",
+		    maple_unit_name(buf, u->port, u->subunit));
+	}
+#endif
 
-	sc->maple_commands_pending = 1;
+	u->u_queuestat = MAPLE_QUEUE_NONE;
 }
 
 static void
-maple_check_responses(struct maple_softc *sc)
+maple_check_unit_change(struct maple_softc *sc, struct maple_unit *u)
 {
-	int p, s;
+	struct maple_devinfo *newinfo = (void *) (u->u_rxbuf + 1);
+	struct maple_unit *u1;
+	int port, subunit;
+	u_int8_t unit_map;
+	int units, un;
+	int i;
+	int dif = 0;
+
+	port = u->port;
+	subunit = u->subunit;
+	unit_map = ((u_int8_t *) u->u_rxbuf)[2];
+	if (subunit == 0 && sc->sc_port_unit_map[port] != unit_map)
+		dif |= 2;
+	if (memcmp(&u->devinfo, newinfo, sizeof(struct maple_devinfo)) != 0)
+		dif |= 1;
+
+	if (dif == 0)
+		goto out;	/* no change */
+
+	units = ((unit_map & 0x1f) << 1) | 1;
+#if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 1
+	if (dif & 2) {
+		char buf[16];
+		printf("%s: unit_map 0x%x -> 0x%x (units 0x%x)\n",
+		    maple_unit_name(buf, u->port, u->subunit),
+		    sc->sc_port_unit_map[port], unit_map, units);
+	}
+#endif
+	if (dif & 1) {
+		/* unit inserted or changed */
+
+		/* first, detach devices if any attached */
+		if (subunit == 0) {
+			for (i = MAPLE_SUBUNITS - 1; i > 0; i--)
+				maple_detach_unit_nofix(sc,
+				    &sc->sc_unit[port][i]);
+		}
+		maple_detach_unit_nofix(sc, u);
+	} else {
+		/* check for unit change */
+		KASSERT(subunit == 0);
+		un = sc->sc_port_units[port] & ~units;
+
+		/* detach removed devices */
+		for (i = MAPLE_SUBUNITS - 1; i > 0; i--)
+			if (un & (1 << i))
+				maple_detach_unit_nofix(sc,
+				    &sc->sc_unit[port][i]);
+	}
 
-	if (!sc->maple_commands_pending || MAPLE_STATE != 0)
-		return;
+	if (dif & 1) {
+		/* attach this device */
+		u->devinfo = *newinfo;
+		maple_attach_unit(sc, u);
+	}
+
+	if (subunit == 0) {
+		sc->sc_port_unit_map[port] = unit_map;
 
-	for (p = 0; p < MAPLE_PORTS; p++) {
-		for (s = 0; s < MAPLE_SUBUNITS; s++) {
-			struct maple_unit *u = &sc->sc_unit[p][s];
-			if (u->getcond_callback != NULL &&
-			    (sc->sc_rxbuf[p][s][0] & 0xff) ==
-			    MAPLE_RESPONSE_DATATRF &&
-			    (sc->sc_rxbuf[p][s][0] >> 24) >= 1 &&
-			    htonl(sc->sc_rxbuf[p][s][1]) == u->getcond_func) {
-				(*u->getcond_callback)(u->getcond_data,
-				    (void *)(sc->sc_rxbuf[p][s] + 2),
-				    ((sc->sc_rxbuf[p][s][0] >> 22) & 1020) - 4);
+		/* schedule scanning child devices */
+		un = units & ~sc->sc_port_units[port];
+		for (i = MAPLE_SUBUNITS - 1; i > 0; i--)
+			if (un & (1 << i)) {
+				u1 = &sc->sc_unit[port][i];
+				maple_remove_from_queues(sc, u1);
+#if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 2
+				{
+					char buf[16];
+					printf("%s: queued to probe 2\n",
+					    maple_unit_name(buf, u1->port, u1->subunit));
+				}
+#endif
+				TAILQ_INSERT_HEAD(&sc->sc_probeq, u1, u_q);
+				u1->u_queuestat = MAPLE_QUEUE_PROBE;
 			}
+	}
+out:
+	maple_remove_from_queues(sc, u);
+#if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 2
+	{
+		char buf[16];
+		printf("%s: queued to ping\n",
+		    maple_unit_name(buf, u->port, u->subunit));
+	}
+#endif
+	TAILQ_INSERT_TAIL(&sc->sc_pingq, u, u_q);
+	u->u_queuestat = MAPLE_QUEUE_PING;
+}
+
+static int
+maple_print(void *aux, const char *str)
+{
+	struct maple_attach_args *ma = aux;
+
+#if 0	/* verbose */
+	if (str)
+		printf("%s", str);
+	printf(" function %d", ma->ma_function);
+
+	return UNCONF;
+#else	/* quiet */
+	if (!str)
+		printf(" function %d", ma->ma_function);
+
+	return QUIET;
+#endif
+}
+
+static void
+maple_attach_unit(struct maple_softc *sc, struct maple_unit *u)
+{
+	struct maple_attach_args ma;
+	u_int32_t func;
+	int f;
+	char oldxname[16];
+
+	ma.ma_unit = u;
+	ma.ma_devinfo = &u->devinfo;
+	func = ntohl(ma.ma_devinfo->di_func);
+
+	mapleprint(&ma, sc->sc_dev.dv_xname);
+	printf("\n");
+	strcpy(oldxname, sc->sc_dev.dv_xname);
+	maple_unit_name(sc->sc_dev.dv_xname, u->port, u->subunit);
+
+	for (f = 0; f < MAPLE_NFUNC; f++, ma.ma_function <<= 1) {
+		u->u_func[f].f_callback = NULL;
+		u->u_func[f].f_arg = NULL;
+		u->u_func[f].f_cmdstat = MAPLE_CMDSTAT_NONE;
+		u->u_func[f].f_dev = NULL;
+		if (func & MAPLE_FUNC(f)) {
+			ma.ma_function = f;
+			u->u_func[f].f_dev = config_found_sm(&sc->sc_dev, &ma,
+			    maple_print, maplesubmatch);
+			u->u_ping_func = f;	/* XXX using largest func */
 		}
 	}
+	strcpy(sc->sc_dev.dv_xname, oldxname);
 
-	sc->maple_commands_pending = 0;
+	sc->sc_port_units[u->port] |= 1 << u->subunit;
+}
+
+static void
+maple_detach_unit_nofix(struct maple_softc *sc, struct maple_unit *u)
+{
+	struct maple_func *fn;
+	struct device *dev;
+	int port;
+	int error;
+	int i;
+	char buf[16];
+
+	maple_remove_from_queues(sc, u);
+
+	port = u->port;
+	sc->sc_port_units[port] &= ~(1 << u->subunit);
+	for (fn = u->u_func; fn < &u->u_func[MAPLE_NFUNC]; fn++) {
+		if ((dev = fn->f_dev) != NULL) {
+#if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 1
+			printf("%s: detaching func %d\n",
+			    maple_unit_name(buf, port, u->subunit),
+			    fn->f_funcno);
+#endif
+
+			/*
+			 * Remove functions from command queue.
+			 */
+			switch (fn->f_cmdstat) {
+			case MAPLE_CMDSTAT_ASYNC:
+			case MAPLE_CMDSTAT_PERIODIC_DEFERED:
+				TAILQ_REMOVE(&sc->sc_acmdq, fn, f_cmdq);
+				break;
+			case MAPLE_CMDSTAT_PERIODIC:
+				TAILQ_REMOVE(&sc->sc_pcmdq, fn, f_cmdq);
+				break;
+			default:
+				break;
+			}
+
+			/*
+			 * Detach devices.
+			 */
+			if ((error = config_detach(fn->f_dev, DETACH_FORCE))) {
+				printf("%s: failed to detach %s (func %d), errno %d\n",
+				    maple_unit_name(buf, port, u->subunit),
+				    fn->f_dev->dv_xname, fn->f_funcno, error);
+			}
+		}
+
+		maple_enable_periodic(&sc->sc_dev, u, fn->f_funcno, 0);
+
+		fn->f_dev = NULL;
+		fn->f_callback = NULL;
+		fn->f_arg = NULL;
+		fn->f_cmdstat = MAPLE_CMDSTAT_NONE;
+	}
+	u->u_dma_stat = MAPLE_DMA_IDLE;
+	u->u_noping = 0;
+	/* u->u_dma_func = uninitialized; */
+	KASSERT(u->getcond_func_set == 0);
+	u->u_cnt_removal = 0;
+	memset(&u->devinfo, 0, sizeof(struct maple_devinfo));
+
+	if (u->subunit == 0) {
+		sc->sc_port_unit_map[port] = 0;
+		for (i = 1; i < MAPLE_SUBUNITS; i++)
+			maple_remove_from_queues(sc, &sc->sc_unit[port][i]);
+#if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 2
+		{
+			char buf[16];
+			printf("%s: queued to probe 3\n",
+			    maple_unit_name(buf, port, u->subunit));
+		}
+#endif
+		TAILQ_INSERT_TAIL(&sc->sc_probeq, u, u_q);
+		u->u_queuestat = MAPLE_QUEUE_PROBE;
+	}
+}
+
+static void
+maple_detach_unit(struct maple_softc *sc, struct maple_unit *u)
+{
+
+	maple_detach_unit_nofix(sc, u);
+	if (u->subunit != 0)
+		sc->sc_port_unit_map[u->port] &= ~(1 << (u->subunit - 1));
+}
+
+/*
+ * Process DMA results.
+ * Requires kernel context.
+ */
+static void
+maple_check_responses(struct maple_softc *sc)
+{
+	struct maple_unit *u, *nextu;
+	struct maple_func *fn;
+	u_int8_t response;
+	int func_code;
+	char buf[16];
+
+	/*
+	 * Note: since the queue element may be queued immediately,
+	 *	 we can't use SIMPLE_FOREACH.
+	 */
+	for (u = SIMPLEQ_FIRST(&sc->sc_dmaq), maple_begin_txbuf(sc);
+	    u; u = nextu) {
+		nextu = SIMPLEQ_NEXT(u, u_dmaq);
+
+		KASSERT(u->u_dma_stat != MAPLE_DMA_IDLE);
+
+		/*
+		 * check for retransmission
+		 */
+		if ((response = u->u_rxbuf[0])
+		    == (u_int8_t) MAPLE_RESPONSE_AGAIN) {
+#ifdef MAPLE_DEBUG
+			if (u->u_resendcnt == 0)
+				printf("%s: retrying\n",
+				    maple_unit_name(buf, u->port, u->subunit));
+#endif
+			u->u_resendcnt++;
+			maple_queue_command(sc, u, u->u_command, u->u_datalen,
+			    u->u_dataaddr);
+			continue;
+		}
+#ifdef MAPLE_DEBUG
+		if (u->u_resendcnt)
+			printf("%s: resendcnt %d\n",
+			    maple_unit_name(buf, u->port, u->subunit),
+			    u->u_resendcnt);
+#endif
+
+#if 0 /*def MAPLE_DEBUG*/
+		printf("%s: checking function %d\n",
+		    maple_unit_name(buf, u->port, u->subunit),
+		    u->u_dma_func);
+#endif
+		/*
+		 * call handler
+		 */
+		if (u->u_dma_stat == MAPLE_DMA_PERIODIC) {
+			/*
+			 * periodic GETCOND
+			 */
+			u->u_dma_stat = MAPLE_DMA_IDLE;
+			func_code = u->u_dma_func;
+			if (response == MAPLE_RESPONSE_DATATRF &&
+			    (u->u_rxbuf[0] >> 24) >= 1 &&
+			    ntohl(u->u_rxbuf[1]) == MAPLE_FUNC(func_code)) {
+				fn = &u->u_func[func_code];
+				if (fn->f_dev)
+					(*fn->f_callback)(fn->f_arg,
+					    (void *)u->u_rxbuf,
+					    (u->u_rxbuf[0] >> 22) & 1020,
+					    MAPLE_FLAG_PERIODIC);
+				u->u_cnt_removal = 0;
+			} else if (response == (u_int8_t)MAPLE_RESPONSE_NONE) {
+				/* XXX OK? */
+				/* detach */
+#if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 2
+				printf("%s: func: %d: periodic response %d\n",
+				    maple_unit_name(buf, u->port, u->subunit),
+				    u->u_dma_func,
+				    response);
+#endif
+				/*
+				 * Some 3rd party devices sometimes
+				 * do not respond.
+				 */
+				if (++u->u_cnt_removal > MAPLE_REMOVAL_CNT)
+					maple_detach_unit(sc, u);
+			}
+			/* XXX check unexpected conditions? */
+		} else if (u->u_dma_stat == MAPLE_DMA_PROBE) {
+			KASSERT(u->u_queuestat == MAPLE_QUEUE_NONE);
+			u->u_dma_stat = MAPLE_DMA_IDLE;
+			switch (response) {
+			default:
+			case (u_int8_t)MAPLE_RESPONSE_NONE:
+				if (u->subunit != 0) {
+					printf("%s: no response\n",
+					    maple_unit_name(buf,
+						u->port, u->subunit));
+				} else {
+					/* probe again */
+#if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 2
+					{
+						char buf[16];
+						printf("%s: queued to probe 4\n",
+						    maple_unit_name(buf, u->port, u->subunit));
+					}
+#endif
+					TAILQ_INSERT_TAIL(&sc->sc_probeq, u,
+					    u_q);
+					u->u_queuestat = MAPLE_QUEUE_PROBE;
+				}
+				break;
+			case MAPLE_RESPONSE_DEVINFO:
+				/* check if the unit is changed */
+				maple_check_unit_change(sc, u);
+				break;
+			}
+		} else if (u->u_dma_stat == MAPLE_DMA_PING) {
+			KASSERT(u->u_queuestat == MAPLE_QUEUE_NONE);
+			u->u_dma_stat = MAPLE_DMA_IDLE;
+			switch (response) {
+			default:
+			case (u_int8_t)MAPLE_RESPONSE_NONE:
+				/*
+				 * Some 3rd party devices sometimes
+				 * do not respond.
+				 */
+				if (++u->u_cnt_removal > MAPLE_REMOVAL_CNT) {
+					/* detach */
+#if defined(MAPLE_DEBUG) && MAPLE_DEBUG > 1
+					printf("%s: ping response %d\n",
+					    maple_unit_name(buf, u->port,
+						u->subunit),
+					    response);
+#endif
+					maple_detach_unit(sc, u);
+				} else {
+					/* retry immediately */
+					maple_queue_command(sc, u,
+					    u->u_command, u->u_datalen,
+					    u->u_dataaddr);
+					u->u_dma_stat = MAPLE_DMA_PING;
+					continue;
+				}
+				break;
+			case (u_int8_t)MAPLE_RESPONSE_BADCMD:
+			case MAPLE_RESPONSE_DATATRF:
+				TAILQ_INSERT_TAIL(&sc->sc_pingq, u, u_q);
+				u->u_queuestat = MAPLE_QUEUE_PING;
+				u->u_cnt_removal = 0;
+				break;
+			case MAPLE_RESPONSE_DEVINFO:
+				/* check for attach */
+				maple_check_unit_change(sc, u);
+				u->u_cnt_removal = 0;
+				break;
+			}
+		} else {
+			/*
+			 * Note: Do not rely on the consistency of responses.
+			 */
+			func_code = u->u_dma_func;
+			u->u_dma_stat = MAPLE_DMA_IDLE;
+
+			fn = &u->u_func[func_code];
+			if (fn->f_dev == NULL) {
+#ifdef MAPLE_DEBUG
+				printf("%s: unknown function: function %d, response %d\n",
+				    maple_unit_name(buf, u->port, u->subunit),
+				    func_code, response);
+#endif
+				continue;
+			}
+			if (fn->f_callback != NULL) {
+				(*fn->f_callback)(fn->f_arg,
+				    (void *)u->u_rxbuf,
+				    (u->u_rxbuf[0] >> 22) & 1020,
+				    (u->u_dma_stat == MAPLE_DMA_PCMD) ?
+					MAPLE_FLAG_CMD_PERIODIC_TIMING : 0);
+			}
+		}
+	}
 }
 
 void
@@ -362,47 +1027,48 @@
 	struct maple_softc *sc;
 
 	sc = (struct maple_softc *)dev;
-
-	if (MAPLE_STATE != 0)
-		return;
 
-	maple_send_commands(sc);
-
-	while (MAPLE_STATE != 0)
+	while (MAPLE_STATE != 0)	/* XXX may lost a DMA cycle */
 		;
 
-	maple_check_responses(sc);
+	/* periodic status check only */
+	maple_begin_txbuf(sc);
+	maple_send_defered_periodic(sc);
+	maple_send_periodic(sc);
+	if (maple_end_txbuf(sc)) {
+		maple_start_poll(sc);
+		maple_check_responses(sc);
+	}
 }
 
 void
-maple_set_condition_callback(struct device *dev, int port, int subunit,
-    u_int32_t func, void (*callback)(void *, void *, int), void *data)
+maple_set_callback(struct device *dev, struct maple_unit *u, int func,
+	void (*callback)(void *, struct maple_response *, int, int), void *arg)
 {
-	struct maple_softc *sc;
+#if 0	/* currently unused */
+	struct maple_softc *sc = (void *) dev;
+#endif
+	struct maple_func *fn;
 
-	sc = (struct maple_softc *)dev;
+	KASSERT(func >= 0 && func < 32);
 
-	if ((port & ~(MAPLE_PORTS-1)) != 0 ||
-	    subunit < 0 || subunit >= MAPLE_SUBUNITS)
-		return;
+	fn = &u->u_func[func];
 
-	sc->sc_unit[port][subunit].getcond_func = func;
-	sc->sc_unit[port][subunit].getcond_callback = callback;
-	sc->sc_unit[port][subunit].getcond_data = data;
+	fn->f_callback = callback;
+	fn->f_arg = arg;
 }
 
 static void
 maple_callout(void *ctx)
 {
 	struct maple_softc *sc = ctx;
-
-	if (!maple_polling) {
-		maple_check_responses(sc);
-		maple_send_commands(sc);
-	}
 
-	callout_reset(&sc->maple_callout_ch, MAPLE_CALLOUT_TICKS,
-	    (void *)maple_callout, sc);
+#if 0	/* XXX ??? */
+	if (maple_polling)
+		return;
+#endif
+	sc->sc_event = 1;	/* mark as periodic event */
+	wakeup(&sc->sc_event);
 }
 
 int
@@ -446,14 +1112,15 @@
 mapleattach(struct device *parent, struct device *self, void *aux)
 {
 	struct maple_softc *sc;
+	struct maple_unit *u;
 	vaddr_t dmabuffer;
 	paddr_t dmabuffer_phys;
 	u_int32_t *p;
-	int i, j;
+	int port, subunit, f;
 
 	sc = (struct maple_softc *)self;
 
-	printf("\n");
+	printf(": %s\n", sysasic_intr_string(IPL_MAPLE));
 
 	if (maple_alloc_dma(MAPLE_DMABUF_SIZE, &dmabuffer, &dmabuffer_phys)) {
 		printf("%s: unable to allocate DMA buffers.\n",
@@ -463,17 +1130,31 @@
 
 	p = (u_int32_t *)dmabuffer;
 
-	for (i = 0; i < MAPLE_PORTS; i++)
-		for (j = 0; j < MAPLE_SUBUNITS; j++) {
-			sc->sc_rxbuf[i][j] = p;
-			sc->sc_rxbuf_phys[i][j] = SH3_P2SEG_TO_PHYS(p);
+	for (port = 0; port < MAPLE_PORTS; port++)
+		for (subunit = 0; subunit < MAPLE_SUBUNITS; subunit++) {
+			u = &sc->sc_unit[port][subunit];
+			u->port = port;
+			u->subunit = subunit;
+			u->u_dma_stat = MAPLE_DMA_IDLE;
+			u->u_rxbuf = p;
+			u->u_rxbuf_phys = SH3_P2SEG_TO_PHYS(p);
 			p += 256;
+
+			for (f = 0; f < MAPLE_NFUNC; f++) {
+				u->u_func[f].f_funcno = f;
+				u->u_func[f].f_unit = u;
+			}
 		}
 
 	sc->sc_txbuf = p;
 	sc->sc_txbuf_phys = SH3_P2SEG_TO_PHYS(p);
 
-	sc->maple_commands_pending = 0;
+	TAILQ_INIT(&sc->sc_probeq);
+	TAILQ_INIT(&sc->sc_pingq);
+	TAILQ_INIT(&sc->sc_periodicq);
+	TAILQ_INIT(&sc->sc_periodicdeferq);
+	TAILQ_INIT(&sc->sc_acmdq);
+	TAILQ_INIT(&sc->sc_pcmdq);
 
 	MAPLE_RESET = RESET_MAGIC;
 	MAPLE_RESET2 = 0;
@@ -482,34 +1163,185 @@
 
 	MAPLE_ENABLE = 1;
 
+	maple_polling = 1;
 	maple_scanbus(sc);
 
-	memset(&sc->maple_callout_ch, 0, sizeof(sc->maple_callout_ch));
+	callout_init(&sc->maple_callout_ch);
 
-	callout_reset(&sc->maple_callout_ch, MAPLE_CALLOUT_TICKS,
-	    (void *)maple_callout, sc);
+	sc->sc_intrhand = sysasic_intr_establish(SYSASIC_EVENT_MAPLE_DMADONE,
+	    IPL_MAPLE, maple_intr, sc);
+
+	config_pending_incr();	/* create thread before mounting root */
+	kthread_create(maple_create_event_thread, sc);
 }
 
-int
-mapleprint(void *aux, const char *pnp)
+void
+maple_create_event_thread(void *arg)
 {
-	struct maple_attach_args *ma = aux;
+	struct maple_softc *sc = arg;
+
+	if (kthread_create1(maple_event_thread, sc, &sc->event_thread,
+	    "%s", sc->sc_dev.dv_xname) == 0)
+		return;
+
+#if 0 /* not yet */
+	config_pending_decr();
+	/* should run in polling mode */
+#else
+	panic("%s: unable to create event thread\n", sc->sc_dev.dv_xname);
+#endif
+}
+
+static void
+maple_event_thread(void *arg)
+{
+	struct maple_softc *sc = arg;
+	unsigned cnt = 1;	/* timing counter */
+	int s;
+
+#ifdef MAPLE_DEBUG
+	printf("%s: forked event thread, pid %d\n",
+	    sc->sc_dev.dv_xname, sc->event_thread->p_pid);
+#endif
 
-	if (pnp != NULL) {
-		printf("maple%c", 'A'+ma->ma_port);
-		if (ma->ma_subunit != 0)
-			printf("%d", ma->ma_subunit);
-		printf(" at %s", pnp);
+	/* begin first DMA cycle */
+	maple_begin_txbuf(sc);
+
+	sc->sc_event = 1;
+
+	/* OK, continue booting system */
+	maple_polling = 0;
+	config_pending_decr();
+
+	for (;;) {
+		/*
+		 * start DMA
+		 */
+
+		/* queue async commands */
+		maple_queue_cmds(sc, &sc->sc_acmdq);
+
+		/* send defered periodic command */
+		maple_send_defered_periodic(sc);
+
+		/* queue periodic commands */
+		if (sc->sc_event) {
+			/* queue commands on periodic timing */
+			maple_queue_cmds(sc, &sc->sc_pcmdq);
+
+			if ((cnt & 31) == 0)	/* XXX */
+				maple_unit_probe(sc);
+			cnt++;
+
+			maple_send_periodic(sc);
+			if ((cnt & 7) == 0)	/* XXX */
+				maple_unit_ping(sc);
+
+			/*
+			 * schedule periodic event
+			 */
+			sc->sc_event = 0;
+			callout_reset(&sc->maple_callout_ch,
+			    MAPLE_CALLOUT_TICKS, maple_callout, sc);
+		}
+
+		if (maple_end_txbuf(sc)) {
+
+			s = splmaple();
+			maple_start(sc);
+
+			/*
+			 * wait until DMA done
+			 */
+			if (tsleep(&sc->sc_dmadone, PWAIT, "mdma", hz)
+			    == EWOULDBLOCK) {
+				/* was DDB active? */
+				printf("%s: timed out\n", sc->sc_dev.dv_xname);
+			}
+			splx(s);
+
+			/*
+			 * call handlers
+			 */
+			maple_check_responses(sc);
+		}
+
+		/*
+		 * wait for an event
+		 */
+		s = splsoftclock();
+		if (TAILQ_EMPTY(&sc->sc_acmdq) && sc->sc_event == 0 &&
+		    TAILQ_EMPTY(&sc->sc_periodicdeferq) &&
+		    SIMPLEQ_EMPTY(&sc->sc_dmaq) /* rare case -- resend cmd */) {
+			if (tsleep(&sc->sc_event, PWAIT, "mslp", hz)
+			    == EWOULDBLOCK) {
+				printf("%s: event timed out\n",
+				    sc->sc_dev.dv_xname);
+			}
+
+		}
+		splx(s);
+
 	}
+
+#if 0	/* maple root device can't be detached */
+	kthread_exit(0);
+	/* NOTREACHED */
+#endif
+}
+
+int
+maple_intr(void *arg)
+{
+	struct maple_softc *sc = arg;
+
+	if (maple_polling)
+		return 1;	/* Debugger mode */
+
+	wakeup(&sc->sc_dmadone);
 
-	printf(" port %d", ma->ma_port);
+	return 1;
+}
+
+int
+mapleprint(void *aux, const char *pnp)
+{
+	struct maple_attach_args *ma = aux;
+	int port, subunit;
+	char buf[16];
+	char *prod, *p, oc;
+
+	port = ma->ma_unit->port;
+	subunit = ma->ma_unit->subunit;
+
+	if (pnp != NULL)
+		printf("%s at %s", maple_unit_name(buf, port, subunit), pnp);
+
+	printf(" port %d", port);
+
+	if (subunit != 0)
+		printf(" subunit %d", subunit);
+
+#ifdef MAPLE_DEBUG
+	printf(": a %#x fn %#x d %#x,%#x,%#x",
+	    ma->ma_devinfo->di_area_code,
+	    ntohl(ma->ma_devinfo->di_func),
+	    ntohl(ma->ma_devinfo->di_function_data[0]),
+	    ntohl(ma->ma_devinfo->di_function_data[1]),
+	    ntohl(ma->ma_devinfo->di_function_data[2]));
+#endif
+
+	/* nul termination */
+	prod = ma->ma_devinfo->di_product_name;
+	for (p = prod + sizeof ma->ma_devinfo->di_product_name; p >= prod; p--)
+		if (p[-1] != '\0' && p[-1] != ' ')
+			break;
+	oc = *p;
+	*p = '\0';
 
-	if (ma->ma_subunit != 0)
-		printf(" subunit %d", ma->ma_subunit);
+	printf(": %s", prod);
 
-	printf(": %.*s",
-	    (int)sizeof(ma->ma_devinfo->di_product_name),
-	    ma->ma_devinfo->di_product_name);
+	*p = oc;	/* restore */
 
 	return (0);
 }
@@ -520,25 +1352,27 @@
 	struct maple_attach_args *ma = aux;
 
 	if (match->cf_loc[MAPLECF_PORT] != MAPLECF_PORT_DEFAULT &&
-	    match->cf_loc[MAPLECF_PORT] != ma->ma_port)
+	    match->cf_loc[MAPLECF_PORT] != ma->ma_unit->port)
 		return (0);
 
 	if (match->cf_loc[MAPLECF_SUBUNIT] != MAPLECF_SUBUNIT_DEFAULT &&
-	    match->cf_loc[MAPLECF_SUBUNIT] != ma->ma_subunit)
+	    match->cf_loc[MAPLECF_SUBUNIT] != ma->ma_unit->subunit)
 		return (0);
 
 	return (config_match(parent, match, aux));
 }
 
 u_int32_t
-maple_get_function_data(struct maple_devinfo *devinfo, u_int32_t function_code)
+maple_get_function_data(struct maple_devinfo *devinfo, int function_code)
 {
 	int i, p = 0;
+	u_int32_t func;
 
+	func = ntohl(devinfo->di_func);
 	for (i = 31; i >= 0; --i)
-		if (devinfo->di_func & (1U << i)) {
-			if (function_code & (1U << i))
-				return devinfo->di_function_data[p];
+		if (func & (1U << i)) {
+			if (function_code == i)
+				return ntohl(devinfo->di_function_data[p]);
 			else
 				if (++p >= 3)
 					break;
@@ -560,7 +1394,7 @@
 
 	if (MAPLEPORT(dev) >= MAPLE_PORTS)
 		return (ENXIO);
-	
+
 	if (MAPLESUBUNIT(dev) >= MAPLE_SUBUNITS)
 		return (ENXIO);
 
Index: dev/maple/maple.h
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/dreamcast/dev/maple/maple.h,v
retrieving revision 1.4
diff -u -r1.4 maple.h
--- dev/maple/maple.h	2002/03/25 18:59:40	1.4
+++ dev/maple/maple.h	2002/10/04 14:32:49
@@ -1,6 +1,42 @@
 /*	$NetBSD: maple.h,v 1.4 2002/03/25 18:59:40 uch Exp $	*/
 
 /*-
+ * Copyright (c) 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by ITOH Yasufumi.
+ *
+ * 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) 2001 Marcus Comstedt
  * All rights reserved.
  *
@@ -36,44 +72,48 @@
 #define _DREAMCAST_DEV_MAPLE_MAPLE_H_
 
 #include <sys/device.h>
+#include <sys/queue.h>
+#include <machine/intr.h>
 
 #define MAPLE_PORTS 4
 #define MAPLE_SUBUNITS 6
 
 /* Maple Bus command and response codes */
 
-#define MAPLE_RESPONSE_FILEERR -5
-#define MAPLE_RESPONSE_AGAIN   -4  /* request should be retransmitted */
-#define MAPLE_RESPONSE_BADCMD  -3
-#define MAPLE_RESPONSE_BADFUNC -2
-#define MAPLE_RESPONSE_NONE    -1  /* unit didn't respond at all */
-#define MAPLE_COMMAND_DEVINFO  1
-#define MAPLE_COMMAND_ALLINFO  2
-#define MAPLE_COMMAND_RESET    3
-#define MAPLE_COMMAND_KILL     4
-#define MAPLE_RESPONSE_DEVINFO 5
-#define MAPLE_RESPONSE_ALLINFO 6
-#define MAPLE_RESPONSE_OK      7
-#define MAPLE_RESPONSE_DATATRF 8
-#define MAPLE_COMMAND_GETCOND  9
-#define MAPLE_COMMAND_GETMINFO 10
-#define MAPLE_COMMAND_BREAD    11
-#define MAPLE_COMMAND_BWRITE   12
-#define MAPLE_COMMAND_SETCOND  14
+#define MAPLE_RESPONSE_FILEERR		-5
+#define MAPLE_RESPONSE_AGAIN		-4 /* request should be retransmitted */
+#define MAPLE_RESPONSE_BADCMD		-3
+#define MAPLE_RESPONSE_BADFUNC		-2
+#define MAPLE_RESPONSE_NONE		-1 /* unit didn't respond at all */
+#define MAPLE_COMMAND_DEVINFO		1
+#define MAPLE_COMMAND_ALLINFO		2
+#define MAPLE_COMMAND_RESET		3
+#define MAPLE_COMMAND_KILL		4
+#define MAPLE_RESPONSE_DEVINFO		5
+#define MAPLE_RESPONSE_ALLINFO		6
+#define MAPLE_RESPONSE_OK		7
+#define MAPLE_RESPONSE_DATATRF		8
+#define MAPLE_COMMAND_GETCOND		9
+#define MAPLE_COMMAND_GETMINFO		10
+#define MAPLE_COMMAND_BREAD		11
+#define MAPLE_COMMAND_BWRITE		12
+#define MAPLE_COMMAND_GETLASTERR	13
+#define MAPLE_COMMAND_SETCOND		14
 
 
 /* Function codes */
+#define MAPLE_FN_CONTROLLER	0
+#define MAPLE_FN_MEMCARD	1
+#define MAPLE_FN_LCD		2
+#define MAPLE_FN_CLOCK		3
+#define MAPLE_FN_MICROPHONE	4
+#define MAPLE_FN_ARGUN		5
+#define MAPLE_FN_KEYBOARD	6
+#define MAPLE_FN_LIGHTGUN	7
+#define MAPLE_FN_PURUPURU	8
+#define MAPLE_FN_MOUSE		9
 
-#define MAPLE_FUNC_CONTROLLER 0x001
-#define MAPLE_FUNC_MEMCARD    0x002
-#define MAPLE_FUNC_LCD        0x004
-#define MAPLE_FUNC_CLOCK      0x008
-#define MAPLE_FUNC_MICROPHONE 0x010
-#define MAPLE_FUNC_ARGUN      0x020
-#define MAPLE_FUNC_KEYBOARD   0x040
-#define MAPLE_FUNC_LIGHTGUN   0x080
-#define MAPLE_FUNC_PURUPURU   0x100
-#define MAPLE_FUNC_MOUSE      0x200
+#define MAPLE_FUNC(fn)		(1 << (fn))
 
 struct maple_devinfo {
 	u_int32_t di_func;		/* function code */
@@ -86,19 +126,109 @@
 	u_int16_t di_max_power;		/* maximum power consumption */
 };
 
+struct maple_response {
+	u_int32_t	response_code;
+	u_int32_t	data[1];	/* variable length */
+};
+
+#define MAPLE_FLAG_PERIODIC		1
+#define MAPLE_FLAG_CMD_PERIODIC_TIMING	2
+
+#define MAPLE_NFUNC	32
+
+struct maple_func {
+	int		f_funcno;
+	struct maple_unit *f_unit;
+	struct device	*f_dev;
+
+	/* callback */
+	void		(*f_callback)(void *, struct maple_response *,
+			    int /*len*/, int /*flags*/);
+	void 		*f_arg;
+
+	u_int32_t	f_work;
+
+	/* periodic command request */
+	enum maple_periodic_stat {
+		MAPLE_PERIODIC_NONE,
+		MAPLE_PERIODIC_INQ,
+		MAPLE_PERIODIC_DEFERED
+	} f_periodic_stat;
+	TAILQ_ENTRY(maple_func)	f_periodicq;
+
+	/* command request */
+	int		f_command;		/* 0: not in queue */
+	int		f_datalen;
+	void		*f_dataaddr;
+	enum maple_command_stat {
+		MAPLE_CMDSTAT_NONE,
+		MAPLE_CMDSTAT_ASYNC,		/* process immediately */
+		MAPLE_CMDSTAT_PERIODIC_DEFERED,	/* periodic but process imdtly*/
+		MAPLE_CMDSTAT_PERIODIC		/* process on periodic timing */
+	} f_cmdstat;
+	TAILQ_ENTRY(maple_func)	f_cmdq;
+};
+
 struct maple_unit {
-	int port, subunit;
-	int status;
-	u_int32_t getcond_func;
-	void (*getcond_callback)(void *, void *, int);
-	void *getcond_data;
+	int		port, subunit;
+	struct maple_func u_func[MAPLE_NFUNC];
+	u_int32_t	getcond_func_set;
+	int		u_ping_func;
+	u_int32_t	u_noping;
 	struct maple_devinfo devinfo;
+
+	/* DMA status / function */
+	enum maple_dma_stat {
+		MAPLE_DMA_IDLE,
+		MAPLE_DMA_PERIODIC,	/* periodic GETCOND */
+		MAPLE_DMA_ACMD,		/* asynchronous command */
+		MAPLE_DMA_PCMD,		/* command on periodic timing */
+		MAPLE_DMA_PROBE,	/* checking for insertion */
+		MAPLE_DMA_PING		/* checking for removal */
+	} u_dma_stat;
+	int	u_dma_func;
+
+	/* start of each receive buffer */
+	u_int32_t	*u_rxbuf;
+  	u_int32_t	u_rxbuf_phys;
+
+	/* for restarting command */
+	int		u_resendcnt;
+	int		u_command;
+	int		u_datalen;
+	void		*u_dataaddr;
+
+	/* required to work around 3rd party device */
+	int		u_cnt_removal;
+#define MAPLE_REMOVAL_CNT	5
+
+	SIMPLEQ_ENTRY(maple_unit)	u_dmaq;
+
+	enum maple_queue_stat {
+		MAPLE_QUEUE_NONE,
+		MAPLE_QUEUE_PROBE,
+		MAPLE_QUEUE_PING
+	} u_queuestat;
+	TAILQ_ENTRY(maple_unit)		u_q;
 };
+
+struct maple_softc;
 
-extern void	maple_set_condition_callback(struct device *, int, int,
-		    u_int32_t, void (*)(void *, void *, int), void *);
-extern u_int32_t maple_get_function_data(struct maple_devinfo *, u_int32_t);
+extern void	maple_set_callback(struct device *, struct maple_unit *, int,
+		    void (*)(void *, struct maple_response *, int, int),
+		    void *);
+extern void	maple_enable_unit_ping(struct device *, struct maple_unit *,
+		    int /*func*/, int /*enable*/);
+extern void	maple_enable_periodic(struct device *, struct maple_unit *,
+		    int /*func*/, int /*on*/);
+extern void	maple_command(struct device *, struct maple_unit *,
+		    int /*func*/, int /*command*/, int /*datalen*/, void *,
+		    int /*flags*/);
+extern u_int32_t maple_get_function_data(struct maple_devinfo *, int);
 extern void	maple_run_polling(struct device *);
 
-#endif /* _DREAMCAST_DEV_MAPLE_MAPLE_H_ */
+/* interrupt priority level */
+#define	IPL_MAPLE	IPL_TTY
+#define splmaple()	spltty()
 
+#endif /* _DREAMCAST_DEV_MAPLE_MAPLE_H_ */
Index: dev/maple/mapleconf.h
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/dreamcast/dev/maple/mapleconf.h,v
retrieving revision 1.4
diff -u -r1.4 mapleconf.h
--- dev/maple/mapleconf.h	2002/03/25 18:59:40	1.4
+++ dev/maple/mapleconf.h	2002/10/04 14:32:49
@@ -33,7 +33,10 @@
  */
 
 struct maple_attach_args {
-	int ma_port, ma_subunit;
+	struct maple_unit *ma_unit;
 	u_int32_t ma_function;
 	struct maple_devinfo *ma_devinfo;
 };
+
+#define MAPLE_MATCH_FUNC	2
+#define MAPLE_MATCH_FALLBACK	1
Index: dev/maple/maplevar.h
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/dreamcast/dev/maple/maplevar.h,v
retrieving revision 1.4
diff -u -r1.4 maplevar.h
--- dev/maple/maplevar.h	2001/05/26 19:04:40	1.4
+++ dev/maple/maplevar.h	2002/10/04 14:32:49
@@ -1,5 +1,42 @@
-/* $NetBSD: maplevar.h,v 1.4 2001/05/26 19:04:40 marcus Exp $ */
+/*	$NetBSD: maplevar.h,v 1.4 2001/05/26 19:04:40 marcus Exp $	*/
+
 /*-
+ * Copyright (c) 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by ITOH Yasufumi.
+ *
+ * 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) 2001 Marcus Comstedt
  * All rights reserved.
  *
@@ -34,13 +71,14 @@
 #include <machine/bus.h>
 
 struct maple_softc {
-	struct device sc_dev;
+	struct device	sc_dev;
 
-	struct callout maple_callout_ch;
-	int maple_commands_pending;
+	struct callout	maple_callout_ch;
+	struct proc	*event_thread;
 
-	int sc_port_units[MAPLE_PORTS];
-	int sc_port_units_open[MAPLE_PORTS];
+	u_int8_t	sc_port_unit_map[MAPLE_PORTS];
+	int		sc_port_units[MAPLE_PORTS];
+	int		sc_port_units_open[MAPLE_PORTS];
 
 	struct maple_unit sc_unit[MAPLE_PORTS][MAPLE_SUBUNITS];
 
@@ -48,10 +86,15 @@
 	u_int32_t *sc_txpos;	/* current write position in tx buffer */
 	u_int32_t *sc_txlink;   /* start of last written frame */
 
-	/* start of each receive buffer */
-	u_int32_t *sc_rxbuf[MAPLE_PORTS][MAPLE_SUBUNITS];
-
 	u_int32_t sc_txbuf_phys;	/* 29-bit physical address */
-  	u_int32_t sc_rxbuf_phys[MAPLE_PORTS][MAPLE_SUBUNITS];
-};
 
+	void	*sc_intrhand;
+	int	sc_dmadone;		/* wchan */
+
+	int	sc_event;		/* periodic event is active / wchan */
+
+	SIMPLEQ_HEAD(maple_dmaq_head, maple_unit) sc_dmaq;
+	TAILQ_HEAD(maple_unitq_head, maple_unit) sc_probeq, sc_pingq;
+	TAILQ_HEAD(maple_fnq_head, maple_func) sc_periodicq, sc_periodicdeferq;
+	TAILQ_HEAD(maple_cmdq_head, maple_func) sc_acmdq, sc_pcmdq;
+};
Index: dev/maple/mkbd.c
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/dreamcast/dev/maple/mkbd.c,v
retrieving revision 1.16
diff -u -r1.16 mkbd.c
--- dev/maple/mkbd.c	2002/10/02 15:45:16	1.16
+++ dev/maple/mkbd.c	2002/10/04 14:32:49
@@ -61,6 +61,7 @@
  */
 static	int mkbdmatch(struct device *, struct cfdata *, void *);
 static	void mkbdattach(struct device *, struct device *, void *);
+static	int mkbddetach(struct device *, int);
 
 int	mkbd_enable(void *, int);
 void	mkbd_set_leds(void *, int);
@@ -72,7 +73,7 @@
 	mkbd_ioctl,
 };
 
-static void mkbd_intr(struct mkbd_softc *, struct mkbd_condition *, int);
+static void mkbd_intr(void *, struct maple_response *, int, int);
 
 void	mkbd_cngetc(void *, u_int *, int *);
 void	mkbd_cnpollc(void *, int);
@@ -88,19 +89,20 @@
 	KB_JP,
 };
 
-static struct mkbd_softc *mkbd_console_softc = NULL;
+static struct mkbd_softc *mkbd_console_softc;
 
-static int mkbd_console_initted = 0;
+static int mkbd_is_console;
+static int mkbd_console_initted;
 
 CFATTACH_DECL(mkbd, sizeof(struct mkbd_softc),
-    mkbdmatch, mkbdattach, NULL, NULL);
+    mkbdmatch, mkbdattach, mkbddetach, NULL);
 
 static int
 mkbdmatch(struct device *parent, struct cfdata *cf, void *aux)
 {
 	struct maple_attach_args *ma = aux;
 
-	return ((ma->ma_function & MAPLE_FUNC_KEYBOARD) != 0);
+	return (ma->ma_function == MAPLE_FN_KEYBOARD ? MAPLE_MATCH_FUNC : 0);
 }
 
 static void
@@ -114,11 +116,10 @@
 	u_int32_t kbdtype;
 
 	sc->sc_parent = parent;
-	sc->sc_port = ma->ma_port;
-	sc->sc_subunit = ma->ma_subunit;
+	sc->sc_unit = ma->ma_unit;
 
 	kbdtype = maple_get_function_data(ma->ma_devinfo,
-	    MAPLE_FUNC_KEYBOARD) >> 24;
+	    MAPLE_FN_KEYBOARD) >> 24;
 	switch (kbdtype) {
 	case 1:
 		printf(": Japanese keyboard");
@@ -138,21 +139,45 @@
 	printf("\n");
 
 #if NWSKBD > 0
-	a.console = ((sc->sc_dev.dv_unit == 0) && (mkbd_console_initted == 1))
-	    ? 1 : 0;
+	if ((a.console = mkbd_is_console) != 0) {
+		mkbd_is_console = 0;
+		if (!mkbd_console_initted)
+			wskbd_cnattach(&mkbd_consops, NULL, &mkbd_keymapdata);
+		mkbd_console_softc = sc;
+	}
 	a.keymap = &mkbd_keymapdata;
 	a.accessops = &mkbd_accessops;
 	a.accesscookie = sc;
-	if (a.console)
-		mkbd_console_softc = sc;
 	sc->sc_wskbddev = config_found(self, &a, wskbddevprint);
 #endif
 
-	maple_set_condition_callback(parent, sc->sc_port, sc->sc_subunit,
-	    MAPLE_FUNC_KEYBOARD,(void (*) (void *, void *, int)) mkbd_intr, sc);
+	maple_set_callback(parent, sc->sc_unit, MAPLE_FN_KEYBOARD,
+	    mkbd_intr, sc);
+	maple_enable_periodic(parent, sc->sc_unit, MAPLE_FN_KEYBOARD, 1);
 }
 
+static int
+mkbddetach(struct device *self, int flags)
+{
+	struct mkbd_softc *sc = (struct mkbd_softc *) self;
+	int rv = 0;
+
+	if (sc == mkbd_console_softc) {
+		/*
+		 * Hack to allow another Maple keyboard to be new console.
+		 * XXX Should some other type device it can be console.
+		 */
+		printf("%s: was console keyboard\n", sc->sc_dev.dv_xname);
+		wskbd_cndetach();
+		mkbd_console_softc = NULL;
+		mkbd_console_initted = 0;
+		mkbd_is_console = 1;
+	}
+	if (sc->sc_wskbddev)
+		rv = config_detach(sc->sc_wskbddev, flags);
 
+	return rv;
+}
 
 int
 mkbd_enable(void *v, int on)
@@ -193,6 +218,7 @@
 
 	wskbd_cnattach(&mkbd_consops, NULL, &mkbd_keymapdata);
 	mkbd_console_initted = 1;
+	mkbd_is_console = 1;
 
 	return (0);
 }
@@ -221,10 +247,13 @@
 #define SHIFT_DOWN(n)	KEY_DOWN((n) | SHIFT_KEYCODE_BASE)
 
 static void
-mkbd_intr(struct mkbd_softc *sc, struct mkbd_condition *kbddata, int sz)
+mkbd_intr(void *arg, struct maple_response *response, int sz, int flags)
 {
+	struct mkbd_softc *sc = arg;
+	struct mkbd_condition *kbddata = (void *) response->data;
 
-	if (sz >= sizeof(struct mkbd_condition)) {
+	if ((flags & MAPLE_FLAG_PERIODIC) &&
+	    sz >= sizeof(struct mkbd_condition)) {
 		int i, j, v;
 
 		v = sc->sc_condition.shift & ~kbddata->shift;
Index: dev/maple/mkbdvar.h
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/dreamcast/dev/maple/mkbdvar.h,v
retrieving revision 1.3
diff -u -r1.3 mkbdvar.h
--- dev/maple/mkbdvar.h	2002/03/25 18:59:40	1.3
+++ dev/maple/mkbdvar.h	2002/10/04 14:32:49
@@ -33,6 +33,7 @@
  */
 
 struct mkbd_condition {
+	u_int32_t func_code;	/* function code (big endian) */
 	u_int8_t shift;
 	u_int8_t led;
 	u_int8_t key[6];
@@ -46,7 +47,7 @@
 	struct device	*sc_wskbddev;
 	struct device *sc_parent;
 
-	int sc_port, sc_subunit;
+	struct maple_unit *sc_unit;
 	struct mkbd_condition sc_condition;
 };
 
Index: dev/maple/mms.c
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/dreamcast/dev/maple/mms.c,v
retrieving revision 1.5
diff -u -r1.5 mms.c
--- dev/maple/mms.c	2002/10/02 15:45:17	1.5
+++ dev/maple/mms.c	2002/10/04 14:32:49
@@ -50,6 +50,7 @@
 #include <dreamcast/dev/maple/mapleconf.h>
 
 struct mms_condition {
+	u_int32_t func_code;	/* function code (big endian) */
 	uint32_t buttons;
 	uint16_t axis1;		/* X */
 	uint16_t axis2;		/* Y */
@@ -86,8 +87,7 @@
 struct mms_softc {
 	struct device sc_dev;
 
-	int sc_port;
-	int sc_subunit;
+	struct maple_unit *sc_unit;
 
 	uint32_t sc_oldbuttons;
 
@@ -96,9 +96,10 @@
 
 int	mms_match(struct device *, struct cfdata *, void *);
 void	mms_attach(struct device *, struct device *, void *);
+int	mms_detach(struct device *, int);
 
 CFATTACH_DECL(mms, sizeof(struct mms_softc),
-    mms_match, mms_attach, NULL, NULL);
+    mms_match, mms_attach, mms_detach, NULL);
 
 int	mms_enable(void *);
 int	mms_ioctl(void *, u_long, caddr_t, int, struct proc *);
@@ -110,14 +111,14 @@
 	mms_disable,
 };
 
-void	mms_intr(void *, void *, int);
+void	mms_intr(void *, struct maple_response *, int, int);
 
 int
 mms_match(struct device *parent, struct cfdata *cf, void *aux)
 {
 	struct maple_attach_args *ma = aux;
 
-	return ((ma->ma_function & MAPLE_FUNC_MOUSE) != 0);
+	return (ma->ma_function == MAPLE_FN_MOUSE ? MAPLE_MATCH_FUNC : 0);
 }
 
 void
@@ -130,11 +131,10 @@
 
 	printf(": SEGA Dreamcast Mouse\n");
 
-	sc->sc_port = ma->ma_port;
-	sc->sc_subunit = ma->ma_subunit;
+	sc->sc_unit = ma->ma_unit;
 
 	data = maple_get_function_data(ma->ma_devinfo,
-	    MAPLE_FUNC_MOUSE);
+	    MAPLE_FN_MOUSE);
 
 	printf("%s: buttons:", sc->sc_dev.dv_xname);
 	if (data & MMS_FUNCDATA_A)
@@ -161,11 +161,23 @@
 		return;
 	}
 
-	maple_set_condition_callback(parent, sc->sc_port, sc->sc_subunit,
-	    MAPLE_FUNC_MOUSE, mms_intr, sc);
+	maple_set_callback(parent, sc->sc_unit, MAPLE_FN_MOUSE, mms_intr, sc);
+	maple_enable_periodic(parent, sc->sc_unit, MAPLE_FN_MOUSE, 1);
 }
 
 int
+mms_detach(struct device *self, int flags)
+{
+	struct mms_softc *sc = (void *) self;
+	int rv = 0;
+
+	if (sc->sc_wsmousedev != NULL)
+		rv = config_detach(sc->sc_wsmousedev, flags);
+
+	return rv;
+}
+
+int
 mms_enable(void *v)
 {
 
@@ -200,14 +212,15 @@
 }
 
 void
-mms_intr(void *arg, void *buf, int size)
+mms_intr(void *arg, struct maple_response *response, int size, int flags)
 {
 	struct mms_softc *sc = arg;
-	struct mms_condition *data = buf;
+	struct mms_condition *data = (void *) response->data;
 	int dx = 0, dy = 0, dz = 0, buttons = 0;
 	uint32_t buttonchg;
 
-	if (size < sizeof(*data))
+	if ((flags & MAPLE_FLAG_PERIODIC) == 0 ||
+	    size < sizeof(*data))
 		return;
 
 	data->buttons &= MMS_BUTTON_MASK;
Index: dreamcast/sysasic.c
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/dreamcast/dreamcast/sysasic.c,v
retrieving revision 1.3
diff -u -r1.3 sysasic.c
--- dreamcast/sysasic.c	2002/09/27 15:35:58	1.3
+++ dreamcast/sysasic.c	2002/10/04 14:32:50
@@ -36,66 +36,132 @@
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/device.h>
+#include <sys/syslog.h>
 
 #include <sh3/exception.h>
 
 #include <machine/intr.h>
 #include <machine/sysasicvar.h>
 
+#define SYSASIC_INTR_ST		0xa05f6900
+#define SYSASIC_INTR_EN(level)	(0xa05f6910 + ((level) << 4))
+
 #define SYSASIC_IRQ_LEVEL_13	0
 #define SYSASIC_IRQ_LEVEL_11	1
 #define SYSASIC_IRQ_LEVEL_9	2
 #define SYSASIC_IRQ_LEVEL_MAX	2
+#define SYSASIC_IRQ_INDEX_TO_IRQ(i)	(13 - 2 * (i))
+
+#define IPL_IRL9	IPL_BIO
+#define IPL_IRL11	IPL_NET
+#define IPL_IRL13	IPL_TTY
 
+/* per-irq */
 struct sysasic_intrhand {
+	/* for quick check on interrupt */
+	unsigned	syh_events[(SYSASIC_EVENT_MAX + 1 + (32 - 1)) / 32];
+#define SYSASIC_EVENT_NMAP	((SYSASIC_EVENT_MAX + 1 + (32 - 1)) / 32)
+#define SYSASIC_EVENT_INTR_MAP(ev)	((ev) >> 5)
+#define SYSASIC_EVENT_INTR_BIT(ev)	((unsigned) 1 << ((ev) & 31))
+
 	void	*syh_intc;
-	int	syh_event;
 	int	syh_idx;
 } sysasic_intrhand[SYSASIC_IRQ_LEVEL_MAX + 1];
+
+/* per-event */
+struct	syh_eventhand {
+	int	(*hnd_fn)(void *);	/* sub handler */
+	void	*hnd_arg;
+	struct sysasic_intrhand *hnd_syh;
+} sysasic_eventhand[SYSASIC_EVENT_MAX + 1];
 
-void sysasic_intr_enable(struct sysasic_intrhand *, int);
+void sysasic_intr_enable(struct sysasic_intrhand *, int /*event*/, int /*on*/);
+int sysasic_intr(void *);
 
+const char *
+sysasic_intr_string(int ipl)
+{
+
+	switch (ipl) {
+	default:
+#ifdef DIAGNOSTIC
+		panic("sysasic_intr_string: unknown ipl %d", ipl);
+#endif
+	case IPL_IRL9:
+		return "SH4 IRL 9";
+	case IPL_IRL11:
+		return "SH4 IRL 11";
+	case IPL_IRL13:
+		return "SH4 IRL 13";
+	}
+	/* NOTREACHED */
+}
+
 /*
  * Set up an interrupt handler to start being called.
  */
 void *
-sysasic_intr_establish(int event, int (*ih_fun)(void *), void *ih_arg)
+sysasic_intr_establish(int event, int ipl, int (*ih_fun)(void *), void *ih_arg)
 {
 	struct sysasic_intrhand *syh;
-	int evtcode, ipl, idx;
+	struct syh_eventhand *hnd;
+	int idx;
+	static const int idx2evt[3] = {
+		SH_INTEVT_IRL13, SH_INTEVT_IRL11, SH_INTEVT_IRL9
+	};
+#ifdef DIAGNOSTIC
+	int i;
+#endif
 
-	if (event < 0 || event > SYSASIC_EVENT_MAX)
-		panic("invalid sysasic event %d", event);
+	KASSERT(event >= 0 && event <= SYSASIC_EVENT_MAX);
+	KASSERT(ih_fun);
 
 	/*
-	 * Dreamcast use SH4 INTC as IRL mode. if INTEVT code is specified,
+	 * Dreamcast use SH4 INTC as IRL mode.  If IRQ is specified,
 	 * its priority level is fixed.
+	 *
+	 * We use IPL to specify the IRQ to trap programming errors. :D
 	 */
-	switch (event) {
-	case SYSASIC_EVENT_EXT:
+	switch (ipl) {
+	default:
+#ifdef DIAGNOSTIC
+		panic("sysasic_intr_establish: unknown ipl %d", ipl);
+#endif
+	case IPL_IRL9:
+		idx = SYSASIC_IRQ_LEVEL_9;
+		break;
+	case IPL_IRL11:
 		idx = SYSASIC_IRQ_LEVEL_11;
-		ipl = IPL_NET;
-		evtcode = SH_INTEVT_IRL11;
 		break;
-	case SYSASIC_EVENT_GDROM:
-		idx = SYSASIC_IRQ_LEVEL_9;
-		ipl = IPL_BIO;
-		evtcode = SH_INTEVT_IRL9;
+	case IPL_IRL13:
+		idx = SYSASIC_IRQ_LEVEL_13;
 		break;
-	default:
-		panic("vaild but unknown event %d", event);
 	}
 
 	syh = &sysasic_intrhand[idx];
 
-	syh->syh_event	= event;
-	syh->syh_idx	= idx;
-	syh->syh_intc	= intc_intr_establish(evtcode, IST_LEVEL, ipl,
-	    ih_fun, ih_arg);
+	if (syh->syh_intc == NULL) {
+		syh->syh_idx	= idx;
+		syh->syh_intc	= intc_intr_establish(idx2evt[idx], IST_LEVEL,
+		    ipl, sysasic_intr, syh);
+	}
 
-	sysasic_intr_enable(syh, 1);
+#ifdef DIAGNOSTIC
+	/* check if the event handler is already installed */
+	for (i = 0; i <= SYSASIC_IRQ_LEVEL_MAX; i++)
+		if ((sysasic_intrhand[i].syh_events[SYSASIC_EVENT_INTR_MAP(event)] &
+		    SYSASIC_EVENT_INTR_BIT(event)) != 0)
+			panic("sysasic_intr_establish: event %d already insatlled irq %d",
+			    event, SYSASIC_IRQ_INDEX_TO_IRQ(i));
+#endif
+
+	hnd = &sysasic_eventhand[event];
+	hnd->hnd_fn = ih_fun;
+	hnd->hnd_arg = ih_arg;
+	hnd->hnd_syh = syh;
+	sysasic_intr_enable(syh, event, 1);
 
-	return (void *)syh;
+	return (void *)hnd;
 }
 
 /*
@@ -104,27 +170,121 @@
 void
 sysasic_intr_disestablish(void *arg)
 {
-	struct sysasic_intrhand *syh = arg;
+	struct syh_eventhand *hnd = arg;
+	struct sysasic_intrhand *syh = hnd->hnd_syh;
 	int event;
+	int i;
 
-	event = syh->syh_event;
+	event = hnd - sysasic_eventhand;
 
+#ifdef DISAGNOSTIC
 	if (event < 0 || event > SYSASIC_EVENT_MAX)
 		panic("invalid sysasic event %d", event);
-
-	sysasic_intr_enable(syh, 0);
+	if (syh->syh_events[SYSASIC_EVENT_INTR_MAP(event)] &
+	    SYSASIC_EVENT_INTR_BIT(event)) == 0)
+		panic("sysasic_intr_disestablish: event %d not installed for irq %d",
+		    event, SYSASIC_IRQ_INDEX_TO_IRQ(syh->syh_idx));
+#endif
+
+	sysasic_intr_enable(syh, event, 0);
+	hnd->hnd_fn = 0;
+	hnd->hnd_arg = 0;
+	hnd->hnd_syh = 0;
+
+	/* deinstall intrc if no event exists */
+	for (i = 0; i < SYSASIC_EVENT_NMAP; i++)
+		if (syh->syh_events[i])
+			return;
 	intc_intr_disestablish(syh->syh_intc);
+	syh->syh_intc = 0;
 }
 
 void
-sysasic_intr_enable(struct sysasic_intrhand *syh, int on)
+sysasic_intr_enable(struct sysasic_intrhand *syh, int event, int on)
 {
-	int event = syh->syh_event;
 	__volatile u_int32_t *masks =
-	    (__volatile u_int32_t *)(0xa05f6910 + (syh->syh_idx << 4));
+	    (__volatile u_int32_t *) SYSASIC_INTR_EN(syh->syh_idx);
+	__volatile u_int32_t *stats = (__volatile u_int32_t *) SYSASIC_INTR_ST;
+	int evmap = SYSASIC_EVENT_INTR_MAP(event);
+	unsigned evbit = SYSASIC_EVENT_INTR_BIT(event);
+
+	if (on) {
+		/* clear pending event if any */
+		stats[evmap] = evbit;
+
+		/* set event map */
+		syh->syh_events[evmap] |= evbit;
+
+		/* enable interrupt */
+		masks[evmap] = syh->syh_events[evmap];
+	} else {
+		/* disable interrupt */
+		masks[evmap] = syh->syh_events[evmap] & ~evbit;
+
+		/* clear pending event if any */
+		stats[evmap] = evbit;
+
+		/* clear event map */
+		syh->syh_events[evmap] &= ~evbit;
+	}
+}
+
+int
+sysasic_intr(void *arg)
+{
+	struct sysasic_intrhand *syh = arg;
+	unsigned ev0, ev;
+	unsigned m, n;
+	unsigned pos;
+	struct syh_eventhand *evh;
+#ifdef DIAGNOSTIC
+	int handled = 0;
+	static int reportcnt = 10;
+#endif
+
+	for (m = 0; m < SYSASIC_EVENT_NMAP; m++) {
+		if ((ev0 = syh->syh_events[m]) &&
+		    (ev = ev0 & ((__volatile u_int32_t *)SYSASIC_INTR_ST)[m])) {
+
+			/* clear interrupts */
+			((__volatile u_int32_t *)SYSASIC_INTR_ST)[m] = ev;
+
+			/* call handlers */
+			n = (m << 5) - 1;	/* -1 to point at current bit */
+			while ((pos = ffs(ev)) != 0) {
+				n += pos;
+#ifdef __OPTIMIZE__
+				/* optimized, assuming 1 <= pos <= 32 */
+				asm("shld	%2,%0"
+				    : "=r" (ev) : "0" (ev), "r" (-pos));
+#else
+				/* ``shift count >= bit width'' is undefined */
+				if (pos >= 32)
+					ev = 0;
+				else
+					ev >>= pos;
+#endif
+
+				evh = &sysasic_eventhand[n];
+#ifdef DIAGNOSTIC
+				KASSERT(evh->hnd_fn);
+				if ((*evh->hnd_fn)(evh->hnd_arg))
+					handled = 1;
+#else
+				(*evh->hnd_fn)(evh->hnd_arg);
+#endif
+			}
+		}
+	}
+
+#ifdef DIAGNOSTIC
+	if (!handled && reportcnt > 0) {
+		reportcnt--;
+		log(LOG_ERR, "sysasic_intr: stray irq%d interrupt%s\n",
+		    SYSASIC_IRQ_INDEX_TO_IRQ(syh->syh_idx),
+		    reportcnt == 0 ? "; stopped logging" : "");
+	}
+#endif
 
-	masks[0] = 0;
-	masks[1] = 0;
-	if (on)
-		masks[event >> 5] = 1 << (event & 31);
+	return 0;
 }
Index: include/intr.h
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/dreamcast/include/intr.h,v
retrieving revision 1.3
diff -u -r1.3 intr.h
--- include/intr.h	2002/03/24 18:21:08	1.3
+++ include/intr.h	2002/10/04 14:32:50
@@ -39,12 +39,12 @@
 #include <sh3/intr.h>
 
 /* Number of interrupt source */
-#define _INTR_N		9	/* TMU0, TMU1, TMU2, SCIF * 4, GDROM, GAPSPCI */
+#define _INTR_N		10	/* TMU0, TMU1, TMU2, SCIF * 4, IRL * 3 */
 
 /* Interrupt priority levels */
 #define	IPL_BIO		9	/* block I/O	(GD-ROM) */
 #define	IPL_NET		11	/* network	(GAPS PCI) */
-#define	IPL_TTY		12	/* terminal */
+#define	IPL_TTY		12	/* terminal	(Maple) */
 #define	IPL_SERIAL	12	/* serial */
 #define	IPL_CLOCK	14	/* clock */
 #define	IPL_HIGH	15	/* everything */
Index: include/sysasicvar.h
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/dreamcast/include/sysasicvar.h,v
retrieving revision 1.2
diff -u -r1.2 sysasicvar.h
--- include/sysasicvar.h	2002/03/24 18:21:09	1.2
+++ include/sysasicvar.h	2002/10/04 14:32:50
@@ -39,13 +39,15 @@
 #ifndef _DREAMCAST_SYSASICVAR_H_
 #define	_DREAMCAST_SYSASICVAR_H_
 
-#define SYSASIC_EVENT_GDROM  32
-#define SYSASIC_EVENT_AICA   33
-#define SYSASIC_EVENT_EXT    35
-#define SYSASIC_EVENT_MAX    63
+#define SYSASIC_EVENT_MAPLE_DMADONE	12
+#define SYSASIC_EVENT_MAPLE_ERROR	13
+#define SYSASIC_EVENT_GDROM		32
+#define SYSASIC_EVENT_AICA		33
+#define SYSASIC_EVENT_EXT		35
+#define SYSASIC_EVENT_MAX		65
 
-void	*sysasic_intr_establish(int, int (*ih_fun)(void *), void *);
+const char *sysasic_intr_string(int /*ipl*/) __attribute__((__const__));
+void	*sysasic_intr_establish(int /*event*/, int /*ipl*/, int (*ih_fun)(void *), void *);
 void    sysasic_intr_disestablish(void *);
 
 #endif /* !_DREAMCAST_SYSASICVAR_H_ */
-

------- =_aaaaaaaaaa0--