Integrate code from John P. Wittkoski <jpw@netwizards.net> and
authorbriggs <briggs@openbsd.org>
Sun, 23 Feb 1997 06:04:50 +0000 (06:04 +0000)
committerbriggs <briggs@openbsd.org>
Sun, 23 Feb 1997 06:04:50 +0000 (06:04 +0000)
Takashi Hamada <hamada@next.etron.kanazawa-it.ac.jp>.  This code
interfaces directly to the hardware to support the ADB on many
macs.  It is enabled by "options HWDIRECT" in the configuration
file.  At some point, this should probably become the default method
as interfacing to the ADB through the ROMs has been painful and sometimes
problematic.

This code should have functioning ADB support for:
II series (II, SE/30, IIx, IIcx)
IIsi series (IIsi, IIci, IIvx, IIvi)
LC II, LC III
Performa 400, 405, 430, 460, 465, 467, 600
Classic II, Color Classic, Color Classic II
PB 5XX series
Duo series
PB 140,145,145b,160,(160c?),165,165c,170,180,180c
Quadra 700,900,950
There is an off-chance that it will work on:
PB 150, PB 190
Quadra/Centris 605,610,630,650,660AV,800,840AV
LC 475,550,575,630
Performa 475,476,575,577,578,630
Note that functioning ADB support does not mean that everything else
will work.  I obviously do not own all of the above machines (does
anyone?  ;-)...  Any reports are welcome.

Many thanks to John Wittkoski and Takashi Hamada!

15 files changed:
sys/arch/mac68k/conf/TIGER
sys/arch/mac68k/conf/files.mac68k
sys/arch/mac68k/dev/adb.c
sys/arch/mac68k/dev/adb_direct.c [new file with mode: 0644]
sys/arch/mac68k/dev/adbsys.c
sys/arch/mac68k/dev/adbvar.h
sys/arch/mac68k/dev/pm_direct.c [new file with mode: 0644]
sys/arch/mac68k/dev/pm_direct.h [new file with mode: 0644]
sys/arch/mac68k/mac68k/machdep.c
sys/arch/mac68k/mac68k/macrom.c
sys/arch/mac68k/mac68k/macrom.h
sys/arch/mac68k/mac68k/macromasm.s
sys/arch/mac68k/mac68k/pram.c
sys/arch/mac68k/mac68k/pram.h
sys/arch/mac68k/mac68k/pramasm.s

index b48c1ab..68d1184 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: TIGER,v 1.1 1997/01/24 01:25:25 briggs Exp $
+#      $OpenBSD: TIGER,v 1.2 1997/02/23 06:04:50 briggs Exp $
 #      $NetBSD: GENERIC,v 1.43 1996/09/22 06:49:09 scottr Exp $
 #
 # Allen's Q700
@@ -38,6 +38,7 @@ options               SYSVSHM,SYSVSEM,SYSVMSG
 options                PPP_BSDCOMP,PPP_DEFLATE
 
 # Mac-specific options
+options                HWDIRECT
 options                M68040
 options                FPSP
 options                COMPAT_NOMID
index 9c9b488..1b3663a 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: files.mac68k,v 1.10 1997/01/24 01:35:26 briggs Exp $
+#      $OpenBSD: files.mac68k,v 1.11 1997/02/23 06:04:51 briggs Exp $
 #      $NetBSD: files.mac68k,v 1.55 1997/01/21 09:43:45 thorpej Exp $
 
 # mac68k-specific configuration info
@@ -24,6 +24,8 @@ attach        adb at obio
 file   arch/mac68k/dev/adb.c           adb
 file   arch/mac68k/dev/adbsys.c
 file   arch/mac68k/dev/adbsysasm.s
+file   arch/mac68k/dev/adb_direct.c    hwdirect
+file   arch/mac68k/dev/pm_direct.c     hwdirect
 
 device asc
 attach asc at obio
@@ -56,7 +58,7 @@ device        sn: ifnet, ether
 attach sn at obio
 file   arch/mac68k/dev/if_sn.c         sn needs-flag
 
-include "scsi/files.scsi"
+include "../../../scsi/files.scsi"
 
 # Option 1 for ncr5380 support
 device ncrscsi: scsi
@@ -90,7 +92,7 @@ file  arch/mac68k/mac68k/fpu.c        fpu
 
 file   arch/m68k/m68k/copy.s
 file   arch/m68k/m68k/db_memrw.c       ddb
-include "arch/m68k/fpe/files.fpe"
+include "../../../arch/m68k/fpe/files.fpe"
 
 file   arch/mac68k/mac68k/autoconf.c
 file   arch/mac68k/mac68k/clock.c
@@ -127,5 +129,5 @@ major       {rd = 13}
 # Compatibility modules
 
 # SunOS Binary Compatibility (COMPAT_SUNOS)
-include "compat/sunos/files.sunos"
+include "../../../compat/sunos/files.sunos"
 file   arch/m68k/m68k/sunos_machdep.c  compat_sunos
