--- /dev/null
+/* $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
--- /dev/null
+/* $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 );
+}
+
+
-/* $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
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 */
+