index 29a5d96..33614c3 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: adb.c,v 1.6 1997/01/24 01:35:27 briggs Exp $  */
+/*     $OpenBSD: adb.c,v 1.7 1997/02/23 06:04:52 briggs Exp $  */
 /*     $NetBSD: adb.c,v 1.13 1996/12/16 16:17:02 scottr Exp $  */
 
 /*-
@@ -39,13 +39,12 @@ e*    notice, this list of conditions and the following disclaimer in the
 #include <sys/signalvar.h>
 #include <sys/systm.h>
 
-#include <machine/adbsys.h>
 #include <machine/autoconf.h>
 #include <machine/keyboard.h>
 
-#include "adbvar.h"
-#include "itevar.h"
-#include "../mac68k/macrom.h"
+#include <arch/mac68k/mac68k/macrom.h>
+#include <arch/mac68k/dev/adbvar.h>
+#include <arch/mac68k/dev/itevar.h>
 
 /*
  * Function declarations.
diff --git a/sys/arch/mac68k/dev/adb_direct.c b/sys/arch/mac68k/dev/adb_direct.c
new file mode 100644 (file)
index 0000000..83b7947
--- /dev/null
@@ -0,0 +1,2204 @@
+/*     $OpenBSD: adb_direct.c,v 1.1 1997/02/23 06:04:52 briggs Exp $   */
+/*  adb_direct.c 1.91 1/20/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 */
+
+#include <sys/types.h>
+#include <sys/cdefs.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#include <machine/cpu.h>
+#include <machine/macinfo.h>
+#include <machine/viareg.h>
+
+#include <arch/mac68k/mac68k/macrom.h>
+#include <arch/mac68k/dev/adbvar.h>
+
+#include "pm_direct.h"
+
+/* more verbose for testing */
+/*#define HWDIRECT_TEST*/
+
+/* 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 */
+
+/*
+ * 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(VIA1, vBufB) |= (vPB4 | vPB5)
+#define ADB_SET_STATE_IDLE_IISI()      via_reg(VIA1, vBufB) &= ~(vPB4 | vPB5)
+#define ADB_SET_STATE_IDLE_CUDA()      via_reg(VIA1, vBufB) |= (vPB4 | vPB5)
+#define ADB_SET_STATE_CMD()            via_reg(VIA1, vBufB) &= ~(vPB4 | vPB5)
+#define ADB_SET_STATE_EVEN()           via_reg(VIA1, vBufB) = ( (via_reg(VIA1, \
+                                               vBufB) | vPB4) & ~vPB5 )
+#define ADB_SET_STATE_ODD()            via_reg(VIA1, vBufB) = ( (via_reg(VIA1, \
+                                               vBufB) | vPB5) & ~vPB4 )
+#define ADB_SET_STATE_ACTIVE()                 via_reg(VIA1, vBufB) |= vPB5
+#define ADB_SET_STATE_INACTIVE()       via_reg(VIA1, vBufB) &= ~vPB5
+#define ADB_SET_STATE_TIP()            via_reg(VIA1, vBufB) &= ~vPB5
+#define ADB_CLR_STATE_TIP()            via_reg(VIA1, vBufB) |= vPB5
+#define ADB_SET_STATE_ACKON()          via_reg(VIA1, vBufB) |= vPB4
+#define ADB_SET_STATE_ACKOFF()         via_reg(VIA1, vBufB) &= ~vPB4
+#define ADB_TOGGLE_STATE_ACK_CUDA()    via_reg(VIA1, vBufB) ^= vPB4
+#define ADB_SET_STATE_ACKON_CUDA()     via_reg(VIA1, vBufB) &= ~vPB4
+#define ADB_SET_STATE_ACKOFF_CUDA()    via_reg(VIA1, vBufB) |= vPB4
+#define ADB_SET_SR_INPUT()             via_reg(VIA1, vACR) &= ~vSR_OUT
+#define ADB_SET_SR_OUTPUT()            via_reg(VIA1, vACR) |= vSR_OUT
+#define ADB_SR()                       via_reg(VIA1, vSR)
+#define ADB_VIA_INTR_ENABLE()          via_reg(VIA1, vIER) = 0x84
+#define ADB_VIA_INTR_DISABLE()         via_reg(VIA1, vIER) = 0x04
+#define ADB_VIA_CLR_INTR()             via_reg(VIA1, vIFR) = 0x04
+#define ADB_INTR_IS_OFF                        ( vPB3 == (via_reg(VIA1, vBufB) & vPB3) )
+#define ADB_INTR_IS_ON                 ( 0 == (via_reg(VIA1, vBufB) & vPB3) )
+#define ADB_SR_INTR_IS_OFF             ( 0 == (via_reg(VIA1, vIFR) & vSR_INT) )
+#define ADB_SR_INTR_IS_ON              ( vSR_INT == (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_ACK_DELAY  150
+
+/*
+ * Maximum ADB message length; includes space for data, result, and
+ * device code - plus a little for safety.
+ */
+#define MAX_ADB_MSG_LENGTH     20
+
+/*
+ * 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[MAX_ADB_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 */
+};
+
+/*
+ * 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     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 = 0;        /* doing ADB reinit, 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[MAX_ADB_MSG_LENGTH];      /* data input buffer */
+u_char adbOutputBuffer[MAX_ADB_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 device we heard from (II ONLY) */
+int     adbLastDevIndex = 0;    /* last ADB device loc. in device table (II ONLY) */
+int     adbLastCommand = 0;     /* the last ADB command we sent (II) */
+int     adbWaitingSubDev = 0;   /* ADB sub-device (RTC, PRAM, etc) - IIsi ONLY - unused */
+int     adbWaitingDevice = 0;   /* ADB device we are waiting for - unused */
+
+struct ADBDevEntry ADBDevTable[16];     /* our ADB device table */
+int     ADBNumDevices;          /* number of ADB devices found with ADBReInit */
+
+extern struct mac68k_machine_S mac68k_machine;
+extern int zshard(int);
+
+
+/*
+ * The following are private routines.
+ */
+void print_single __P((unsigned char *));
+void adb_intr __P((void));
+void adb_intr_II __P((void));
+void adb_intr_IIsi __P((void));
+void adb_intr_cuda __P((void));
+int send_adb_II __P((unsigned char *, unsigned char *, void *, void *, int));
+int send_adb_IIsi __P((unsigned char *, unsigned char *, void *, void *, int));
+int send_adb_cuda __P((unsigned char *, unsigned char *, void *, void *, int));
+void adb_handle_unsol __P((unsigned char *));
+void adb_op_comprout __P((void));
+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));
+void adb_handle_unsol __P((unsigned char *));
+int adb_op_sync __P((Ptr, Ptr, Ptr, short));
+void adb_read_II __P((unsigned char *));
+void adb_cleanup __P((unsigned char *));
+void adb_cleanup_IIsi __P((unsigned char *));
+void adb_comp_exec __P((void));
+int adb_cmd_result __P((unsigned char *));
+int adb_cmd_extra __P((unsigned 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((unsigned 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("nothing returned\n");
+                return;
+        }
+        if (thestring == 0) {
+                printf("no data - null pointer\n");
+                return;
+        }
+        if (thestring[0] > 20) {
+                printf("ADB: ACK > 20 no way!\n");
+                thestring[0] = 20;
+        }
+        printf("(length=0x%x):", thestring[0]);
+        for (x = 0; x < thestring[0]; x++)
+                printf("  0x%02x", thestring[x + 1]);
+        printf("\n");
+}
+
+
+/* 
+ * called when when an adb interrupt happens 
+ *
+ * Cuda version of adb_intr
+ * TO DO: can probably reduce the number of zshard calls in here
+ */
+void 
+adb_intr_cuda(void)
+{
+        int     i, ending, len;
+        unsigned int s;
+
+        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:
+                adbInputBuffer[1] = ADB_SR();   /* get byte */
+                ADB_SET_SR_INPUT();            /* make sure SR is set to IN */
+                ADB_SET_STATE_TIP();           /* signal start of data frame */
+               printf("idle 0x%02x ", adbInputBuffer[1]);
+                adbInputBuffer[0] = 1;
+                adbActionState = ADB_ACTION_IN; /* set next state */
+                break;
+
+        case ADB_ACTION_IN:
+                adbInputBuffer[++adbInputBuffer[0]] = ADB_SR(); /* get byte */
+                ADB_SET_SR_INPUT();            /* make sure SR is set to IN */
+                if (ADB_INTR_IS_OFF)           /* check for end of frame */
+                        ending = 1;
+                else
+                        ending = 0;
+
+                if (1 == ending) {      /* end of message? */
+                        ADB_CLR_STATE_TIP();       /* signal end of frame */
+                       printf("in end 0x%02x ", adbInputBuffer[adbInputBuffer[0]]);
+                       print_single(adbInputBuffer);
+                        /* this section _should_ handle all ADB and RTC/PRAM type commands, */
+                        /* but there may be more... */
+                        /* note: commands are always at [4], even for rtc/pram commands */
+                        if ((adbWaiting == 1) &&        /* are we waiting AND */
+                            (adbInputBuffer[4] == adbWaitingCmd) &&     /* the cmd we sent AND */
+                            ((adbInputBuffer[2] == 0x00) ||     /* it's from the
+                                                                * ADB device OR */
+                                (adbInputBuffer[2] == 0x01))) { /* it's from the PRAM/RTC device */
+                                
+                                /* is this data we are waiting for? */
+                                if (adbBuffer != (long) 0) {    /* if valid return data pointer */
+                                       /* get return length minus extras */
+                                        len = adbInputBuffer[0] - 4;    
+                                        /* if adb_op is ever made to be called from a user
+                                         * routine, we should use a copyout or copyin
+                                         * here to be sure we're in the correct context */
+                                        for (i = 1; i <= len; i++)
+                                                adbBuffer[i] = adbInputBuffer[4 + i];
+                                        if (len < 0)
+                                                len = 0;
+                                        adbBuffer[0] = len;
+                                }
+                                adb_comp_exec();        /* call completion routine */
+
+                                adbWaitingCmd = 0;      /* reset "waiting" vars */
+                                adbWaiting = 0;
+                                adbBuffer = (long) 0;
+                                adbCompRout = (long) 0;
+                                adbCompData = (long) 0;
+                        } else {
+                                /* pass the data off to the handler */
+                                /* This section IGNORES all data that is not from 
+                                 * the ADB sub-device. That is, not from rtc or pram.
+                                 * Maybe we  should fix later, but do the other
+                                 * devices every send things without
+                                 * being asked? */
+                                if (adbStarting == 0)   /* ignore if during adbreinit */
+                                        if (adbInputBuffer[2] == 0x00)
+                                                adb_handle_unsol(adbInputBuffer);
+                        }
+
+                        adbActionState = ADB_ACTION_IDLE;
+                        adbInputBuffer[0] = 0;  /* reset length */
+
+                        if (adbWriteDelay == 1) {       /* were we waiting to write? */\
+                               printf("WRITE DELAY ");
+                                adbSentChars = 0;       /* nothing sent yet */
+                                adbActionState = ADB_ACTION_OUT;        /* set next state */
+
+                                if (ADB_INTR_IS_ON) {   /* ADB intr low during write */
+                                        ADB_CLR_STATE_TIP();      /* reset */
+                                        ADB_SET_SR_INPUT();     /* make sure SR is set to IN */
+                                        adbSentChars = 0;       /* must start all over */
+                                        adbActionState = ADB_ACTION_IDLE;      /* new state */
+                                        adbInputBuffer[0] = 0;
+                                        break;
+                                }
+                                ADB_SET_SR_OUTPUT();    /* set shift register for OUT */
+                                ADB_SR() = adbOutputBuffer[adbSentChars + 1];
+                                ADB_SET_STATE_TIP();   /* tell ADB that we want to send */
+                        }
+                } else {
+                       ADB_TOGGLE_STATE_ACK_CUDA();
+                       printf("in 0x%02x ", adbInputBuffer[adbInputBuffer[0]]);
+                }
+                       
+                break;
+
+        case ADB_ACTION_OUT:
+                i = ADB_SR();          /* reset SR-intr in IFR */
+               printf("intr out 0x%02x ", i);
+                ADB_SET_SR_OUTPUT();    /* set shift register for OUT */
+
+                adbSentChars++;
+                if (ADB_INTR_IS_ON) {          /* ADB intr low during write */
+                printf("intr was on ");
+                        ADB_CLR_STATE_TIP();      /* reset */
+                        ADB_SET_SR_INPUT();     /* make sure SR is set to IN */
+                        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_ACK_DELAY);   /* delay */
+                        /* TO DO: not sure if this is the right thing to do for Cuda */
+                        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 */
+                                adb_comp_exec();        /* call completion routine */
+                                adbWaitingCmd = 0;      /* reset "waiting" vars, just in case */
+                                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();          make sure SR is set to IN */
+                        ADB_TOGGLE_STATE_ACK_CUDA();
+                        ADB_CLR_STATE_TIP();           /* end of frame */
+                       printf("write done ");
+                } else {
+                        ADB_SR() = adbOutputBuffer[adbSentChars + 1];   /* send next byte */
+                        ADB_TOGGLE_STATE_ACK_CUDA();  /* signal byte ready to shift */
+                        printf("toggle ");
+                }
+                break;
+
+        case ADB_ACTION_NOTREADY:
+                printf("adb: not yet initialized\n");
+                break;
+
+        default:
+                printf("intr: unknown ADB state\n");
+        }
+
+        ADB_VIA_INTR_ENABLE();  /* enable ADB interrupt on IIs. */
+
+        splx(s);                /* restore */
+
+        return;
+}                               /* end adb_intr_IIsi */
+
+
+int 
+send_adb_cuda(u_char *in, u_char *buffer, void *compRout, void *data, int
+command)
+{
+        int     i, s, len;
+
+        if (adbActionState == ADB_ACTION_NOTREADY)
+                return 1;
+
+        s = splhigh();          /* don't interrupt while we are messing with the ADB */
+
+        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! */
+        }
+
+        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 <= (adbOutputBuffer[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? */
+        printf("out start ");
+                adbActionState = ADB_ACTION_OUT;        /* set next state */
+                ADB_SET_SR_OUTPUT();    /* set shift register for OUT */
+                ADB_SR() = 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 (0x0100 <= (s & 0x0700))     /* 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();     /* go process "interrupt" */
+
+        return 0;
+}                               /* send_adb_cuda */
+
+
+/* TO DO: add one or two zshard calls in here */
+void
+adb_intr_II(void)
+{
+        int    i, len, intr_on = 0;
+        int    send = 0, do_srq = 0;
+        unsigned int   s;
+
+        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. */
+
+/*if (ADB_INTR_IS_ON)*/
+/*     printf("INTR ON ");*/
+if (ADB_INTR_IS_ON)
+       intr_on=1;      /* save for later */
+
+        switch (adbActionState) {
+        case ADB_ACTION_IDLE:
+               if ( !intr_on ) {
+                       /*printf("FAKE DROPPED \n");*/
+                       /*printf(" XX ");*/
+                       i=ADB_SR();
+                       break;
+               }
+               adbNextEnd=0;
+               /*printf("idle ");*/
+                adbInputBuffer[0] = 1;
+                adbInputBuffer[1] = ADB_SR();   /* get first byte */
+               /*printf("0x%02x ", adbInputBuffer[1]);*/
+                ADB_SET_SR_INPUT();            /* make sure SR is set to IN */
+                adbActionState = ADB_ACTION_IN;        /* set next state */
+                ADB_SET_STATE_EVEN();          /* set bus state to even */
+                adbBusState = ADB_BUS_EVEN;
+               break;
+        
+        case ADB_ACTION_IN:
+                adbInputBuffer[++adbInputBuffer[0]] = ADB_SR(); /* get byte */
+               /*printf("in 0x%02x ", adbInputBuffer[adbInputBuffer[0]]);*/
+                ADB_SET_SR_INPUT();     /* make sure SR is set to IN */
+                
+                /*
+                 * Check for an unsolicited Service Request (SRQ).
+                 * An empty SRQ packet NEVER ends, so we must manually
+                 * check for the following condition. 
+                 */
+                if ( adbInputBuffer[0]==4 && adbInputBuffer[2]==0xff &&
+                    adbInputBuffer[3]==0xff && adbInputBuffer[4]==0xff &&
+                    intr_on && !adbNextEnd )
+                       do_srq=1;
+                
+                if (adbNextEnd==1) {   /* process last byte of packet */
+                       adbNextEnd=0;
+                       /*printf("done: ");*/
+                       
+                       /* 
+                        * If the following conditions are true (4 byte
+                        * message, last 3 bytes are 0xff) then we
+                        * basically got a "no response" from the ADB chip,
+                        * so change the message to an empty one.
+                        * We also clear intr_on to stop the SRQ send later
+                        * on because these packets normally have the SRQ 
+                        * bit set even when there is NOT a pending SRQ.
+                        */
+                       if ( adbInputBuffer[0]==4 && adbInputBuffer[2]==0xff &&
+                           adbInputBuffer[3]==0xff && adbInputBuffer[4]==0xff ) {
+                               /*printf("NO RESP ");*/
+                               intr_on=0;
+                               adbInputBuffer[0]=0;
+                       }
+                       
+                       adbLastDevice=(adbInputBuffer[1] & 0xf0) >> 4;
+                       
+                       if ((!adbWaiting || adbPolling )
+                           && (adbInputBuffer[0] != 0)) {
+                               /* unsolicided - ignore if starting */
+                               if (!adbStarting)
+                                       adb_handle_unsol(adbInputBuffer);
+                       } else if ( !adbPolling ) { /* someone asked for it */
+                               /*printf("SOL: ");*/
+                               /*print_single(adbInputBuffer);*/
+                                if (adbBuffer != (long) 0) {   /* if valid return data pointer */
+                                       /* get return length minus extras */
+                                        len = adbInputBuffer[0] - 1;
+                                           
+                                        /* if adb_op is ever made to be called from a user
+                                         * routine, we should  use a copyout or copyin
+                                         * here to be sure we're in the correct context. */
+                                        for (i = 1; i <= len; i++)
+                                                adbBuffer[i] = adbInputBuffer[i + 1];
+                                        if (len < 0)
+                                                len = 0;
+                                        adbBuffer[0] = len;
+                                }
+                               adb_comp_exec();
+                       }
+                                               
+                       adbWaiting=0;
+                       adbPolling=0;
+                       adbInputBuffer[0]=0;
+                        adbBuffer = (long) 0;
+                        adbCompRout = (long) 0;
+                        adbCompData = (long) 0;
+                        /*
+                         * Since we are done, check whether there is any data 
+                         * waiting to do out. If so, start the sending the data.
+                         */
+                        if (adbOutQueueHasData == 1) {
+                        /*printf("XXX: DOING OUT QUEUE\n");*/
+                                /* copy over data */
+                                for (i = 0; i <= (adbOutQueue.outBuf[0] + 1); i++)
+                                        adbOutputBuffer[i] = adbOutQueue.outBuf[i];
+                                adbBuffer = adbOutQueue.saveBuf;       /* user data area */
+                                adbCompRout = adbOutQueue.compRout;     /* completion routine */
+                                adbCompData = adbOutQueue.data;        /* comp. rout. data */
+                                adbOutQueueHasData = 0; /* currently processing "queue" entry */
+                                adbPolling=0;
+                                send=1;
+                       /* if intr_on is true, then it's a SRQ
+                        * so poll other devices. */
+                       } else if (intr_on) {
+                               /*printf("starting POLL ");*/
+                               do_srq=1;
+                               adbPolling=1;
+                       } else if ( (adbInputBuffer[1] & 0x0f) != 0x0c) {
+                               /*printf("xC HACK ");*/
+                               adbPolling=1;
+                               send=1;
+                               adbOutputBuffer[0]=1;
+                               adbOutputBuffer[1]=(adbInputBuffer[1] & 0xf0) | 0x0c;
+                       } else {
+                               /*printf("ending ");*/
+                               adbBusState=ADB_BUS_IDLE;
+                               adbActionState=ADB_ACTION_IDLE;
+                               ADB_SET_STATE_IDLE_II();
+                               break;
+                       }
+                }
+                
+                /*
+                 * If do_srq is true then something above determined that
+                 * the message has ended and some device is sending a 
+                 * service request. So we need to determine the next device
+                 * and send a poll to it. (If the device we send to isn't the
+                 * one that sent the SRQ, that ok as it will be caught
+                 * the next time though.)
+                 */
+                if ( do_srq ) {
+                       /*printf("SRQ! ");*/
+                       adbPolling=1;
+                       adb_guess_next_device();
+                       adbOutputBuffer[0]=1;
+                       adbOutputBuffer[1]=((adbLastDevice & 0x0f) << 4) | 0x0c;
+                       send=1;
+                }
+
+                /*
+                 * If send is true then something above determined that
+                 * the message has ended and we need to start sending out
+                 * a new message immediately. This could be because there
+                 * is data waiting to go out or because an SRQ was seen.
+                 */
+                if ( send ) {
+                       adbNextEnd = 0;
+                       adbSentChars = 0;                       /* nothing sent yet */
+                       adbActionState = ADB_ACTION_OUT;        /* set next state */
+                       ADB_SET_SR_OUTPUT();                    /* set shift register for OUT */
+                       ADB_SR() = adbOutputBuffer[1];          /* load byte for output */
+                       adbBusState = ADB_BUS_CMD;              /* set bus to cmd state */
+                       ADB_SET_STATE_CMD();                    /* tell ADB that we want to send */
+                       break;
+                }
+
+               /* 
+                * We only get this far if the message hasn't
+                * ended yet.
+                */
+                if (!intr_on)                  /* if adb intr. on then the */
+                       adbNextEnd=1;           /* NEXT byte is the last */
+                       
+                       switch (adbBusState) {          /* set to next state */
+                case ADB_BUS_EVEN:
+                       ADB_SET_STATE_ODD();    /* set state to odd */
+                       adbBusState = ADB_BUS_ODD;
+                       break;
+
+               case ADB_BUS_ODD:
+                       ADB_SET_STATE_EVEN();   /* set state to even */
+                       adbBusState = ADB_BUS_EVEN;
+                               break;
+                default:
+                               printf("strange state!!!\n");      /* huh? */
+                       break;
+                }
+               break;
+        
+        case ADB_ACTION_OUT:
+                       adbNextEnd=0;
+                       if (!adbPolling)
+                               adbWaiting=1;           /* not unsolicited */
+               i=ADB_SR();                     /* clear interrupt */
+               adbSentChars++;
+               /*
+                * If the outgoing data was a TALK, we must
+                * switch to input mode to get the result.
+                */
+               if ( (adbOutputBuffer[1] & 0x0c) == 0x0c ) {
+                       adbInputBuffer[0]=1;
+                       adbInputBuffer[1]=i;
+                       adbActionState=ADB_ACTION_IN;
+                       ADB_SET_SR_INPUT();
+                       adbBusState= ADB_BUS_EVEN;
+                       ADB_SET_STATE_EVEN();
+                       /*printf("talk out 0x%02x ", i);*/
+                       break;
+               }
+               
+               /* 
+                * If it's not a TALK, check whether all data has been
+                * sent. If so, call the completion routine and clean up.
+                * If not, advance to the next state.
+                */
+               /*printf("non-talk out 0x%0x ", i);*/
+               ADB_SET_SR_OUTPUT();
+                if (adbOutputBuffer[0] == adbSentChars) {       /* check for done */
+                       /*printf("done \n");*/
+                       adb_comp_exec();
+                        adbBuffer = (long) 0;
+                        adbCompRout = (long) 0;
+                        adbCompData = (long) 0;
+                        if (adbOutQueueHasData == 1) {
+                                /* copy over data */
+                                for (i = 0; i <= (adbOutQueue.outBuf[0] + 1); i++)
+                                        adbOutputBuffer[i] = adbOutQueue.outBuf[i];
+                                adbBuffer = adbOutQueue.saveBuf;       /* user data area */
+                                adbCompRout = adbOutQueue.compRout;     /* completion routine */
+                                adbCompData = adbOutQueue.data;        /* comp. rout. data */
+                                adbOutQueueHasData = 0; /* currently processing "queue" entry */
+                                adbPolling=0;
+                        } else {
+                               adbOutputBuffer[0]=1;
+                               adbOutputBuffer[1]=(adbOutputBuffer[1] & 0xf0) | 0x0c;
+                               adbPolling=1;                   /* non-user poll */
+                       }
+                        adbNextEnd = 0;
+                       adbSentChars = 0;                       /* nothing sent yet */
+                       adbActionState = ADB_ACTION_OUT;        /* set next state */
+                       ADB_SET_SR_OUTPUT();                    /* set shift register for OUT */
+                       ADB_SR() = adbOutputBuffer[1];          /* load byte for output */
+                       adbBusState = ADB_BUS_CMD;              /* set bus to cmd state */
+                       ADB_SET_STATE_CMD();                    /* tell ADB that we want to send */
+                       break;
+               }
+                
+               ADB_SR() = adbOutputBuffer[adbSentChars + 1];
+                       switch (adbBusState) {          /* advance to next state */
+                case ADB_BUS_EVEN:
+                       ADB_SET_STATE_ODD();    /* set state to odd */
+                       adbBusState = ADB_BUS_ODD;
+                       break;
+
+                case ADB_BUS_CMD:
+                case ADB_BUS_ODD:
+                        ADB_SET_STATE_EVEN();   /* set state to even */
+                        adbBusState = ADB_BUS_EVEN;
+                        break;
+
+                default:
+                        printf("strange state!!! (0x%x)\n", adbBusState);
+                        break;
+                }
+               break;
+               
+        default:
+                printf("adb: unknown ADB state (during intr)\n");
+        }
+       
+        ADB_VIA_INTR_ENABLE();  /* enable ADB interrupt on IIs. */
+
+        splx(s);                /* restore */
+
+        return;
+
+}
+
+
+/* 
+ * send_adb version for II series machines 
+ */
+int
+send_adb_II(u_char *in, u_char *buffer, void *compRout, void *data, int command)
+{
+        int     i, s, len;
+
+        if (adbActionState == ADB_ACTION_NOTREADY)      /* return if ADB not available */
+                return 1;
+
+        s = splhigh();          /* don't interrupt while we are messing with the ADB */
+
+        if (0 != adbOutQueueHasData) {  /* right now, "has data" means "full" */
+                splx(s);               /* sorry, try again later */
+                return 1;
+        }
+        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), especially on II series!
+                 */
+                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 */
+
+                adbOutQueue.outBuf[0] = 1 + len;       /* command + addl. data */
+                adbOutQueue.outBuf[1] = (u_char) command;      /* load command */
+
+                for (i = 1; i <= len; i++)      /* copy additional output data, if any */
+                        adbOutQueue.outBuf[1 + i] = buffer[i];
+        } else
+                       /* if data ready, just copy over */                
+               for (i = 0; i <= (adbOutQueue.outBuf[0] + 1); i++)
+                        adbOutQueue.outBuf[i] = in[i];
+
+        adbOutQueue.saveBuf = buffer;          /* save buffer to know where to save result */
+        adbOutQueue.compRout = compRout;        /* save completion routine pointer */
+        adbOutQueue.data = data;               /* save completion routine data pointer */
+
+        if ((adbActionState == ADB_ACTION_IDLE) &&      /* is ADB available? */
+            (ADB_INTR_IS_OFF) &&                       /* and no incoming interrupts? */
+            (adbPolling == 0)) {                       /* and we are not currently polling */
+                                                       /* then start command now */
+                for (i = 0; i <= (adbOutQueue.outBuf[0] + 1); i++)      /* copy over data */
+                        adbOutputBuffer[i] = adbOutQueue.outBuf[i];
+                        
+                adbBuffer = adbOutQueue.saveBuf;        /* pointer to user data area */
+                adbCompRout = adbOutQueue.compRout;     /* pointer to the completion routine */
+                adbCompData = adbOutQueue.data;        /* pointer to the completion routine data */
+
+                adbSentChars = 0;                      /* nothing sent yet */
+                adbActionState = ADB_ACTION_OUT;        /* set next state */
+                adbBusState = ADB_BUS_CMD;             /* set bus to cmd state */
+
+                ADB_SET_SR_OUTPUT();                   /* set shift register for OUT */
+
+                ADB_SR() = adbOutputBuffer[adbSentChars + 1];   /* load byte for output */
+                ADB_SET_STATE_CMD();    /* tell ADB that we want to send */
+                adbOutQueueHasData = 0; /* currently processing "queue" entry */
+        } else
+                adbOutQueueHasData = 1; /* something in the write "queue" */
+
+        splx(s);
+
+        if (0x0100 <= (s & 0x0700))     /* were VIA1 interrupts blocked ? */
+                /* poll until message done */
+                while ((adbActionState != ADB_ACTION_IDLE) || (ADB_INTR_IS_ON)
+                    || (adbWaiting == 1) || (adbPolling == 1))
+                        if (ADB_SR_INTR_IS_ON)         /* wait for "interrupt" */
+                                adb_intr_II();       /* go process "interrupt" */
+
+        return 0;
+}
+
+
+/*
+ * 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)
+{
+        int     i, ending, len;
+        unsigned int s;
+
+        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:
+                delay(ADB_ACK_DELAY);   /* short delay is required
+                                         * before the first byte */
+
+                ADB_SET_SR_INPUT();            /* make sure SR is set to IN */
+                ADB_SET_STATE_ACTIVE();                /* signal start of data frame */
+                adbInputBuffer[1] = ADB_SR();   /* get byte */
+                adbInputBuffer[0] = 1;
+                adbActionState = ADB_ACTION_IN; /* set next state */
+
+                ADB_SET_STATE_ACKON();         /* start ACK to ADB chip */
+                delay(ADB_ACK_DELAY);          /* delay */
+                ADB_SET_STATE_ACKOFF();                /* end ACK to ADB chip */
+                zshard(0);                     /* grab any serial interrupts */
+                break;
+
+        case ADB_ACTION_IN:
+                ADB_SET_SR_INPUT();            /* make sure SR is set to IN */
+                adbInputBuffer[++adbInputBuffer[0]] = ADB_SR(); /* get byte */
+                if (ADB_INTR_IS_OFF)           /* check for end of frame */
+                        ending = 1;
+                else
+                        ending = 0;
+
+                ADB_SET_STATE_ACKON();  /* start ACK to ADB chip */
+                delay(ADB_ACK_DELAY);   /* delay */
+                ADB_SET_STATE_ACKOFF(); /* end ACK to ADB chip */
+                zshard(0);              /* grab any serial interrupts */
+
+                if (1 == ending) {      /* end of message? */
+                        ADB_SET_STATE_INACTIVE();       /* signal end of frame */
+                        /* this section _should_ handle all ADB and RTC/PRAM type commands, */
+                        /* but there may be more... */
+                        /* note: commands are always at [4], even for rtc/pram commands */
+                        if ((adbWaiting == 1) &&        /* are we waiting AND */
+                            (adbInputBuffer[4] == adbWaitingCmd) &&     /* the cmd we sent AND */
+                            ((adbInputBuffer[2] == 0x00) ||     /* it's from the
+                                                                * ADB device OR */
+                                (adbInputBuffer[2] == 0x01))) { /* it's from the PRAM/RTC device */
+                                
+                                /* is this data we are waiting for? */
+                                if (adbBuffer != (long) 0) {    /* if valid return data pointer */
+                                       /* get return length minus extras */
+                                        len = adbInputBuffer[0] - 4;    
+                                        /* if adb_op is ever made to be called from a user
+                                         * routine, we should use a copyout or copyin
+                                         * here to be sure we're in the correct context */
+                                        for (i = 1; i <= len; i++)
+                                                adbBuffer[i] = adbInputBuffer[4 + i];
+                                        if (len < 0)
+                                                len = 0;
+                                        adbBuffer[0] = len;
+                                }
+                                adb_comp_exec();        /* call completion routine */
+
+                                adbWaitingCmd = 0;      /* reset "waiting" vars */
+                                adbWaiting = 0;
+                                adbBuffer = (long) 0;
+                                adbCompRout = (long) 0;
+                                adbCompData = (long) 0;
+                        } else {
+                                /* pass the data off to the handler */
+                                /* This section IGNORES all data that is not from 
+                                 * the ADB sub-device. That is, not from rtc or pram.
+                                 * Maybe we  should fix later, but do the other
+                                 * devices every send things without
+                                 * being asked? */
+                                if (adbStarting == 0)   /* ignore if during adbreinit */
+                                        if (adbInputBuffer[2] == 0x00)
+                                                adb_handle_unsol(adbInputBuffer);
+                        }
+
+                        adbActionState = ADB_ACTION_IDLE;
+                        adbInputBuffer[0] = 0;  /* reset length */
+
+                        if (adbWriteDelay == 1) {       /* were we waiting to write? */
+                                adbSentChars = 0;       /* nothing sent yet */
+                                adbActionState = ADB_ACTION_OUT;        /* set next state */
+
+                                delay(ADB_ACK_DELAY);   /* delay */
+                                zshard(0);             /* grab any serial interrupts */
+
+                                if (ADB_INTR_IS_ON) {   /* ADB intr low during write */
+                                        ADB_SET_STATE_IDLE_IISI();      /* reset */
+                                        ADB_SET_SR_INPUT();     /* make sure SR is set to IN */
+                                        adbSentChars = 0;       /* must start all over */
+                                        adbActionState = ADB_ACTION_IDLE;      /* new state */
+                                        adbInputBuffer[0] = 0;
+                                        /* may be able to take this out later */
+                                        delay(ADB_ACK_DELAY);   /* delay */
+                                        break;
+                                }
+                                ADB_SET_STATE_ACTIVE(); /* tell ADB that we want to send */
+                                ADB_SET_STATE_ACKOFF(); /* make sure */
+                                ADB_SET_SR_OUTPUT();    /* set shift register for OUT */
+                                ADB_SR() = adbOutputBuffer[adbSentChars + 1];
+                                ADB_SET_STATE_ACKON();  /* tell ADB byte ready to shift */
+                        }
+                }
+                break;
+
+        case ADB_ACTION_OUT:
+                i = ADB_SR();          /* reset SR-intr in IFR */
+                ADB_SET_SR_OUTPUT();    /* set shift register for OUT */
+
+                ADB_SET_STATE_ACKOFF(); /* finish ACK */
+                adbSentChars++;
+                if (ADB_INTR_IS_ON) {          /* ADB intr low during write */
+                        ADB_SET_STATE_IDLE_IISI();      /* reset */
+                        ADB_SET_SR_INPUT();     /* make sure SR is set to IN */
+                        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_ACK_DELAY);   /* delay */
+                        zshard(0);              /* grab any serial interrupts */
+                        goto switch_start;      /* process next state  right now */
+                        break;
+                }
+                delay(ADB_ACK_DELAY);   /* required delay */
+                zshard(0);             /* grab any serial interrupts */
+
+                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 */
+                                adb_comp_exec();        /* call completion routine */
+                                adbWaitingCmd = 0;      /* reset "waiting" vars, just in case */
+                                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();            /* make sure SR is set to IN */
+                        ADB_SET_STATE_INACTIVE();       /* end of frame */
+                } else {
+                        ADB_SR() = adbOutputBuffer[adbSentChars + 1];   /* send next byte */
+                        ADB_SET_STATE_ACKON();  /* signal byte ready to shift */
+                }
+                break;
+
+        case ADB_ACTION_NOTREADY:
+                printf("adb: not yet initialized\n");
+                break;
+
+        default:
+                printf("intr: unknown ADB state\n");
+        }
+
+        ADB_VIA_INTR_ENABLE();  /* enable ADB interrupt on IIs. */
+
+        splx(s);                /* restore */
+
+        return;
+}                               /* end 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)
+{
+        int     i, s, len;
+
+        if (adbActionState == ADB_ACTION_NOTREADY)
+                return 1;
+
+        s = splhigh();          /* don't interrupt while we are messing with the ADB */
+
+        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! */
+        }
+
+        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 <= (adbOutputBuffer[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? */
+                adbActionState = ADB_ACTION_OUT;        /* set next state */
+
+                ADB_SET_STATE_ACTIVE(); /* tell ADB that we want to send */
+                ADB_SET_STATE_ACKOFF(); /* make sure */
+
+                ADB_SET_SR_OUTPUT();    /* set shift register for OUT */
+
+                ADB_SR() = adbOutputBuffer[adbSentChars + 1];   /* load byte for output */
+
+                ADB_SET_STATE_ACKON();  /* tell ADB byte ready to shift */
+        }
+        adbWriteDelay = 1;             /* something in the write "queue" */
+
+        splx(s);
+
+        if (0x0100 <= (s & 0x0700))     /* 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_IIsi();     /* go process "interrupt" */
+
+        return 0;
+}                               /* send_adb_IIsi */
+
+
+/* 
+ * adb_comp_exec
+ * This is a general routine that calls the completion routine if there is one.
+ */
+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) );
+               #else                                   /* for macos 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
+}
+       
+
+/*
+ * this routine handles what needs to be done after a message is read 
+ * from the adb data points to the raw data received from the device, 
+ * including device number (on IIsi) and result code.
+ */
+void 
+adb_handle_unsol(u_char *in)
+{
+        int     i, cmd;
+        u_char data[MAX_ADB_MSG_LENGTH];
+
+       /* make local copy so we don't destroy the real one - it may
+        * be needed later. */
+        for (i = 0; i <= (in[0] + 1); i++)
+               data[i] = in[i];
+       
+        switch (adbHardware) {
+        case ADB_HW_II:
+                /* adjust the "length" byte */
+                cmd = data[1];
+                if (data[0] < 2)
+                        data[1] = 0;
+                else
+                        data[1] = data[0] - 1;
+
+                adb_complete((data + 1), (long) 0, cmd);
+
+                break;
+
+        case ADB_HW_IISI:
+        case ADB_HW_CUDA:
+                /* only handles ADB for now */
+                if (0 != *(data + 2))
+                        return;
+
+                /* adjust the "length" byte */
+                cmd = data[4];
+                if (data[0] < 5)
+                        data[4] = 0;
+                else
+                        data[4] = data[0] - 4;
+
+                adb_complete((data + 4), (long) 0, cmd);
+
+                break;
+                
+        case ADB_HW_PB:
+               return;         /* how does PM handle "unsolicited" messages? */
+        case ADB_HW_UNKNOWN:
+                return;
+        }
+
+        return;
+
+#if 0
+        /* this should really be used later, once it is set up properly */
+        /* AND we need to make sure that we DON'T call it if it is zero! */
+        if ( 0 != ADBDevTable[i].devType )
+                (*(ADBDevTable[i].ServiceRtPtr))();
+#endif
+}
+
+
+/*
+ * 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);
+                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);
+               break;
+
+        case ADB_HW_PB:
+               result = pm_adb_op(
+                    (u_char *) buffer, (void *) compRout,
+                    (void *) data, (int) command);
+                break;
+
+        case ADB_HW_CUDA:
+                result = send_adb_cuda((u_char *) 0, 
+                    (u_char *) buffer, (void *) compRout,
+                    (void *) data, (int) command);
+               break;
+
+        case ADB_HW_UNKNOWN:
+       default:
+                return -1;
+        }
+        if (result == 0)
+             return 0;
+        else
+             return -1;
+}
+
+
+/*
+ * adb_cleanup
+ * This routine simply calls the appropriate version of the adb_cleanup routine.
+ */
+void 
+adb_cleanup(u_char *in)
+{
+        switch (adbHardware) {
+        case ADB_HW_II:
+                ADB_VIA_CLR_INTR();     /* clear interrupt */
+                break;
+
+        case ADB_HW_IISI:
+                /* get those pesky clock ticks we missed while booting */
+                adb_cleanup_IIsi(in);
+                break;
+
+        case ADB_HW_PB:
+               /* TO DO: 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:
+               /* TO DO: probably need some sort of cleanup for Cuda */
+               ADB_VIA_CLR_INTR();
+               ADB_SET_STATE_IDLE_CUDA();
+                break;
+
+        case ADB_HW_UNKNOWN:
+                return;
+        }
+}
+       
+       
+/* 
+ * adb_cleanup_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_cleanup_IIsi(u_char *buffer)
+{
+        int     i;
+        int     dummy;
+        int     s;
+        long    my_time;
+        int     endofframe;
+
+        delay(ADB_ACK_DELAY);
+
+        i = 1;                  /* skip over [0] */
+        s = splhigh();          /* block ALL interrupts while we are working */
+        ADB_SET_SR_INPUT();     /* make sure SR is set to IN */
+        ADB_VIA_INTR_DISABLE(); /* disable ADB interrupt on IIs. */
+        /* this is required, especially on faster machines */
+        delay(ADB_ACK_DELAY);
+
+        if (ADB_INTR_IS_ON) {
+                ADB_SET_STATE_ACTIVE(); /* signal start of data frame */
+
+                endofframe = 0;
+                while (0 == endofframe) {
+                        /* poll for ADB interrupt and watch for timeout */
+                        /* if time out, keep going in hopes of not hanging the ADB chip - I think */
+                        my_time = ADB_ACK_DELAY * 5;
+                        while ((ADB_SR_INTR_IS_OFF) && (my_time-- > 0))
+                                dummy = via_reg(VIA1, vBufB);
+
+                        buffer[i++] = ADB_SR(); /* reset interrupt flag by reading vSR */
+                        /* perhaps put in a check here that ignores all data
+                         * after the first MAX_ADB_MSG_LENGTH bytes ??? */
+                        if (ADB_INTR_IS_OFF)    /* check for end of frame */
+                                endofframe = 1;
+
+                        ADB_SET_STATE_ACKON();  /* send ACK to ADB chip */
+                        delay(ADB_ACK_DELAY);   /* delay */
+                        ADB_SET_STATE_ACKOFF(); /* send ACK to ADB chip */
+                }
+                ADB_SET_STATE_INACTIVE();       /* signal end of frame and delay */
+
+                /* probably don't need to delay this long */
+                delay(ADB_ACK_DELAY);
+        }
+        buffer[0] = --i;        /* [0] is length of message */
+        ADB_VIA_INTR_ENABLE();  /* enable ADB interrupt on IIs. */
+        splx(s);                /* restore interrupts */
+
+        return;
+}                               /* adb_cleanup_IIsi */
+
+
+/*
+ * adb_reinit sets up the adb stuff
+ *
+ */
+void 
+adb_reinit(void)
+{
+    u_char send_string[MAX_ADB_MSG_LENGTH];
+    int    s;
+    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 */
+
+        /* Make sure we are not interrupted while building the table. */
+               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 */
+
+        /* Set up all the VIA bits we need to do the ADB stuff.
+         */
+        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 */
+                       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 */
+                       break;
+
+               case ADB_HW_PB:
+               break;                          /* there has to be more than this? */
+
+        case ADB_HW_CUDA:
+               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 */
+               adbActionState = ADB_ACTION_IDLE;       /* used by all types of hardware */
+               adbBusState = ADB_BUS_IDLE;     /* this var. used in II-series code only */
+               via_reg(VIA1, vIER) = 0x84;     /* make sure VIA interrupts are on */
+                ADB_SET_STATE_IDLE_CUDA();      /* set ADB bus state to idle */
+                break;
+                
+        case ADB_HW_UNKNOWN:                   /* if type unknown then skip out */
+       default:
+                       via_reg(VIA1, vIER) = 0x04;     /* turn interrupts off - TO DO: turn PB ints off? */
+                       return;
+               break;
+        }
+
+        /*
+         * Clear out any "leftover" commands.  Remember that up until this
+         * point, the interrupt routine will be either off or it should be
+         * able to ignore inputs until the device table is built.
+         */
+        for (i = 0; i < 30; i++) {
+                delay(ADB_ACK_DELAY);
+                adb_cleanup(send_string);
+                printf("adb: cleanup: ");
+                print_single(send_string);
+                delay(ADB_ACK_DELAY);
+                if (ADB_INTR_IS_OFF)
+                        break;
+        }
+
+        /* 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;
+                       /*printf("initial device found (at index %d)\n", ADBNumDevices);*/
+                       pm_check_adb_devices(i);
+               }
+       }
+       
+       /* 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;
+       
+       /*printf("first free is: 0x%02x\n", saveptr);*/
+       /*printf("devices: %d\n", ADBNumDevices);*/
+       
+       nonewtimes=0;           /* no loops w/o new devices */
+       while ( nonewtimes++ < 11 ) {
+               for ( i=1; i <= ADBNumDevices; i++ ) {
+                       device=ADBDevTable[i].currentAddr;
+                       /*printf("moving device 0x%02x to 0x%02x (index 0x%02x)  ", device, saveptr, i);*/
+
+                       /* 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;
+                               /*printf("old device at index %d\n",i);*/
+                               /* add new device in table */
+                               /*printf("new device found\n");*/
+                               ADBDevTable[++ADBNumDevices].devType = (u_char) send_string[2];
+                               ADBDevTable[ADBNumDevices].origAddr = device;
+                               ADBDevTable[ADBNumDevices].currentAddr = device;
+                               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;
+                                       }
+                               /*printf("new free is 0x%02x\n", saveptr);*/
+                               nonewtimes=0;
+                       } else {
+                               /*printf("moving back...\n");*/
+                               /* 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);
+                       }
+               }
+       }
+
+        adb_prog_switch_enable();       /* enable the programmer's switch, if we have one */
+
+        if (0 == ADBNumDevices)         /* tell user if no devices found */
+                printf("adb: no devices found\n");
+
+        adbStarting = 0;        /* not starting anymore */
+        printf("adb: ADBReInit complete\n");
+
+        splx(s);
+
+        return;
+}
+
+
+/* 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;
+                else
+                        return 1;
+                break;
+
+        case ADB_HW_IISI:
+        case ADB_HW_CUDA:
+               /* was is an ADB talk command? */
+                if ((in[1] == 0x00) && ((in[2] & 0x0c) == 0x0c))
+                       return 0;
+                else
+                       /* was is an RTC/PRAM read date/time? */
+                        if ((in[1] == 0x01) && (in[2] == 0x03)) 
+                                return 0;
+                        else
+                                return 1;
+                break;
+
+        case ADB_HW_PB:
+                return 1;
+                break;
+
+        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;
+                else
+                        return 1;
+                break;
+
+        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;
+                else    /* add others later */
+                        return 1;
+                break;
+
+        case ADB_HW_PB:
+                return 1;
+                break;
+
+        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
+ */
+int 
+adb_op_sync(Ptr buffer, Ptr compRout, Ptr data, short command)
+{
+        int     result;
+        int     flag;
+
+        flag = 0;
+        result = adb_op(buffer, (void *) adb_op_comprout,
+            (void *) &flag, command);   /* send command */
+        if (result == 0) {              /* send ok? */
+                /* Don't need to use adb_cmd_result since this section is
+                 * hardware independent, and for ADB commands only (no RTC or PRAM) */
+                /*if ((command & 0x0c) == 0x0c)   was it a talk? */
+                        while (0 == flag) ;
+
+                return 0;
+        } else
+                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(void)
+{
+       #ifdef __NetBSD__
+       asm ( "movw    #1,a2@                   | update flag value" );
+       #else                                   /* for macos based testing */
+       asm     { move.w #1,(a2) }              /* update flag value */
+       #endif
+}
+
+void 
+adb_setup_hw_type(void)
+{
+        long    response;
+
+        response = mac68k_machine.machineid;
+
+        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:        /* Centris 650 */
+                adbHardware = ADB_HW_II;
+                printf("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 49:        /* Color Classic - not sure if IIsi or not */
+        case 62:        /* Performa 460/465/467 */
+        case 83:        /* Color Classic II (number right?) - not sure if IIsi or not */
+                adbHardware = ADB_HW_IISI;
+                printf("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("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("adb: using PowerBook Duo-series and PowerBook 500-series hardware support\n");
+                break;
+        case 60:        /* Centris 660AV */
+        case 78:        /* Quadra 840AV */
+        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 */
+                adbHardware = ADB_HW_CUDA;
+                printf("adb: using Cuda series hardware support\n");
+                break;
+        default:
+                adbHardware = ADB_HW_UNKNOWN;
+                printf("adb: hardware type unknown for this machine\n");
+                printf("adb: ADB support is disabled\n");
+                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);
+
+        /* printf("index 0x%x devType is: 0x%x\n", index,
+            ADBDevTable[index].devType); */
+        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 */
+
+}
+
+#ifdef HWDIRECT
+long
+mrg_adbintr(void)
+{
+        adb_intr();
+       return 1;       /* mimic mrg_adbintr in macrom.h just in case */
+}
+
+long
+mrg_pmintr(void)       /* we don't do this yet */
+{
+       pm_intr();
+       return 1;       /* mimic mrg_pmintr in macrom.h just in case */
+}
+#endif
+
+/* 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[MAX_ADB_MSG_LENGTH];
+        int     result;
+        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,
+                    (void *) &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));
+                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[MAX_ADB_MSG_LENGTH];
+        int     result;
+        int     flag = 0;
+
+        switch (adbHardware) {
+        case ADB_HW_II:
+               return -1;
+
+        case ADB_HW_IISI:
+                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_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_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_UNKNOWN:
+       default:
+                return -1;
+        }
+}
+
+
+int 
+adb_poweroff(void)
+{
+        u_char output[MAX_ADB_MSG_LENGTH];
+        int     result;
+
+        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;
+
+       /* TO DO: some cuda models claim to do soft power - check out */
+        case ADB_HW_II:                        /* II models don't do soft power */
+       case ADB_HW_CUDA:               /* cuda doesn't do soft power */
+        case ADB_HW_UNKNOWN:
+       default:
+                return -1;
+        }
+}                               /* adb_poweroff */
+
+int 
+adb_prog_switch_enable(void)
+{
+        u_char output[MAX_ADB_MSG_LENGTH];
+        int     result;
+        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 */
+        case ADB_HW_UNKNOWN:
+       default:
+                return -1;
+        }
+}                               /* adb_prog_switch_enable */
+
+int 
+adb_prog_switch_disable(void)
+{
+        u_char output[MAX_ADB_MSG_LENGTH];
+        int     result;
+        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;
+        }
+}                               /* adb_prog_switch_disable */
+
+#ifdef HWDIRECT
+
+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
index c4e3fe5..4b0869c 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: adbsys.c,v 1.6 1997/01/24 01:35:28 briggs Exp $       */
+/*     $OpenBSD: adbsys.c,v 1.7 1997/02/23 06:04:54 briggs Exp $       */
 /*     $NetBSD: adbsys.c,v 1.24 1997/01/13 07:01:23 scottr Exp $       */
 
 /*-
 #include <sys/param.h>
 #include <sys/systm.h>
 
-#include <machine/adbsys.h>
 #include <machine/cpu.h>
 #include <machine/macinfo.h>
 #include <machine/viareg.h>
 
-#include "adbvar.h"
-#include "../mac68k/macrom.h"
+#include <arch/mac68k/mac68k/macrom.h>
+#include <arch/mac68k/dev/adbvar.h>
 
 extern struct mac68k_machine_S mac68k_machine;
 
@@ -182,10 +181,13 @@ adb_init()
                return;
        }
 
+#ifndef HWDIRECT               /* We don't care about ADB ROM driver if we are
+                                * using the HWDIRECT method for ADB/PRAM/RTC. */
        if (!mrg_romready()) {
                printf("adb: no ROM ADB driver in this kernel for this machine\n");
                return;
        }
+#endif
        printf("adb: bus subsystem\n");
 #ifdef MRG_DEBUG
        printf("adb: call mrg_initadbintr\n");
@@ -199,12 +201,21 @@ adb_init()
        /* ADBReInit pre/post-processing */
        JADBProc = adb_jadbproc;
 
-       /* Initialize ADB */
+       /*
+        * Initialize ADB
+        *
+        * If using HWDIRECT method to access ADB, then call
+        * ADBReInit directly.  Otherwise use ADB AlternateInit()
+        */
+#ifdef HWDIRECT
+       printf("adb: calling ADBReInit\n");
+       ADBReInit();
+#else
 #ifdef MRG_DEBUG
        printf("adb: calling ADBAlternateInit.\n");
 #endif
-
        ADBAlternateInit();
+#endif
 
 #ifdef MRG_DEBUG
        printf("adb: done with ADBReInit\n");
index 97e3886..3070587 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: adbvar.h,v 1.4 1997/01/24 01:35:28 briggs Exp $       */
+/*     $OpenBSD: adbvar.h,v 1.5 1997/02/23 06:04:55 briggs Exp $       */
 /*     $NetBSD: adbvar.h,v 1.5 1997/01/13 07:01:24 scottr Exp $        */
 
 /*-
@@ -31,6 +31,8 @@
  * 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;
@@ -64,3 +66,25 @@ void extdms_complete __P((void));
 /* adbsys.c */
 void   adb_complete __P((caddr_t buffer, caddr_t data_area, int adb_command));
 void   extdms_init __P((int));
+
+#ifdef HWDIRECT
+
+/* 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
diff --git a/sys/arch/mac68k/dev/pm_direct.c b/sys/arch/mac68k/dev/pm_direct.c
new file mode 100644 (file)
index 0000000..90ab35a
--- /dev/null
@@ -0,0 +1,1098 @@
+/*     $OpenBSD: pm_direct.c,v 1.1 1997/02/23 06:04:56 briggs Exp $    */
+/*  pm_direct.c 1.22 01/09/97 Takashi Hamada */
+
+/*
+ * Copyright (C) 1997 Takashi Hamada
+ * 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 Takashi HAMADA
+ * 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.
+ */
+
+
+/* #define     PM_DEBUG        1 */
+/* #define     PM_GRAB_SI      1 */
+
+#include <sys/types.h>
+#include <sys/cdefs.h>
+#include <sys/systm.h>
+
+#include <machine/adbsys.h>
+#include <machine/cpu.h>
+#include <machine/macinfo.h>
+#include <machine/param.h>
+#include <machine/viareg.h>
+
+#include <arch/mac68k/mac68k/macrom.h>
+#include <arch/mac68k/dev/adbvar.h>
+
+#include "pm_direct.h"
+
+/* hardware dependent values */
+extern u_short ADBDelay;
+extern u_int32_t HwCfgFlags3;
+
+/* define the types of the Power Manager */
+#define PM_HW_UNKNOWN          0x00    /* don't know */
+#define PM_HW_PB1XX            0x01    /* PowerBook 1XX series */
+#define        PM_HW_PB5XX             0x02    /* PowerBook Duo and 5XX series */
+
+/* useful macros */
+#define PM_SR()                        via_reg(VIA1, vSR)
+#define PM_VIA_INTR_ENABLE()   via_reg(VIA1, vIER) = 0x90
+#define PM_VIA_INTR_DISABLE()  via_reg(VIA1, vIER) = 0x10
+#define PM_VIA_CLR_INTR()      via_reg(VIA1, vIFR) = 0x90
+#define PM_SET_STATE_ACKON()   via_reg(VIA2, vBufB) |= 0x04
+#define PM_SET_STATE_ACKOFF()  via_reg(VIA2, vBufB) &= ~0x04
+#define PM_IS_ON               ( 0x02 == (via_reg(VIA2, vBufB) & 0x02) )
+#define PM_IS_OFF              ( 0x00 == (via_reg(VIA2, vBufB) & 0x02) )
+
+/* 
+ * Valiables for internal use
+ */
+int    pmHardware = PM_HW_UNKNOWN;
+u_short        pm_existent_ADB_devices = 0x0;  /* each bit expresses the existent ADB device */
+u_int  pm_LCD_brightness = 0x0;
+u_int  pm_LCD_contrast = 0x0;
+u_int  pm_counter = 0;                 /* clock count */
+
+/* these values shows that number of data returned after 'send' cmd is sent */
+char pm_send_cmd_type[] = {
+       0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+       0x01,0x01,0xff,0xff,0xff,0xff,0xff,0xff, 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0x00,
+       0xff,0x00,0x02,0x01,0x01,0xff,0xff,0xff, 0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+       0x04,0x14,0xff,0xff,0xff,0xff,0xff,0xff, 0x00,0x00,0x02,0xff,0xff,0xff,0xff,0xff,
+       0x01,0x01,0xff,0xff,0xff,0xff,0xff,0xff, 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,
+       0x01,0x00,0x02,0x02,0xff,0x01,0x03,0x01, 0x00,0x01,0x00,0x00,0x00,0xff,0xff,0xff,
+       0x02,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,
+       0x01,0x01,0x01,0xff,0xff,0xff,0xff,0xff, 0x00,0x00,0xff,0xff,0xff,0xff,0x04,0x04,
+       0x04,0xff,0x00,0xff,0xff,0xff,0xff,0xff, 0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+       0x01,0x02,0xff,0xff,0xff,0xff,0xff,0xff, 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,
+       0x02,0x02,0x02,0x04,0xff,0x00,0xff,0xff, 0x01,0x01,0x03,0x02,0xff,0xff,0xff,0xff,
+       0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+       0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+       0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x01,0x01,0xff,0xff,0x00,0x00,0xff,0xff,
+       0xff,0x04,0x00,0xff,0xff,0xff,0xff,0xff, 0x03,0xff,0x00,0xff,0x00,0xff,0xff,0x00,
+       0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
+};
+
+/* these values shows that number of data returned after 'receive' cmd is sent */
+char pm_receive_cmd_type[] = {
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x02,0x02,0xff,0xff,0xff,0xff,0xff,0x00,
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x05,0x15,0xff,0xff,0xff,0xff,0xff,0xff,
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x02,0x02,0xff,0xff,0xff,0xff,0xff,0xff,
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x02,0x00,0x03,0x03,0xff,0xff,0xff,0xff,
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x04,0x04,0x03,0x09,0xff,0xff,0xff,0xff,
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x01,
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x06,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x02,0x02,0xff,0xff,0xff,0xff,0xff,0xff,
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x02,0x00,0x00,0x00,0xff,0xff,0xff,0xff,
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x02,0x02,0xff,0xff,0x02,0xff,0xff,0xff,
+       0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00, 0xff,0xff,0x02,0xff,0xff,0xff,0xff,0x00,
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+};
+
+
+/*
+ * Define the private functions
+ */
+
+/* for debugging */
+#ifdef PM_DEBUG
+void pm_printerr __P(( char *, int, int, char * ));
+#endif
+
+int pm_wait_busy __P((int));
+int pm_wait_free __P((int));
+
+/* these functions are for the PB1XX series */
+int pm_receive_pm1 __P((u_char *));
+int pm_send_pm1 __P((u_char,int));
+int pm_pmgrop_pm1 __P((PMData *));
+void pm_intr_pm1 __P((void));
+
+/* these functions are for the PB Duo series and the PB 5XX series */
+int pm_receive_pm2 __P((u_char *));
+int pm_send_pm2 __P((u_char));
+int pm_pmgrop_pm2 __P((PMData *));
+void pm_intr_pm2 __P((void));
+
+/* this function is MRG-Based (for testing) */
+int pm_pmgrop_mrg __P((PMData *));
+
+/* these functions are called from adb_direct.c */
+void pm_setup_adb __P((void));
+void pm_check_adb_devices __P((int));
+void pm_intr __P((void));
+int pm_adb_op __P((u_char *, void *, void *, int));
+
+/* these functions also use the valiables of adb_direct.c */
+void pm_adb_get_TALK_result __P((PMData *));
+void pm_adb_get_ADB_data __P((PMData *));
+void pm_adb_poll_next_device_pm1 __P((PMData *));
+
+
+/*
+ * These valiables are in adb_direct.c.
+ */
+extern u_char  *adbBuffer;     /* pointer to user data area */
+#define MAX_ADB_MSG_LENGTH     20
+extern u_char  adbInputBuffer[MAX_ADB_MSG_LENGTH];      /* data input buffer */
+extern void    *adbCompRout;   /* pointer to the completion routine */
+extern void    *adbCompData;   /* pointer to the completion routine data */
+extern int     adbWaiting;     /* waiting for return data from the device */
+extern int     adbWaitingCmd;  /* ADB command we are waiting for */
+extern int     adbStarting;    /* doing ADB reinit, so do "polling" differently */
+
+/*
+ * Define the external functions
+ */
+extern int zshard(int);                        /* from zs.c */
+extern void adb_comp_exec(void);       /* from adb_direct.c */
+
+
+#ifdef PM_DEBUG
+/*
+ * This function dumps contents of the PMData
+ */
+void
+pm_printerr(ttl, rval, num, data)
+       char    *ttl;
+       int     rval;
+       int     num;
+       char    *data;
+{
+       int i;
+
+       printf( "pm: %s:%04x %02x ", ttl, rval, num );
+       for( i=0; i<num; i++ )
+               printf( "%02x ", data[i] );
+       printf( "\n" );
+}
+#endif
+
+
+
+/*
+ * Check the hardware type of the Power Manager
+ */
+void
+pm_setup_adb(void)
+{
+       switch (mac68k_machine.machineid) {
+               case MACH_MACPB140:
+               case MACH_MACPB145:
+               case MACH_MACPB150:
+               case MACH_MACPB160:
+               case MACH_MACPB165:
+               case MACH_MACPB165C:
+               case MACH_MACPB170:
+               case MACH_MACPB180:
+               case MACH_MACPB180C:
+                       pmHardware = PM_HW_PB1XX;
+                       break;
+               case MACH_MACPB210:
+               case MACH_MACPB230:
+               case MACH_MACPB250:
+               case MACH_MACPB270:
+               case MACH_MACPB280:
+               case MACH_MACPB280C:
+               case MACH_MACPB500:
+                       pmHardware = PM_HW_PB5XX;
+                       break;
+               default:
+                       break;
+       }
+}
+
+
+/*
+ * Check the existent ADB devices
+ */
+void
+pm_check_adb_devices(id)
+       int id;
+{
+       u_short ed = 0x1;
+
+       ed <<= id;
+       pm_existent_ADB_devices |= ed;
+}
+
+
+/*
+ * Wait until PM IC is busy
+ */
+int
+pm_wait_busy(delay)
+       int delay;
+{
+       while(PM_IS_ON) {
+#ifdef PM_GRAB_SI
+               zshard(0);              /* grab any serial interrupts */
+#endif
+               if ((--delay) < 0)
+                       return( 1 );    /* timeout */
+       }
+       return( 0 );
+}
+
+
+/*
+ * Wait until PM IC is free
+ */
+int
+pm_wait_free(delay)
+       int delay;
+{
+       while(PM_IS_OFF) {
+#ifdef PM_GRAB_SI
+               zshard(0);              /* grab any serial interrupts */
+#endif
+               if ((--delay) < 0)
+                       return( 0 );    /* timeout */
+       }
+       return( 1 );
+}
+
+
+
+/*
+ * Functions for the PB1XX series
+ */
+
+/*
+ * Receive data from PM for the PB1XX series
+ */
+int
+pm_receive_pm1(data)
+       u_char *data;
+{
+       int rval = 0xffffcd34;
+
+       via_reg(VIA2, vDirA) = 0x00;
+
+       switch( 1 ) {
+               default:
+                       if (pm_wait_busy( 0x40 ) != 0)
+                               break;                  /* timeout */
+
+                       PM_SET_STATE_ACKOFF();
+                       *data = via_reg(VIA2, 0x200);
+
+                       rval = 0xffffcd33;
+                       if (pm_wait_free( 0x40 ) == 0)
+                               break;                  /* timeout */
+
+                       rval = 0x00;
+                       break;
+       }
+
+       PM_SET_STATE_ACKON();
+       via_reg(VIA2, vDirA) = 0x00;
+
+       return( rval );
+}
+
+
+
+/*
+ * Send data to PM for the PB1XX series
+ */
+int
+pm_send_pm1(data, delay)
+       u_char data;
+       int delay;
+{
+       int     rval;
+
+       via_reg(VIA2, vDirA) = 0xff;
+       via_reg(VIA2, 0x200) = data;
+
+       PM_SET_STATE_ACKOFF();
+       if (pm_wait_busy( 0x400 ) != 0) {
+               PM_SET_STATE_ACKON();
+               via_reg(VIA2, vDirA) = 0x00;
+
+               return( 0xffffcd36 );           
+       }
+
+       rval = 0x0;
+       PM_SET_STATE_ACKON();
+       if (pm_wait_free( 0x40 ) == 0)
+               rval = 0xffffcd35;
+
+       PM_SET_STATE_ACKON();
+       via_reg(VIA2, vDirA) = 0x00;
+
+       return( rval );
+}
+
+
+/*
+ * My PMgrOp routine for the PB1XX series
+ */
+int
+pm_pmgrop_pm1(pmdata)
+       PMData *pmdata;
+{
+       int     i;
+       int     s = 0x81815963;
+       u_char  via1_vIER, via1_vDirA;
+       int     rval = 0;
+       int     num_pm_data = 0;
+       u_char  pm_cmd; 
+       u_char  pm_data;
+       u_char  *pm_buf;
+
+       /* disable all inetrrupts but PM */
+       via1_vIER = via_reg(VIA1, vIER);
+       PM_VIA_INTR_DISABLE();
+
+       via1_vDirA = via_reg(VIA1, vDirA);
+
+       switch( pmdata->command ) {
+               default:
+                       for( i=0; i<7; i++ ) {
+                               via_reg(VIA2, vDirA) = 0x00;    
+
+                               /* wait until PM is free */
+                               if (pm_wait_free( ADBDelay ) == 0) {    /* timeout */
+                                       via_reg(VIA2, vDirA) = 0x00;
+                                       /* restore formar value */
+                                       via_reg(VIA1, vDirA) = via1_vDirA;
+                                       via_reg(VIA1, vIER) = via1_vIER;
+                                       return( 0xffffcd38 );
+                               }
+
+                               switch( mac68k_machine.machineid ) {
+                                       case MACH_MACPB160:
+                                       case MACH_MACPB165:
+                                       case MACH_MACPB165C:
+                                       case MACH_MACPB180:
+                                       case MACH_MACPB180C:
+                                               {
+                                                       int delay = ADBDelay * 16;
+
+                                                       via_reg(VIA2, vDirA) = 0x00;
+                                                       while((via_reg(VIA2, 0x200) == 0x7f) && (delay >= 0))
+                                                               delay--;
+
+                                                       if (delay < 0) {        /* timeout */
+                                                               via_reg(VIA2, vDirA) = 0x00;
+                                                               /* restore formar value */
+                                                               via_reg(VIA1, vIER) = via1_vIER;
+                                                               return( 0xffffcd38 );
+                                                       }
+                                               }
+                               } /* end switch */
+
+                               s=splhigh();
+
+                               via1_vDirA = via_reg(VIA1, vDirA);
+                               via_reg(VIA1, vDirA) &= 0x7f;
+
+                               pm_cmd = (u_char)(pmdata->command & 0xff);
+                               if ((rval = pm_send_pm1( pm_cmd, ADBDelay*8 )) == 0)    /* succeeded to send PM command */
+                                       break;
+
+                               via_reg(VIA1, vDirA) = via1_vDirA;
+                               splx(s);
+                       } /* end for */
+
+                       /* failed to send a command */
+                       if (i == 7) {
+                               via_reg(VIA2, vDirA) = 0x00;
+                               /* restore formar value */
+                               via_reg(VIA1, vDirA) = via1_vDirA;
+                               via_reg(VIA1, vIER) = via1_vIER;
+                                       return( 0xffffcd38 );
+                       }
+
+                       /* send # of PM data */
+                       num_pm_data = pmdata->num_data;
+                       if ((rval = pm_send_pm1( (u_char)(num_pm_data & 0xff), ADBDelay*8 )) != 0)
+                               break;                  /* timeout */
+
+                       /* send PM data */
+                       pm_buf = (u_char *)pmdata->s_buf;
+                       for( i=0; i<num_pm_data; i++ )
+                               if((rval = pm_send_pm1( pm_buf[i], ADBDelay*8 )) != 0)
+                                       break;                  /* timeout */
+                       if ((i != num_pm_data) && (num_pm_data != 0))
+                               break;                          /* timeout */
+
+                       /* Will PM IC return data? */
+                       if ((pm_cmd & 0x08) == 0) {
+                               rval = 0;
+                               break;                          /* no returned data */
+                       }
+
+                       rval = 0xffffcd37;
+                       if (pm_wait_busy( ADBDelay ) != 0) {
+                               break;                  /* timeout */
+                       }
+
+                       /* receive PM command */
+                       if ((rval = pm_receive_pm1( &pm_data )) != 0)
+                               break;
+
+                       pmdata->command = pm_data;
+
+                       /* receive number of PM data */
+                       if ((rval = pm_receive_pm1( &pm_data )) != 0)
+                               break;                          /* timeout */
+                       num_pm_data = pm_data;
+                       pmdata->num_data = num_pm_data;
+
+                       /* receive PM data */
+                       pm_buf = (u_char *)pmdata->r_buf;
+                       for( i=0; i<num_pm_data; i++ ) {
+                               if ((rval = pm_receive_pm1( &pm_data )) != 0)
+                                       break;                          /* timeout */
+                               pm_buf[i] = pm_data;
+                       }
+
+                       rval = 0;
+       }
+
+       via_reg(VIA2, vDirA) = 0x00;    
+
+       /* restore formar value */
+       via_reg(VIA1, vDirA) = via1_vDirA;
+       via_reg(VIA1, vIER) = via1_vIER;
+       if (s != 0x81815963)
+               splx(s);
+
+       return( rval );
+}
+
+
+/*
+ * My PM interrupt routine for PB100-series
+ */
+void
+pm_intr_pm1(void)
+{
+       int     s;
+       int     rval;
+       PMData  pmdata;
+
+       s = splhigh();
+
+       PM_VIA_CLR_INTR();                              /* clear VIA1 interrupt */
+
+       /* ask PM what happend */
+       pmdata.command = 0x78;
+       pmdata.num_data = 0;
+       pmdata.data[0] = pmdata.data[1] = 0;
+       pmdata.s_buf = &pmdata.data[2];
+       pmdata.r_buf = &pmdata.data[2];
+       rval = pm_pmgrop_pm1( &pmdata );
+       if (rval != 0) {
+#ifdef PM_DEBUG
+               printf( "pm: PM is not ready. error code=%08x\n", rval );
+#endif
+               splx(s);
+       }
+
+       if ((pmdata.data[2] & 0x10) == 0x10) {
+               if ((pmdata.data[2] & 0x0f) == 0) {     /* ADB data that were requested by TALK command */
+                       pm_adb_get_TALK_result(&pmdata);
+               } else if ((pmdata.data[2] & 0x08) == 0x8) {    /* PM is requesting to poll  */
+                       pm_adb_poll_next_device_pm1(&pmdata);
+               } else if ((pmdata.data[2] & 0x04) == 0x4) {    /* ADB device event */
+                       pm_adb_get_ADB_data(&pmdata);
+               }
+       } else {
+#ifdef PM_DEBUG
+               pm_printerr( "driver does not supported this event.", rval,  pmdata.num_data, pmdata.data );
+#endif
+       }
+
+       splx(s);
+}
+
+
+
+/*
+ * Functions for the PB Duo series and the PB 5XX series
+ */
+
+/*
+ * Receive data from PM for the PB Duo series and the PB 5XX series
+ */
+int
+pm_receive_pm2(data)
+       u_char *data;
+{
+       int     i;
+       int     rval;
+
+       rval = 0xffffcd34;
+
+       switch( 1 ) {
+               default:
+                       /* set VIA SR to input mode */
+                       via_reg(VIA1, vACR) |= 0x0c;
+                       via_reg(VIA1, vACR) &= ~0x10;
+                       i = PM_SR();
+
+                       PM_SET_STATE_ACKOFF();
+                       if (pm_wait_busy((int)ADBDelay*32) != 0)
+                               break;          /* timeout */
+
+                       PM_SET_STATE_ACKON();
+                       rval = 0xffffcd33;
+                       if (pm_wait_free((int)ADBDelay*32) == 0)
+                               break;          /* timeout */
+
+                       *data = PM_SR();
+                       rval = 0;
+
+                       break;
+       }
+
+       PM_SET_STATE_ACKON();
+       via_reg(VIA1, vACR) |= 0x1c;
+
+       return( rval );
+}      
+
+
+
+/*
+ * Send data to PM for the PB Duo series and the PB 5XX series
+ */
+int
+pm_send_pm2(data)
+       u_char data;
+{
+       int     rval;
+
+       via_reg(VIA1, vACR) |= 0x1c;
+       PM_SR() = data;
+
+       PM_SET_STATE_ACKOFF();
+       rval = 0xffffcd36;
+       if (pm_wait_busy((int)ADBDelay*32) != 0) {
+               PM_SET_STATE_ACKON();
+
+               via_reg(VIA1, vACR) |= 0x1c;
+
+               return( rval );         
+       }
+
+       PM_SET_STATE_ACKON();
+       rval = 0xffffcd35;
+       if (pm_wait_free((int)ADBDelay*32) != 0)
+               rval = 0;
+
+       PM_SET_STATE_ACKON();
+       via_reg(VIA1, vACR) |= 0x1c;
+
+       return( rval );
+}
+
+
+
+/*
+ * My PMgrOp routine for the PB Duo series and the PB 5XX series
+ */
+int
+pm_pmgrop_pm2(pmdata)
+       PMData *pmdata;
+{
+       int     i;
+       int     s;
+       u_char  via1_vIER;
+       int     rval = 0;
+       int     num_pm_data = 0;
+       u_char  pm_cmd; 
+       short   pm_num_rx_data;
+       u_char  pm_data;
+       u_char  *pm_buf;
+
+       s=splhigh();
+
+       /* disable all inetrrupts but PM */
+       via1_vIER = 0x10;
+       via1_vIER &= via_reg(VIA1, vIER);
+       via_reg(VIA1, vIER) = via1_vIER;
+       if (via1_vIER != 0x0)
+               via1_vIER |= 0x80;
+
+       switch( pmdata->command ) {
+               default:
+                       /* wait until PM is free */
+                       pm_cmd = (u_char)(pmdata->command & 0xff);
+                       rval = 0xcd38;
+                       if (pm_wait_free( ADBDelay * 4 ) == 0)
+                               break;                  /* timeout */
+
+                       if (HwCfgFlags3 & 0x00200000) {         /* PB 160, PB 165(c), PB 180(c) ? */
+                               int     delay = ADBDelay * 16;
+
+                               via_reg(VIA2, vDirA) = 0x00;
+                               while((via_reg(VIA2, 0x200) == 0x07) && (delay >= 0))
+                                       delay--;
+
+                               if (delay < 0) {
+                                       rval = 0xffffcd38;
+                                       break;          /* timeout */
+                               }
+                       }
+
+                       /* send PM command */
+                       if ((rval = pm_send_pm2( (u_char)(pm_cmd & 0xff) )))
+                               break;                          /* timeout */
+
+                       /* send number of PM data */
+                       num_pm_data = pmdata->num_data;
+                       if (HwCfgFlags3 & 0x00020000) {         /* PB Duo, PB 5XX */
+                               if (pm_send_cmd_type[pm_cmd] < 0) {
+                                       if ((rval = pm_send_pm2( (u_char)(num_pm_data & 0xff) )) != 0)
+                                               break;          /* timeout */
+                                       pmdata->command = 0;
+                               }
+                       } else {                                /* PB 1XX series ? */
+                               if ((rval = pm_send_pm2( (u_char)(num_pm_data & 0xff) )) != 0)
+                                       break;                  /* timeout */
+                       }                       
+                       /* send PM data */
+                       pm_buf = (u_char *)pmdata->s_buf;
+                       for( i=0; i<num_pm_data; i++ )
+                               if((rval = pm_send_pm2( pm_buf[i] )) != 0)
+                                       break;                  /* timeout */
+                       if (i != num_pm_data)
+                               break;                          /* timeout */
+
+
+                       /* check if PM will send me data  */
+                       pm_num_rx_data = pm_receive_cmd_type[pm_cmd];
+                       pmdata->num_data = pm_num_rx_data;
+                       if (pm_num_rx_data == 0) {
+                               rval = 0;
+                               break;                          /* no return data */
+                       }
+
+                       /* receive PM command */
+                       pm_data = pmdata->command;
+                       if (HwCfgFlags3 & 0x00020000) {         /* PB Duo, PB 5XX */
+                               pm_num_rx_data--;
+                               if (pm_num_rx_data == 0)
+                                       if ((rval = pm_receive_pm2( &pm_data )) != 0) {
+                                               rval = 0xffffcd37;
+                                               break;
+                                       }
+                               pmdata->command = pm_data;
+                       } else {                                /* PB 1XX series ? */
+                               if ((rval = pm_receive_pm2( &pm_data )) != 0) {
+                                       rval = 0xffffcd37;
+                                       break;
+                               }
+                               pmdata->command = pm_data;
+                       }
+
+                       /* receive number of PM data */
+                       if (HwCfgFlags3 & 0x00020000) {         /* PB Duo, PB 5XX */
+                               if (pm_num_rx_data < 0) {
+                                       if ((rval = pm_receive_pm2( &pm_data )) != 0)
+                                               break;          /* timeout */
+                                       num_pm_data = pm_data;
+                               } else
+                                       num_pm_data = pm_num_rx_data;
+                               pmdata->num_data = num_pm_data;
+                       } else {                                /* PB 1XX serias ? */
+                               if ((rval = pm_receive_pm2( &pm_data )) != 0)
+                                       break;                  /* timeout */
+                               num_pm_data = pm_data;
+                               pmdata->num_data = num_pm_data;
+                       }
+
+                       /* receive PM data */
+                       pm_buf = (u_char *)pmdata->r_buf;
+                       for( i=0; i<num_pm_data; i++ ) {
+                               if ((rval = pm_receive_pm2( &pm_data )) != 0)
+                                       break;                  /* timeout */
+                               pm_buf[i] = pm_data;
+                       }
+
+                       rval = 0;
+       }
+
+       /* restore former value */
+       via_reg(VIA1, vIER) = via1_vIER;
+       splx(s);
+
+       return( rval );
+}
+
+
+/*
+ * My PM interrupt routine for the PB Duo series and the PB 5XX series
+ */
+void
+pm_intr_pm2(void)
+{
+       int     s;
+       int     rval;
+       PMData  pmdata;
+
+       s = splhigh();
+
+       PM_VIA_CLR_INTR();                              /* clear VIA1 interrupt */
+                                                       /* ask PM what happend */
+       pmdata.command = 0x78;
+       pmdata.num_data = 0;
+       pmdata.s_buf = &pmdata.data[2];
+       pmdata.r_buf = &pmdata.data[2];
+       rval = pm_pmgrop_pm2( &pmdata );
+       if (rval != 0) {
+#ifdef PM_DEBUG
+               printf( "pm: PM is not ready. error code: %08x\n", rval );
+#endif
+               splx(s);
+       }
+
+       switch( (u_int)(pmdata.data[2] & 0xff) ) {
+               case 0x00:                              /* 1 sec interrupt? */
+                       {
+                       break;
+                       }
+               case 0x80:                              /* 1 sec interrupt? */
+                       {
+                       pm_counter++;
+                       break;
+                       }
+               case 0x08:                              /* Brightness/Contrast button on LCD panel */
+                       {
+                       /* get brightness and contrast of the LCD */
+                       pm_LCD_brightness = (u_int)pmdata.data[3] & 0xff;
+                       pm_LCD_contrast = (u_int)pmdata.data[4] & 0xff;
+/*
+                       pm_printerr( "#08", rval, pmdata.num_data, pmdata.data );
+                       pmdata.command = 0x33;
+                       pmdata.num_data = 1;
+                       pmdata.s_buf = pmdata.data;
+                       pmdata.r_buf = pmdata.data;
+                       pmdata.data[0] = pm_LCD_contrast;
+                       rval = pm_pmgrop_pm2( &pmdata );
+                       pm_printerr( "#33", rval, pmdata.num_data, pmdata.data );
+*/
+                       /* this is an experimental code */
+                       pmdata.command = 0x41;
+                       pmdata.num_data = 1;
+                       pmdata.s_buf = pmdata.data;
+                       pmdata.r_buf = pmdata.data;
+                       pm_LCD_brightness = 0x7f - pm_LCD_brightness / 2;
+                       if (pm_LCD_brightness < 0x25)   pm_LCD_brightness = 0x25;
+                       if (pm_LCD_brightness > 0x5a)   pm_LCD_brightness = 0x7f;
+                       pmdata.data[0] = pm_LCD_brightness;
+                       rval = pm_pmgrop_pm2( &pmdata );
+                       break;
+                       }
+                                                       /* ADB data that were requested by TALK command */
+               case 0x10:
+               case 0x14:
+                       pm_adb_get_TALK_result(&pmdata);
+                       break;
+                                                       /* ADB device event */
+               case 0x16:
+               case 0x18:
+               case 0x1e:
+                       pm_adb_get_ADB_data(&pmdata);
+                       break;
+               default:
+                       {
+#ifdef PM_DEBUG
+                       pm_printerr( "driver does not supported this event.", pmdata.data[2], pmdata.num_data, pmdata.data );
+#endif
+                       }
+                       break;
+       }
+
+       splx(s);
+}
+
+
+/*
+ * MRG-based PMgrOp routine
+ */
+int
+pm_pmgrop_mrg(pmdata)
+       PMData *pmdata;
+{
+       u_int32_t rval=0;
+
+       asm("
+               movl    %1, a0
+               .word   0xa085
+               movl    d0, %0"
+               : "=g" (rval)
+               : "g" (pmdata)
+               : "a0", "d0" );
+
+       return rval;
+}
+
+
+/*
+ * My PMgrOp routine
+ */
+int
+pmgrop(pmdata)
+       PMData *pmdata;
+{
+       switch( pmHardware ) {
+               case PM_HW_PB1XX:
+                       {
+                       return( pm_pmgrop_pm1(pmdata) );
+                       break;
+                       }
+               case PM_HW_PB5XX:
+                       {
+                       return( pm_pmgrop_pm2(pmdata) );
+                       break;
+                       }
+               default:
+/*                     return( pmgrop_mrg(pmdata) );   */
+                       return( -1 );
+       }
+}
+
+
+/*
+ * My PM interrupt routine
+ */
+void
+pm_intr(void)
+{
+       switch( pmHardware ) {
+               case PM_HW_PB1XX:
+                       {
+                       pm_intr_pm1();
+                       break;
+                       }
+               case PM_HW_PB5XX:
+                       {
+                       pm_intr_pm2();
+                       break;
+                       }
+               default:
+                       break;
+       }
+}
+
+
+
+/*
+ * Synchronous ADBOp routine for the Power Manager
+ */
+int
+pm_adb_op(buffer, compRout, data, command)
+       u_char *buffer;
+       void *compRout;
+       void *data;
+       int command;
+{
+       int     i,len;
+       int     s;
+       int     rval;
+       int     delay;
+       PMData  pmdata;
+
+       if (adbWaiting == 1)
+               return( -1 );
+
+       s = splhigh();
+       via_reg(VIA1, vIER) = 0x10;
+
+       adbBuffer = buffer;
+       adbCompRout = compRout;
+       adbCompData = data;
+
+       pmdata.command = 0x20;
+       pmdata.s_buf = pmdata.data;
+       pmdata.r_buf = pmdata.data;
+
+       if ((command & 0xc) == 0x8) {           /* if the command is LISTEN, add number of ADB data to number of PM data */
+               if (buffer != (u_char *)0)
+                       pmdata.num_data = buffer[0] + 3;
+       } else {
+               pmdata.num_data = 3;
+       }
+
+       pmdata.data[0] = (u_char)(command & 0xff);
+       pmdata.data[1] = 0;
+       if ((command & 0xc) == 0x8) {           /* if the command is LISTEN, copy ADB data to PM buffer */
+               if ((buffer != (u_char *)0) && (buffer[0] <= 24)) {
+                       pmdata.data[2] = buffer[0];             /* number of data */
+                       for( i=0; i<buffer[0]; i++ )
+                               pmdata.data[3 + i] = buffer[1 + i];
+               } else
+                       pmdata.data[2] = 0;
+       } else
+               pmdata.data[2] = 0;
+
+       rval = pmgrop( &pmdata );
+       if (rval != 0)
+               return( -1 );
+
+       if (adbWaiting == 0) {
+               adbWaiting = 1;
+               adbWaitingCmd = command;
+       }
+
+       PM_VIA_INTR_ENABLE();
+
+       /* wait until the PM interrupt is occured */
+       delay = 0x80000;
+       while(adbWaiting == 1) {
+               if ((via_reg(VIA1, vIFR) & 0x10) == 0x10)
+                       pm_intr();
+#ifdef PM_GRAB_SI
+                       zshard(0);              /* grab any serial interrupts */
+#endif
+               if ((--delay) < 0)
+                       return( -1 );
+       }
+
+       if (buffer != (u_char *)0) {
+               len = adbInputBuffer[3];
+               for (i=0; i<=len; i++)
+                               buffer[i] = adbInputBuffer[3 + i];
+               if (len < 0)
+                       buffer[0] = 0;  
+       }
+
+       /* this command enables the interrupt by operating ADB devices */ 
+       if (HwCfgFlags3 & 0x00020000) {         /* PB Duo series, PB 500 series */
+               pmdata.command = 0x20;
+               pmdata.num_data = 4;
+               pmdata.s_buf = pmdata.data;
+               pmdata.r_buf = pmdata.data;
+               pmdata.data[0] = 0x00;  
+               pmdata.data[1] = 0x86;  /* magic spell for awaking the PM */
+               pmdata.data[2] = 0x00;  
+               pmdata.data[3] = 0x0c;  /* each bit may express the existent ADB device */
+       } else {                                /* PB 100-series */
+               pmdata.command = 0x20;
+               pmdata.num_data = 3;
+               pmdata.s_buf = pmdata.data;
+               pmdata.r_buf = pmdata.data;
+               pmdata.data[0] = (u_char)(command & 0xf0) | 0xc;
+               pmdata.data[1] = 0x04;
+               pmdata.data[2] = 0x00;
+       }
+       rval = pmgrop( &pmdata );
+
+       splx(s);
+       return( rval );
+}
+
+
+void
+pm_adb_get_TALK_result(pmdata)
+       PMData *pmdata;
+{
+       int i;
+       int rx_pm_adb_cmd;
+
+       rx_pm_adb_cmd = (u_int)pmdata->data[3] & 0xff;
+
+       pmdata->data[2] &= 0xf;
+       pmdata->data[1] = pmdata->data[3];
+       pmdata->data[3] = pmdata->num_data - 2;
+
+       adbInputBuffer[0] = pmdata->num_data + 1;
+       for( i=1; i<pmdata->num_data+2; i++ )
+               adbInputBuffer[i] = pmdata->data[i];
+
+       if ((adbWaiting == 1) && (rx_pm_adb_cmd == adbWaitingCmd)) {
+               if (adbStarting == 0)
+                       adb_complete( &pmdata->data[3] , (long)0, adbWaitingCmd );
+               adbWaitingCmd = 0x0;
+                                       
+               adbWaiting = 0;
+               adb_comp_exec();
+               adbBuffer = (long)0;
+               adbCompRout = (long)0;
+               adbCompData = (long)0;
+       }
+}
+
+
+void
+pm_adb_get_ADB_data(pmdata)
+       PMData *pmdata;
+{
+       int i;
+
+       i = (u_int)pmdata->data[3] & 0xff;
+       pmdata->data[2] &= 0xf;
+       pmdata->data[1] = pmdata->data[3];
+       pmdata->data[3] = pmdata->num_data - 2;
+
+       adbInputBuffer[0] = pmdata->num_data + 1;
+       if (adbStarting == 0)
+               adb_complete( &pmdata->data[3] , (long)0, i );
+}
+
+
+void
+pm_adb_poll_next_device_pm1(pmdata)
+       PMData *pmdata;
+{
+       int i;
+       int ndid;
+       u_short bendid = 0x1;
+       int rval;
+       PMData tmp_pmdata;
+
+       /* find another existent ADB device to poll */
+       for( i=1; i<16; i++ ) {
+               ndid = (((pmdata->data[3] & 0xf0) >> 4) + i) & 0xf;
+               bendid <<= ndid;
+               if ((pm_existent_ADB_devices & bendid) != 0)
+                       break;
+       }
+
+       /* poll the other device */
+       tmp_pmdata.command = 0x20;
+       tmp_pmdata.num_data = 3;
+       tmp_pmdata.s_buf = tmp_pmdata.data;
+       tmp_pmdata.r_buf = tmp_pmdata.data;
+       tmp_pmdata.data[0] = (u_char)(ndid << 4) | 0xc;
+       tmp_pmdata.data[1] = 0x04;      /* magic spell for awaking the PM */
+       tmp_pmdata.data[2] = 0x00;
+       rval = pmgrop( &tmp_pmdata );
+}
+
+
diff --git a/sys/arch/mac68k/dev/pm_direct.h b/sys/arch/mac68k/dev/pm_direct.h
new file mode 100644 (file)
index 0000000..99b5cf0
--- /dev/null
@@ -0,0 +1,53 @@
+/*  pm_direct.h 1.0 01/02/97 Takashi Hamada */
+
+/*
+ * Copyright (C) 1997 Takashi Hamada
+ * 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 Takashi Hamada.
+ * 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.
+ */
+
+/*
+ * Public declarations that other routines may need.
+ */
+
+/* data structure of the command of the Power Manager */
+typedef        struct  {
+       short   command;                /* command of the Power Manager         */
+       short   num_data;               /* number of data                                       */
+       char    *s_buf;                 /* pointer to buffer for sending        */
+       char    *r_buf;                 /* pointer to buffer for receiving      */
+       char    data[32];               /* data buffer (is it too much?)        */
+}      PMData;
+
+int            pmgrop(PMData *);
+
+extern void pm_setup_adb __P((void));
+extern void pm_check_adb_devices __P((int));
+extern void pm_intr __P((void));
+extern int pm_adb_op __P((u_char *, void *, void *, int));
+extern void pm_init_adb_device __P((void));
+
index d3542a5..de4d909 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: machdep.c,v 1.28 1997/02/21 05:49:29 briggs Exp $     */
+/*     $OpenBSD: machdep.c,v 1.29 1997/02/23 06:04:59 briggs Exp $     */
 /*     $NetBSD: machdep.c,v 1.129 1997/01/09 07:20:46 scottr Exp $     */
 
 /*
 #include <vm/vm_page.h>
 
 #include <dev/cons.h>
+#include <arch/mac68k/mac68k/macrom.h>
+#include <arch/mac68k/dev/adbvar.h>
 
 #include <machine/viareg.h>
-#include "macrom.h"
 #include "ether.h"
 
 /* The following is used externally (sysctl_hw) */
index dbc19c0..bfef792 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: macrom.c,v 1.8 1997/01/24 01:35:49 briggs Exp $       */
+/*     $OpenBSD: macrom.c,v 1.9 1997/02/23 06:05:00 briggs Exp $       */
 /*     $NetBSD: macrom.c,v 1.30 1996/12/18 07:21:06 scottr Exp $       */
 
 /*-
@@ -120,6 +120,9 @@ caddr_t ResHndls[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 caddr_t ResHndls[]={0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
 #endif
 
+void   setup_egret __P((void));
+
+
 /*
  * Last straw functions; we didn't set them up, so freak out!
  * When someone sees these called, we can finally go back and
@@ -347,6 +350,10 @@ mrg_jkybdtaskpanic()       /* JKybdTask stopper */
        panic("Agh!  Called JKybdTask!\n");
 }
 
+#ifndef HWDIRECT       /* mrg_adbintr and mrg_pmintr are not defined
+                         * here if we are using the HWDIRECT method to
+                        * access the ADB/PRAM/RTC. They are
+                        * defined in adb_direct.c */
 long
 mrg_adbintr()  /* Call ROM ADB Interrupt */
 {
@@ -403,6 +410,7 @@ mrg_pmintr()        /* Call ROM PM Interrupt */
        }
        return(1);
 }
+#endif /* ifndef HWDIRECT */
 
 
 void
@@ -427,7 +435,7 @@ mrg_NewPtr()
        u_int32_t trapword;
        caddr_t ptr;
 
-       __asm(" movl    d1, %0
+       __asm(" movw    d1, %0
                movl    d0, %1"
                : "=g" (trapword), "=g" (numbytes) : : "d0", "d1");
 
@@ -654,16 +662,18 @@ mrg_aline_super(struct frame *frame)
        tron();
 #endif
 
-/*     put trapword in d1 */
-/*     put trapaddr in a1 */
-/*     put a0 in a0 */
-/*     put d0 in d0 */
-/* save a6 */
-/*     call the damn routine */
-/* restore a6 */
-/*     store d0 in d0bucket */
-/*     store a0 in d0bucket */
-/* This will change a1,d1,d0,a0 and possibly a6 */
+/*
+ *     put trapword in d1
+ *     put trapaddr in a1
+ *     put a0 in a0
+ *     put d0 in d0
+ * save a6
+ *     call the damn routine
+ * restore a6
+ *     store d0 in d0bucket
+ *     store a0 in d0bucket
+ * This will change a1,d1,d0,a0 and possibly a6
+ */
 
        __asm("
                movl    %2, a1
@@ -677,7 +687,7 @@ mrg_aline_super(struct frame *frame)
                : "=g" (a0bucket), "=g" (d0bucket)
 
                : "g" (trapaddr), "g" (trapword),
-                       "m" (frame->f_regs[0]), "m" (frame->f_regs[8])
+                 "m" (frame->f_regs[0]), "m" (frame->f_regs[8])
 
                : "d0", "d1", "a0", "a1", "a6"
 
@@ -979,9 +989,7 @@ mrg_init()
        }
 }
 
-static void    setup_egret __P((void));
-
-static void
+void
 setup_egret(void)
 {
        if (0 != mrg_InitEgret){
@@ -1034,6 +1042,10 @@ mrg_initadbintr()
                        HwCfgFlags, HwCfgFlags2, HwCfgFlags3);
        }
 
+#ifdef HWDIRECT                /* Extra Egret setup not required for the
+                        * HWDIRECT method. */
+        printf("mrg: skipping egret setup\n");
+#else
        /*
         * If we think there is an Egret in the machine, attempt to
         * set it up.  If not, just enable the interrupts (only on
@@ -1060,6 +1072,7 @@ mrg_initadbintr()
                if (mac68k_machine.do_graybars)
                        printf("mrg: ADB interrupts enabled.\n");
        }       
+#endif
 }
 
 /*
@@ -1229,6 +1242,7 @@ t:  walter@ghpc8.ihf.rwth-aachen.de\n");
 #endif
 }   
 
+#ifndef HWDIRECT
 void
 ADBAlternateInit(void)
 {
@@ -1246,3 +1260,4 @@ ADBAlternateInit(void)
                        : "a1", "a3");
        }
 }
+#endif
index 350b332..9bce888 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: macrom.h,v 1.4 1997/01/19 03:58:08 briggs Exp $       */
+/*     $OpenBSD: macrom.h,v 1.5 1997/02/23 06:05:02 briggs Exp $       */
 /*     $NetBSD: macrom.h,v 1.9 1996/05/25 14:45:35 briggs Exp $        */
 
 /*-
@@ -96,7 +96,7 @@ typedef struct {
        unsigned char   devType;
        unsigned char   origADBAddr;
        Ptr             dbServiceRtPtr;
-       Ptr             dbDataAreaAdd;
+       Ptr             dbDataAreaAddr;
 } ADBDataBlock;
 
 
@@ -108,6 +108,10 @@ int MyOwnTrap(
 void KnownRTS(
        void);
 
+#ifndef HWDIRECT       /* These routines are NOT defined here
+                        * if using the HWDIRECT method for accessing
+                        * the ADB/PRAM/RTC. They are 
+                        * defined in adb_direct.h */
 /* ADB Manager */
 int SetADBInfo(
        ADBSetInfoBlock *info,
@@ -129,6 +133,7 @@ int ADBOp(
        short   commandNum);
 void ADBAlternateInit(
        void);
+#endif
 
 /* Memory Manager */
 Ptr NewPtr(
index ec529dd..92595bc 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: macromasm.s,v 1.3 1996/05/26 18:36:26 briggs Exp $    */
+/*     $OpenBSD: macromasm.s,v 1.4 1997/02/23 06:05:03 briggs Exp $    */
 /*     $NetBSD: macromasm.s,v 1.11 1996/05/25 14:45:37 briggs Exp $    */
 
 /*-
        .global _panic
        .global _printf
 
+#ifndef HWDIRECT       /* These functions are NOT defined here if using the
+                        * HWDIRECT method of accessing the ADB/PRAM/RTC. 
+                        * They are in adb_direct.c. */
 /*
  * Most of the following glue just takes C function calls, converts
  * the parameters to the MacOS Trap parameters, and then tries to
@@ -216,6 +219,7 @@ _ADBOp:
        movl    sp@(16), d0
        .word 0xa07c
        rts
+#endif /* ifndef HWDIRECT */
 
 
 #if 0
index 86c1faf..8a22388 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: pram.c,v 1.4 1997/01/24 01:35:52 briggs Exp $ */
+/*     $OpenBSD: pram.c,v 1.5 1997/02/23 06:05:04 briggs Exp $ */
 /*     $NetBSD: pram.c,v 1.11 1996/10/21 05:42:29 scottr Exp $ */
 
 /*-
 #ifdef DEBUG
 #include <sys/systm.h>
 #endif
+#include <sys/param.h>
+
 #include <machine/viareg.h>
-#include "pram.h"
-#include "macrom.h"
+
+#include <arch/mac68k/mac68k/pram.h>
+#include <arch/mac68k/mac68k/macrom.h>
+#ifdef HWDIRECT
+#include <arch/mac68k/dev/adbvar.h>
+#endif
 
 #if DEBUG
 static char *convtime(unsigned long t)
@@ -146,3 +152,71 @@ pram_settime(unsigned long time)
    else
        return setPramTime(time);
 }
+
+#ifdef HWDIRECT         /* These routines are defined here only
+                         * when the HWDIRECT method for accessing
+                         * the ADB/PRAM/RTC is enabled. */
+
+extern int adbHardware;         /* from newadb.c */
+
+/*
+ * getPramTime
+ * This function can be called regrardless of the machine
+ * type. It calls the correct hardware-specific code.
+ * (It's sort of redundant with the above, but it was
+ * added later.)
+ */
+unsigned long
+getPramTime(void)
+{
+        unsigned long time;
+
+        switch (adbHardware) {
+        case ADB_HW_II:         /* access PRAM via VIA interface */
+                time=(long)getPramTimeII();
+                return time;
+
+        case ADB_HW_IISI:       /* access PRAM via pseudo-adb functions */
+                if (0 != adb_read_date_time(&time))
+                        return 0;
+                else
+                        return time;
+
+        case ADB_HW_PB:         /* don't know how to access this yet */
+                return 0;
+
+        case ADB_HW_UNKNOWN:
+        default:
+                return 0;
+        }
+}
+
+/*
+ * setPramTime
+ * This function can be called regrardless of the machine
+ * type. It calls the correct hardware-specific code.
+ * (It's sort of redundant with the above, but it was
+ * added later.)
+ */
+void
+setPramTime(unsigned long time)
+{
+        switch (adbHardware) {
+        case ADB_HW_II:         /* access PRAM via ADB interface */
+                setPramTimeII(time);
+                return;
+
+        case ADB_HW_IISI:       /* access PRAM via pseudo-adb functions */
+                adb_set_date_time(time);
+                return;
+
+        case ADB_HW_PB:         /* don't know how to access this yet */
+                return;
+
+        case ADB_HW_UNKNOWN:
+                return;
+        }
+
+}
+
+#endif  /* ifdef HWDIRECT */
index 877a9aa..172f505 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: pram.h,v 1.3 1996/05/26 18:36:31 briggs Exp $ */
+/*     $OpenBSD: pram.h,v 1.4 1997/02/23 06:05:05 briggs Exp $ */
 /*     $NetBSD: pram.h,v 1.3 1996/05/05 06:18:53 briggs Exp $  */
 
 /*
@@ -73,3 +73,11 @@ void                 setPramTime(unsigned long time);
 unsigned long  pram_readtime __P((void));
 void           pram_settime __P((unsigned long));
 
+#ifdef HWDIRECT                /* These functions exist only when ADB/PRAM/RTC
+                        * access is done via the HWDIRECT method. */
+
+unsigned long getPramTimeII(void);
+void setPramTimeII(unsigned long);
+
+#endif
+
index af40f5f..11b1e0d 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: pramasm.s,v 1.2 1996/05/26 18:36:32 briggs Exp $      */
+/*     $OpenBSD: pramasm.s,v 1.3 1997/02/23 06:05:05 briggs Exp $      */
 /*     $NetBSD: pramasm.s,v 1.4 1995/09/28 03:15:54 briggs Exp $       */
 
 /*
  * that are defined later in this file.
  */
 
+#ifndef HWDIRECT       /* These routines are NOT defined at all
+                         * if using the HWDIRECT method for accessing
+                         * the ADB/PRAM/RTC. */
+
        .text
 
        .even
@@ -140,3 +144,281 @@ _setPramTime:
        unlk    a6              |  clean up after ourselves
        rts                     |  and return to caller
 
+#else                          /* The following routines are the hardware
+                                * specific routines for the machines that
+                                * use the II-like method to access the PRAM,
+                                * and are only defined when the HWDIRECT method
+                                * is used to access the PRAM. */
+
+/*
+ *  The following are the C interface functions to RTC access functions
+ * that are defined later in this file.
+ */
+
+       .text
+
+       .even
+.globl _readPramII
+_readPramII:
+       link    a6,#-4          |  create a little home for ourselves
+       moveq   #0,d0           |  zero out our future command register
+       moveb   a6@(19),d0      |  move the length byte in
+       swap    d0              |  and make that the MSW
+       moveb   a6@(15),d0      |  now get out PRAM location
+       oriw    #0x0100,d0      |  and set up for non-extended read
+       movel   a6@(8),a0       |  get our data address
+       jbsr    _PRAMacc        |  and go read the data
+       unlk a6                 |  clean up after ourselves
+       rts                     |  and return to caller
+
+.globl _writePramII
+_writePramII:
+       link    a6,#-4          |  create a little home for ourselves
+       moveq   #0,d0           |  zero out our future command register
+       moveb   a6@(19),d0      |  move the length byte in
+       swap    d0              |  and make that the MSW
+       moveb   a6@(15),d0      |  now get out PRAM location
+       nop                     |  and set up for non-extended write 
+       movel   a6@(8),a0       |  get our data address
+       jbsr    _PRAMacc        |  and go write the data
+       unlk a6                 |  clean up after ourselves
+       rts                     |  and return to caller
+
+.globl _readExtPramII
+_readExtPramII:
+       link    a6,#-4          |  create a little home for ourselves
+       moveq   #0,d0           |  zero out our future command register
+       moveb   a6@(19),d0      |  move the length byte in
+       swap    d0              |  and make that the MSW
+       moveb   a6@(15),d0      |  now get out PRAM location
+       oriw    #0x0300,d0      |  and set up for extended read
+       movel   a6@(8),a0       |  get our data address
+       jbsr    _PRAMacc        |  and go read the data
+       unlk a6                 |  clean up after ourselves
+       rts                     |  and return to caller
+
+.globl _writeExtPramII
+_writeExtPramII:
+       link    a6,#-4          |  create a little home for ourselves
+       moveq   #0,d0           |  zero out our future command register
+       moveb   a6@(19),d0      |  move the length byte in
+       swap    d0              |  and make that the MSW
+       moveb   a6@(15),d0      |  now get out PRAM location
+       oriw    #0x0200,d0      |  and set up for extended write
+       movel   a6@(8),a0       |  get our data address
+       jbsr    _PRAMacc        |  and go write the data
+       unlk a6                 |  clean up after ourselves
+       rts                     |  and return to caller
+
+.globl _getPramTimeII
+_getPramTimeII:
+       link    a6,#-4          |  create a little home for ourselves
+       jbsr    _readClock      |  call the routine to read the time
+       unlk    a6              |  clean up after ourselves
+       rts                     |  and return to caller
+
+.globl _setPramTimeII
+_setPramTimeII:
+       link    a6,#-4          |  create a little home for ourselves
+       movel   a6@(8),d0       |  get the passed in long (seconds since 1904)
+       jbsr    _writeClock     |  call the routine to write the time
+       unlk    a6              |  clean up after ourselves
+       rts                     |  and return to caller
+
+/*
+ *  The following are the RTC access functions used by the interface
+ * routines, above.
+ */
+
+_readClock:
+       moveml  #0x7cc0, sp@-   | store off the regs we need
+       moveq   #00,d0          | zero out our result reg
+readagan:
+       moveq   #00,d5          | and our temp result reg
+       moveq   #03,d4          | set our count down reg to 4
+       movel   #0x00000081,d1  | read sec byte 0 first
+getSecb:
+       bsr     _Transfer       | get that byte
+       rorl    #8,d5           | shift our time to the right
+       swap    d1              | we want to access our new data
+       moveb   d1,d5           | move that byte to the spot we vacated
+       swap    d1              | return our PRAM command to orig. config
+       addqb   #4,d1           | increment to the next sec byte
+       dbf     d4,getSecb      | any more bytes to get ?
+       cmpl    d5,d0           | same secs value we as we just got ?
+       beq     gotTime         | we got a good time value
+       movel   d5,d0           | copy our current time to the compare reg
+       bra     readagan        | read the time again
+gotTime:
+       rorl    #8,d0           | make that last shift to correctly order
+                               |  time bytes!!!
+       movel   #0x00d50035,d1  | we have to set the write protect bit
+                               | so the clock doesn't run down !
+       bsr     _Transfer       | (so sezs Apple...)
+       moveml  sp@+, #0x033e   | restore our regs
+       rts                     | and return to caller
+
+_writeClock:
+       moveml  #0x78c0, sp@-   | store off the regs we need
+       moveq   #03,d4          | set our count down reg to 4
+       movel   #0x00550035,d1  | de-write-protect the PRAM
+       bsr     _Transfer       | so we can set our value
+       moveq   #1,d1           | write sec byte 0 first
+putSecb:
+       swap    d1              | we want access to data byte of command
+       moveb   d0,d1           | set our first secs byte
+       swap    d1              | and return command to orig. config
+       bsr     _Transfer       | write that byte
+       rorl    #8,d0           | shift our time to the right 
+       addqb   #4,d1           | increment to the next sec byte
+       dbf     d4,putSecb      | any more bytes to put ?
+       movel   #0x00d50035,d1  | we have to set the write protect bit
+                               | so the clock doesn't run down !
+       bsr     _Transfer       | (so sezs Apple...)
+       moveml  sp@+, #0x031e   | restore our regs
+       rts                     | and return to caller
+
+_PRAMacc:
+       moveml  #0xf8c0, sp@-   | store off the regs we'll use
+       moveq   #00,d3          | zero out our command reg
+       moveq   #00,d4          | zero out our count reg too
+       swap    d0              | we want the length byte
+       movew   d0,d4           | copy length byte to our counter reg
+       swap    d0              | and return command reg to prior state
+       subqb   #1,d4           | predecrement counter for use w/ DBF
+       movew   d0,d2           | copy command to d2
+       rorw    #8,d2           | rotate copy to examine flags
+       roxrw   #1,d2           | read/write bit out of param.
+       roxlb   #1,d3           | and into command reg
+       tstb    d3              | was it read (1) or write (0) ?
+       bne     NoWrit          | go around de-write protect logic
+       movel   #0x00550035,d1  | clear write protect bit of PRAM
+                               | (we really only need to zero the high
+                               |  bit, but other patterns don't work! )
+       moveml  #0x3000, sp@-   | store off the regs that'll change
+       bsr     _Transfer       | and go de-write protect RTC
+       moveml  sp@+, #0x000c   | reclaim our reg values
+NoWrit:
+       andib   #1,d2           | isolate the extended command bit
+       beq     oldPRAM         | it's zero, so do old PRAM style access
+NuPRAM:
+       moveb   d0,d2           | reget our PRAM location
+       lslw    #4,d3           | insert our template blanks
+       moveq   #2,d1           | set bit counter for 3 cycles
+threebit:
+       roxlb   #1,d2           | rotate address bit from d2
+       roxlw   #1,d3           | and into command in d3
+       dbf     d1,threebit     | until we've done bits 7-5
+       lslw    #1,d3           | and add a bit spacer
+       moveq   #4,d1           | ok, 5 bits to go...
+fivebit:
+       roxlb   #1,d2           | another addr bit out of d2
+       roxlw   #1,d3           | and into command template in d3
+       dbf     d1,fivebit      | til we've done bit 4-0
+       lslw    #2,d3           | more bit magic
+       oriw    #0x3880,d3      | set extended command bits
+       bra     Loaddata        | go load the rest of command for xfer rtn
+oldPRAM:
+       moveb   d0,d2           | reget our PRAM location
+       lslb    #1,d3           | add a template blank (bit)
+       rolb    #4,d2           | get low nibble of PRAM loc ready
+       moveq   #3,d1           | set our bit counter for 4 cycles
+fourbit:
+       roxlb   #1,d2           | bit out of PRAM loc
+       roxlb   #1,d3           | and bit into PRAM command
+       dbf     d1,fourbit      | until we've done the low nibble
+       lslb    #2,d3           | bump bits to type of command byte
+       orib    #0x41,d3        | set command bits (for access to $0-F!)
+       btst    #4,d2           | change to access $10-13 ?
+       beq     Loaddata        | nope, should stay the way it is
+       andib   #0x8F,d3        | clear bits 4-6 of current command
+       orib    #0x20,d3        | and set bit 5 (now accesses $10-13)
+Loaddata:
+       moveb   a0@,d1          | get our (data/dummy) byte into d1
+       swap    d1              | move (data/dummy) byte to MSW
+       movew   d3,d1           | now move command into d1
+tagain:        
+       bsr     _Transfer       | now execute that command
+       swap    d1              | we want access to (data/dummy) byte
+       moveb   d1,a0@+         | move (data/dummy) byte back to a0,
+       moveb   a0@,d1          | NEXT VICTIM!!
+       swap    d1              | now we want to tweak the command
+       addqw   #4,d1           | increment our memory addr by 1 (this even 
+                               | works if we want to dump across 32 byte
+                               | boundries for an extended command!!!
+                               | thanks to the oriw #$3880 above !!!)
+       dbf     d4,tagain       | repeat until we've got all we want
+       movel   #0x00d50035,d1  | remember that command to write the wp byte ?
+                               | set the high bit in the wp reg (Apple sezs
+                               | this way the battery won't wear down !! )
+       bsr     _Transfer       | so we'll play by the rules
+       moveml  sp@+, #0x031f   | restore all our registers
+       rts                     | and return to our gracious caller
+
+_Transfer:
+       movew   sr,sp@-         | store the SR (we'll change it!)
+       oriw    #0x0700,sr      | disable all interrupts
+       moveal  _Via1Base,a1    | move VIA1 addr in reference reg
+       moveq   #0,d2           | zero out d2 (it'll hold VIA1 reg B contents)
+       moveb   a1@,d2          | and get VIA1 reg B contents
+       andib   #0xF8,d2        | don't touch any but RTC bits
+                               | (and zero all those)
+       movew   d1,d3           | we want to manipulate our command
+       andiw   #0xFF00,d3      | zero the LSB
+       beq     oldPRAMc        | do an old PRAM style command
+xPRAMc:
+       rorw    #8,d1           | swap the command bytes (1st byte of 2)
+       bsr     writebyte       | and write the command byte
+       rorw    #8,d1           | swap the command bytes again (2nd byte of 2)
+       bsr     writebyte       | write that byte to RTC too
+       moveq   #0x1F,d3        | r/w bit is $F for an extended command
+                               | (but command is swapped to MSW!! so add $10)
+       bra     Rwbrnch         | go figure out if it's a read or a write cmd
+oldPRAMc:
+       bsr     writebyte       | only one byte for an old PRAM command
+       moveq   #0x17,d3        | r/w bit is $7 for and old PRAM command
+                               | ( command is swapped to MSW, add $10)
+Rwbrnch:
+       swap    d1              | better get that (data/dummy) byte ready
+       btst    d3,d1           | test bit no. d3 of reg d1 (read or write ?)
+       beq     Wtrue           | 0 = write, 1 = read (branch on write)
+Rtrue:
+       bsr     readbyte        | read a byte from the RTC
+       bra     Cleanup         | and call mom to clean up after us
+Wtrue:
+       bsr     writebyte       | write the data to the RTC
+Cleanup:
+       swap    d1              | move command to LSW again
+       bset    #2,a1@          | bring the RTC enable line high (end of xfer)
+       movew   sp@+,sr         | restore prior interrupt status
+       rts                     | and return to caller
+
+writebyte:
+       moveq   #7,d3           | set our bit counter to 8
+wagain:        
+       lsrb    #1,d2           | ditch the old data channel value
+       roxlb   #1,d1           | and move a new value to X
+       roxlb   #1,d2           | now move value from X to data channel
+       moveb   d2,a1@          | set our VIA1 reg B contents to match
+       bset    #1,a1@          | and finish strobing the clock line
+       dbf     d3,wagain       | do this until we've sent a whole byte
+       lsrb    #1,d2           | ditch the data channel value one last time
+       roxlb   #1,d1           | get rid of the extra X bit we've carried
+       lslb    #1,d2           | and restore d2 to prior status
+       rts                     | return to caller
+
+readbyte:
+       moveq   #7,d3           | set our bit counter to 8
+       bclr    #0,a1@(0x0400)  | set VIA1 reg B data line to input
+ragain:
+       bclr    #1,a1@          | strobe the clock line to make
+       bset    #1,a1@          | the data valid
+       moveb   a1@,d2          | and get out data byte 
+       lsrb    #1,d2           | get the data channel value to X
+       roxlb   #1,d1           | and move X to data byte
+       dbf     d3,ragain       | do this until we've received a whole byte
+       bset    #0,a1@(0x0400)  | and return RTC data line to output
+       rts                     | return to caller
+
+#endif                                 /* ifdef HWDIRECT */
+