From 76fb5db2243b129c6b8e48adccfecb7944a16405 Mon Sep 17 00:00:00 2001 From: briggs Date: Sun, 23 Feb 1997 06:04:50 +0000 Subject: [PATCH] Integrate code from John P. Wittkoski and Takashi Hamada . This code interfaces directly to the hardware to support the ADB on many macs. It is enabled by "options HWDIRECT" in the configuration file. At some point, this should probably become the default method as interfacing to the ADB through the ROMs has been painful and sometimes problematic. This code should have functioning ADB support for: II series (II, SE/30, IIx, IIcx) IIsi series (IIsi, IIci, IIvx, IIvi) LC II, LC III Performa 400, 405, 430, 460, 465, 467, 600 Classic II, Color Classic, Color Classic II PB 5XX series Duo series PB 140,145,145b,160,(160c?),165,165c,170,180,180c Quadra 700,900,950 There is an off-chance that it will work on: PB 150, PB 190 Quadra/Centris 605,610,630,650,660AV,800,840AV LC 475,550,575,630 Performa 475,476,575,577,578,630 Note that functioning ADB support does not mean that everything else will work. I obviously do not own all of the above machines (does anyone? ;-)... Any reports are welcome. Many thanks to John Wittkoski and Takashi Hamada! --- sys/arch/mac68k/conf/TIGER | 3 +- sys/arch/mac68k/conf/files.mac68k | 10 +- sys/arch/mac68k/dev/adb.c | 9 +- sys/arch/mac68k/dev/adb_direct.c | 2204 ++++++++++++++++++++++++++++ sys/arch/mac68k/dev/adbsys.c | 23 +- sys/arch/mac68k/dev/adbvar.h | 26 +- sys/arch/mac68k/dev/pm_direct.c | 1098 ++++++++++++++ sys/arch/mac68k/dev/pm_direct.h | 53 + sys/arch/mac68k/mac68k/machdep.c | 5 +- sys/arch/mac68k/mac68k/macrom.c | 47 +- sys/arch/mac68k/mac68k/macrom.h | 9 +- sys/arch/mac68k/mac68k/macromasm.s | 6 +- sys/arch/mac68k/mac68k/pram.c | 80 +- sys/arch/mac68k/mac68k/pram.h | 10 +- sys/arch/mac68k/mac68k/pramasm.s | 284 +++- 15 files changed, 3824 insertions(+), 43 deletions(-) create mode 100644 sys/arch/mac68k/dev/adb_direct.c create mode 100644 sys/arch/mac68k/dev/pm_direct.c create mode 100644 sys/arch/mac68k/dev/pm_direct.h diff --git a/sys/arch/mac68k/conf/TIGER b/sys/arch/mac68k/conf/TIGER index b48c1ab985d..68d11848d3f 100644 --- a/sys/arch/mac68k/conf/TIGER +++ b/sys/arch/mac68k/conf/TIGER @@ -1,4 +1,4 @@ -# $OpenBSD: TIGER,v 1.1 1997/01/24 01:25:25 briggs Exp $ +# $OpenBSD: TIGER,v 1.2 1997/02/23 06:04:50 briggs Exp $ # $NetBSD: GENERIC,v 1.43 1996/09/22 06:49:09 scottr Exp $ # # Allen's Q700 @@ -38,6 +38,7 @@ options SYSVSHM,SYSVSEM,SYSVMSG options PPP_BSDCOMP,PPP_DEFLATE # Mac-specific options +options HWDIRECT options M68040 options FPSP options COMPAT_NOMID diff --git a/sys/arch/mac68k/conf/files.mac68k b/sys/arch/mac68k/conf/files.mac68k index 9c9b488a036..1b3663a1f57 100644 --- a/sys/arch/mac68k/conf/files.mac68k +++ b/sys/arch/mac68k/conf/files.mac68k @@ -1,4 +1,4 @@ -# $OpenBSD: files.mac68k,v 1.10 1997/01/24 01:35:26 briggs Exp $ +# $OpenBSD: files.mac68k,v 1.11 1997/02/23 06:04:51 briggs Exp $ # $NetBSD: files.mac68k,v 1.55 1997/01/21 09:43:45 thorpej Exp $ # mac68k-specific configuration info @@ -24,6 +24,8 @@ attach adb at obio file arch/mac68k/dev/adb.c adb file arch/mac68k/dev/adbsys.c file arch/mac68k/dev/adbsysasm.s +file arch/mac68k/dev/adb_direct.c hwdirect +file arch/mac68k/dev/pm_direct.c hwdirect device asc attach asc at obio @@ -56,7 +58,7 @@ device sn: ifnet, ether attach sn at obio file arch/mac68k/dev/if_sn.c sn needs-flag -include "scsi/files.scsi" +include "../../../scsi/files.scsi" # Option 1 for ncr5380 support device ncrscsi: scsi @@ -90,7 +92,7 @@ file arch/mac68k/mac68k/fpu.c fpu file arch/m68k/m68k/copy.s file arch/m68k/m68k/db_memrw.c ddb -include "arch/m68k/fpe/files.fpe" +include "../../../arch/m68k/fpe/files.fpe" file arch/mac68k/mac68k/autoconf.c file arch/mac68k/mac68k/clock.c @@ -127,5 +129,5 @@ major {rd = 13} # Compatibility modules # SunOS Binary Compatibility (COMPAT_SUNOS) -include "compat/sunos/files.sunos" +include "../../../compat/sunos/files.sunos" file arch/m68k/m68k/sunos_machdep.c compat_sunos diff --git a/sys/arch/mac68k/dev/adb.c b/sys/arch/mac68k/dev/adb.c index 29a5d960688..33614c3e4bb 100644 --- a/sys/arch/mac68k/dev/adb.c +++ b/sys/arch/mac68k/dev/adb.c @@ -1,4 +1,4 @@ -/* $OpenBSD: adb.c,v 1.6 1997/01/24 01:35:27 briggs Exp $ */ +/* $OpenBSD: adb.c,v 1.7 1997/02/23 06:04:52 briggs Exp $ */ /* $NetBSD: adb.c,v 1.13 1996/12/16 16:17:02 scottr Exp $ */ /*- @@ -39,13 +39,12 @@ e* notice, this list of conditions and the following disclaimer in the #include #include -#include #include #include -#include "adbvar.h" -#include "itevar.h" -#include "../mac68k/macrom.h" +#include +#include +#include /* * Function declarations. diff --git a/sys/arch/mac68k/dev/adb_direct.c b/sys/arch/mac68k/dev/adb_direct.c new file mode 100644 index 00000000000..83b79474145 --- /dev/null +++ b/sys/arch/mac68k/dev/adb_direct.c @@ -0,0 +1,2204 @@ +/* $OpenBSD: adb_direct.c,v 1.1 1997/02/23 06:04:52 briggs Exp $ */ +/* adb_direct.c 1.91 1/20/97 jpw */ + +/* + * Copyright (C) 1996, 1997 John P. Wittkoski + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John P. Wittkoski. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* This code is rather messy, but I don't have time right now + * to clean it up as much as I would like. + * But it works, so I'm happy. :-) jpw */ + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#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 diff --git a/sys/arch/mac68k/dev/adbsys.c b/sys/arch/mac68k/dev/adbsys.c index c4e3fe5a664..4b0869c21ef 100644 --- a/sys/arch/mac68k/dev/adbsys.c +++ b/sys/arch/mac68k/dev/adbsys.c @@ -1,4 +1,4 @@ -/* $OpenBSD: adbsys.c,v 1.6 1997/01/24 01:35:28 briggs Exp $ */ +/* $OpenBSD: adbsys.c,v 1.7 1997/02/23 06:04:54 briggs Exp $ */ /* $NetBSD: adbsys.c,v 1.24 1997/01/13 07:01:23 scottr Exp $ */ /*- @@ -34,13 +34,12 @@ #include #include -#include #include #include #include -#include "adbvar.h" -#include "../mac68k/macrom.h" +#include +#include extern struct mac68k_machine_S mac68k_machine; @@ -182,10 +181,13 @@ adb_init() return; } +#ifndef HWDIRECT /* We don't care about ADB ROM driver if we are + * using the HWDIRECT method for ADB/PRAM/RTC. */ if (!mrg_romready()) { printf("adb: no ROM ADB driver in this kernel for this machine\n"); return; } +#endif printf("adb: bus subsystem\n"); #ifdef MRG_DEBUG printf("adb: call mrg_initadbintr\n"); @@ -199,12 +201,21 @@ adb_init() /* ADBReInit pre/post-processing */ JADBProc = adb_jadbproc; - /* Initialize ADB */ + /* + * Initialize ADB + * + * If using HWDIRECT method to access ADB, then call + * ADBReInit directly. Otherwise use ADB AlternateInit() + */ +#ifdef HWDIRECT + printf("adb: calling ADBReInit\n"); + ADBReInit(); +#else #ifdef MRG_DEBUG printf("adb: calling ADBAlternateInit.\n"); #endif - ADBAlternateInit(); +#endif #ifdef MRG_DEBUG printf("adb: done with ADBReInit\n"); diff --git a/sys/arch/mac68k/dev/adbvar.h b/sys/arch/mac68k/dev/adbvar.h index 97e38867a5b..3070587e981 100644 --- a/sys/arch/mac68k/dev/adbvar.h +++ b/sys/arch/mac68k/dev/adbvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: adbvar.h,v 1.4 1997/01/24 01:35:28 briggs Exp $ */ +/* $OpenBSD: adbvar.h,v 1.5 1997/02/23 06:04:55 briggs Exp $ */ /* $NetBSD: adbvar.h,v 1.5 1997/01/13 07:01:24 scottr Exp $ */ /*- @@ -31,6 +31,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include + #define ADB_MAXTRACE (NBPG / sizeof(int) - 1) extern int adb_traceq[ADB_MAXTRACE]; extern int adb_traceq_tail; @@ -64,3 +66,25 @@ void extdms_complete __P((void)); /* adbsys.c */ void adb_complete __P((caddr_t buffer, caddr_t data_area, int adb_command)); void extdms_init __P((int)); + +#ifdef HWDIRECT + +/* types of adb hardware that we (will eventually) support */ +#define ADB_HW_UNKNOWN 0x01 /* don't know */ +#define ADB_HW_II 0x02 /* Mac II series */ +#define ADB_HW_IISI 0x03 /* Mac IIsi series */ +#define ADB_HW_PB 0x04 /* PowerBook series */ +#define ADB_HW_CUDA 0x05 /* Machines with a Cuda chip */ + +/* adb_direct.c */ +int adb_poweroff __P((void)); +int CountADBs __P((void)); +void ADBReInit __P((void)); +int GetIndADB __P((ADBDataBlock * info, int index)); +int GetADBInfo __P((ADBDataBlock * info, int adbAddr)); +int SetADBInfo __P((ADBSetInfoBlock * info, int adbAddr)); +int ADBOp __P((Ptr buffer, Ptr compRout, Ptr data, short commandNum)); +int adb_read_date_time __P((unsigned long *t)); +int adb_set_date_time __P((unsigned long t)); + +#endif diff --git a/sys/arch/mac68k/dev/pm_direct.c b/sys/arch/mac68k/dev/pm_direct.c new file mode 100644 index 00000000000..90ab35aeb89 --- /dev/null +++ b/sys/arch/mac68k/dev/pm_direct.c @@ -0,0 +1,1098 @@ +/* $OpenBSD: pm_direct.c,v 1.1 1997/02/23 06:04:56 briggs Exp $ */ +/* pm_direct.c 1.22 01/09/97 Takashi Hamada */ + +/* + * Copyright (C) 1997 Takashi Hamada + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Takashi HAMADA + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/* #define PM_DEBUG 1 */ +/* #define PM_GRAB_SI 1 */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#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; icommand ) { + 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; icommand = 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; icommand ) { + 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; inum_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 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; idata[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; inum_data+2; i++ ) + adbInputBuffer[i] = pmdata->data[i]; + + if ((adbWaiting == 1) && (rx_pm_adb_cmd == adbWaitingCmd)) { + if (adbStarting == 0) + adb_complete( &pmdata->data[3] , (long)0, adbWaitingCmd ); + adbWaitingCmd = 0x0; + + adbWaiting = 0; + adb_comp_exec(); + adbBuffer = (long)0; + adbCompRout = (long)0; + adbCompData = (long)0; + } +} + + +void +pm_adb_get_ADB_data(pmdata) + PMData *pmdata; +{ + int i; + + i = (u_int)pmdata->data[3] & 0xff; + pmdata->data[2] &= 0xf; + pmdata->data[1] = pmdata->data[3]; + pmdata->data[3] = pmdata->num_data - 2; + + adbInputBuffer[0] = pmdata->num_data + 1; + if (adbStarting == 0) + adb_complete( &pmdata->data[3] , (long)0, i ); +} + + +void +pm_adb_poll_next_device_pm1(pmdata) + PMData *pmdata; +{ + int i; + int ndid; + u_short bendid = 0x1; + int rval; + PMData tmp_pmdata; + + /* find another existent ADB device to poll */ + for( i=1; i<16; i++ ) { + ndid = (((pmdata->data[3] & 0xf0) >> 4) + i) & 0xf; + bendid <<= ndid; + if ((pm_existent_ADB_devices & bendid) != 0) + break; + } + + /* poll the other device */ + tmp_pmdata.command = 0x20; + tmp_pmdata.num_data = 3; + tmp_pmdata.s_buf = tmp_pmdata.data; + tmp_pmdata.r_buf = tmp_pmdata.data; + tmp_pmdata.data[0] = (u_char)(ndid << 4) | 0xc; + tmp_pmdata.data[1] = 0x04; /* magic spell for awaking the PM */ + tmp_pmdata.data[2] = 0x00; + rval = pmgrop( &tmp_pmdata ); +} + + diff --git a/sys/arch/mac68k/dev/pm_direct.h b/sys/arch/mac68k/dev/pm_direct.h new file mode 100644 index 00000000000..99b5cf067bb --- /dev/null +++ b/sys/arch/mac68k/dev/pm_direct.h @@ -0,0 +1,53 @@ +/* pm_direct.h 1.0 01/02/97 Takashi Hamada */ + +/* + * Copyright (C) 1997 Takashi Hamada + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Takashi Hamada. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Public declarations that other routines may need. + */ + +/* data structure of the command of the Power Manager */ +typedef struct { + short command; /* command of the Power Manager */ + short num_data; /* number of data */ + char *s_buf; /* pointer to buffer for sending */ + char *r_buf; /* pointer to buffer for receiving */ + char data[32]; /* data buffer (is it too much?) */ +} PMData; + +int pmgrop(PMData *); + +extern void pm_setup_adb __P((void)); +extern void pm_check_adb_devices __P((int)); +extern void pm_intr __P((void)); +extern int pm_adb_op __P((u_char *, void *, void *, int)); +extern void pm_init_adb_device __P((void)); + diff --git a/sys/arch/mac68k/mac68k/machdep.c b/sys/arch/mac68k/mac68k/machdep.c index d3542a5be7a..de4d9092ea3 100644 --- a/sys/arch/mac68k/mac68k/machdep.c +++ b/sys/arch/mac68k/mac68k/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.28 1997/02/21 05:49:29 briggs Exp $ */ +/* $OpenBSD: machdep.c,v 1.29 1997/02/23 06:04:59 briggs Exp $ */ /* $NetBSD: machdep.c,v 1.129 1997/01/09 07:20:46 scottr Exp $ */ /* @@ -129,9 +129,10 @@ #include #include +#include +#include #include -#include "macrom.h" #include "ether.h" /* The following is used externally (sysctl_hw) */ diff --git a/sys/arch/mac68k/mac68k/macrom.c b/sys/arch/mac68k/mac68k/macrom.c index dbc19c0a814..bfef792ef48 100644 --- a/sys/arch/mac68k/mac68k/macrom.c +++ b/sys/arch/mac68k/mac68k/macrom.c @@ -1,4 +1,4 @@ -/* $OpenBSD: macrom.c,v 1.8 1997/01/24 01:35:49 briggs Exp $ */ +/* $OpenBSD: macrom.c,v 1.9 1997/02/23 06:05:00 briggs Exp $ */ /* $NetBSD: macrom.c,v 1.30 1996/12/18 07:21:06 scottr Exp $ */ /*- @@ -120,6 +120,9 @@ caddr_t ResHndls[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, caddr_t ResHndls[]={0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; #endif +void setup_egret __P((void)); + + /* * Last straw functions; we didn't set them up, so freak out! * When someone sees these called, we can finally go back and @@ -347,6 +350,10 @@ mrg_jkybdtaskpanic() /* JKybdTask stopper */ panic("Agh! Called JKybdTask!\n"); } +#ifndef HWDIRECT /* mrg_adbintr and mrg_pmintr are not defined + * here if we are using the HWDIRECT method to + * access the ADB/PRAM/RTC. They are + * defined in adb_direct.c */ long mrg_adbintr() /* Call ROM ADB Interrupt */ { @@ -403,6 +410,7 @@ mrg_pmintr() /* Call ROM PM Interrupt */ } return(1); } +#endif /* ifndef HWDIRECT */ void @@ -427,7 +435,7 @@ mrg_NewPtr() u_int32_t trapword; caddr_t ptr; - __asm(" movl d1, %0 + __asm(" movw d1, %0 movl d0, %1" : "=g" (trapword), "=g" (numbytes) : : "d0", "d1"); @@ -654,16 +662,18 @@ mrg_aline_super(struct frame *frame) tron(); #endif -/* put trapword in d1 */ -/* put trapaddr in a1 */ -/* put a0 in a0 */ -/* put d0 in d0 */ -/* save a6 */ -/* call the damn routine */ -/* restore a6 */ -/* store d0 in d0bucket */ -/* store a0 in d0bucket */ -/* This will change a1,d1,d0,a0 and possibly a6 */ +/* + * put trapword in d1 + * put trapaddr in a1 + * put a0 in a0 + * put d0 in d0 + * save a6 + * call the damn routine + * restore a6 + * store d0 in d0bucket + * store a0 in d0bucket + * This will change a1,d1,d0,a0 and possibly a6 + */ __asm(" movl %2, a1 @@ -677,7 +687,7 @@ mrg_aline_super(struct frame *frame) : "=g" (a0bucket), "=g" (d0bucket) : "g" (trapaddr), "g" (trapword), - "m" (frame->f_regs[0]), "m" (frame->f_regs[8]) + "m" (frame->f_regs[0]), "m" (frame->f_regs[8]) : "d0", "d1", "a0", "a1", "a6" @@ -979,9 +989,7 @@ mrg_init() } } -static void setup_egret __P((void)); - -static void +void setup_egret(void) { if (0 != mrg_InitEgret){ @@ -1034,6 +1042,10 @@ mrg_initadbintr() HwCfgFlags, HwCfgFlags2, HwCfgFlags3); } +#ifdef HWDIRECT /* Extra Egret setup not required for the + * HWDIRECT method. */ + printf("mrg: skipping egret setup\n"); +#else /* * If we think there is an Egret in the machine, attempt to * set it up. If not, just enable the interrupts (only on @@ -1060,6 +1072,7 @@ mrg_initadbintr() if (mac68k_machine.do_graybars) printf("mrg: ADB interrupts enabled.\n"); } +#endif } /* @@ -1229,6 +1242,7 @@ t: walter@ghpc8.ihf.rwth-aachen.de\n"); #endif } +#ifndef HWDIRECT void ADBAlternateInit(void) { @@ -1246,3 +1260,4 @@ ADBAlternateInit(void) : "a1", "a3"); } } +#endif diff --git a/sys/arch/mac68k/mac68k/macrom.h b/sys/arch/mac68k/mac68k/macrom.h index 350b332c2d5..9bce888e5bf 100644 --- a/sys/arch/mac68k/mac68k/macrom.h +++ b/sys/arch/mac68k/mac68k/macrom.h @@ -1,4 +1,4 @@ -/* $OpenBSD: macrom.h,v 1.4 1997/01/19 03:58:08 briggs Exp $ */ +/* $OpenBSD: macrom.h,v 1.5 1997/02/23 06:05:02 briggs Exp $ */ /* $NetBSD: macrom.h,v 1.9 1996/05/25 14:45:35 briggs Exp $ */ /*- @@ -96,7 +96,7 @@ typedef struct { unsigned char devType; unsigned char origADBAddr; Ptr dbServiceRtPtr; - Ptr dbDataAreaAdd; + Ptr dbDataAreaAddr; } ADBDataBlock; @@ -108,6 +108,10 @@ int MyOwnTrap( void KnownRTS( void); +#ifndef HWDIRECT /* These routines are NOT defined here + * if using the HWDIRECT method for accessing + * the ADB/PRAM/RTC. They are + * defined in adb_direct.h */ /* ADB Manager */ int SetADBInfo( ADBSetInfoBlock *info, @@ -129,6 +133,7 @@ int ADBOp( short commandNum); void ADBAlternateInit( void); +#endif /* Memory Manager */ Ptr NewPtr( diff --git a/sys/arch/mac68k/mac68k/macromasm.s b/sys/arch/mac68k/mac68k/macromasm.s index ec529dd5f26..92595bcd78c 100644 --- a/sys/arch/mac68k/mac68k/macromasm.s +++ b/sys/arch/mac68k/mac68k/macromasm.s @@ -1,4 +1,4 @@ -/* $OpenBSD: macromasm.s,v 1.3 1996/05/26 18:36:26 briggs Exp $ */ +/* $OpenBSD: macromasm.s,v 1.4 1997/02/23 06:05:03 briggs Exp $ */ /* $NetBSD: macromasm.s,v 1.11 1996/05/25 14:45:37 briggs Exp $ */ /*- @@ -122,6 +122,9 @@ .global _panic .global _printf +#ifndef HWDIRECT /* These functions are NOT defined here if using the + * HWDIRECT method of accessing the ADB/PRAM/RTC. + * They are in adb_direct.c. */ /* * Most of the following glue just takes C function calls, converts * the parameters to the MacOS Trap parameters, and then tries to @@ -216,6 +219,7 @@ _ADBOp: movl sp@(16), d0 .word 0xa07c rts +#endif /* ifndef HWDIRECT */ #if 0 diff --git a/sys/arch/mac68k/mac68k/pram.c b/sys/arch/mac68k/mac68k/pram.c index 86c1faf4f56..8a22388b9ad 100644 --- a/sys/arch/mac68k/mac68k/pram.c +++ b/sys/arch/mac68k/mac68k/pram.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pram.c,v 1.4 1997/01/24 01:35:52 briggs Exp $ */ +/* $OpenBSD: pram.c,v 1.5 1997/02/23 06:05:04 briggs Exp $ */ /* $NetBSD: pram.c,v 1.11 1996/10/21 05:42:29 scottr Exp $ */ /*- @@ -40,9 +40,15 @@ #ifdef DEBUG #include #endif +#include + #include -#include "pram.h" -#include "macrom.h" + +#include +#include +#ifdef HWDIRECT +#include +#endif #if DEBUG static char *convtime(unsigned long t) @@ -146,3 +152,71 @@ pram_settime(unsigned long time) else return setPramTime(time); } + +#ifdef HWDIRECT /* These routines are defined here only + * when the HWDIRECT method for accessing + * the ADB/PRAM/RTC is enabled. */ + +extern int adbHardware; /* from newadb.c */ + +/* + * getPramTime + * This function can be called regrardless of the machine + * type. It calls the correct hardware-specific code. + * (It's sort of redundant with the above, but it was + * added later.) + */ +unsigned long +getPramTime(void) +{ + unsigned long time; + + switch (adbHardware) { + case ADB_HW_II: /* access PRAM via VIA interface */ + time=(long)getPramTimeII(); + return time; + + case ADB_HW_IISI: /* access PRAM via pseudo-adb functions */ + if (0 != adb_read_date_time(&time)) + return 0; + else + return time; + + case ADB_HW_PB: /* don't know how to access this yet */ + return 0; + + case ADB_HW_UNKNOWN: + default: + return 0; + } +} + +/* + * setPramTime + * This function can be called regrardless of the machine + * type. It calls the correct hardware-specific code. + * (It's sort of redundant with the above, but it was + * added later.) + */ +void +setPramTime(unsigned long time) +{ + switch (adbHardware) { + case ADB_HW_II: /* access PRAM via ADB interface */ + setPramTimeII(time); + return; + + case ADB_HW_IISI: /* access PRAM via pseudo-adb functions */ + adb_set_date_time(time); + return; + + case ADB_HW_PB: /* don't know how to access this yet */ + return; + + case ADB_HW_UNKNOWN: + return; + } + +} + +#endif /* ifdef HWDIRECT */ diff --git a/sys/arch/mac68k/mac68k/pram.h b/sys/arch/mac68k/mac68k/pram.h index 877a9aa817f..172f5059ab9 100644 --- a/sys/arch/mac68k/mac68k/pram.h +++ b/sys/arch/mac68k/mac68k/pram.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pram.h,v 1.3 1996/05/26 18:36:31 briggs Exp $ */ +/* $OpenBSD: pram.h,v 1.4 1997/02/23 06:05:05 briggs Exp $ */ /* $NetBSD: pram.h,v 1.3 1996/05/05 06:18:53 briggs Exp $ */ /* @@ -73,3 +73,11 @@ void setPramTime(unsigned long time); unsigned long pram_readtime __P((void)); void pram_settime __P((unsigned long)); +#ifdef HWDIRECT /* These functions exist only when ADB/PRAM/RTC + * access is done via the HWDIRECT method. */ + +unsigned long getPramTimeII(void); +void setPramTimeII(unsigned long); + +#endif + diff --git a/sys/arch/mac68k/mac68k/pramasm.s b/sys/arch/mac68k/mac68k/pramasm.s index af40f5f6eeb..11b1e0d8457 100644 --- a/sys/arch/mac68k/mac68k/pramasm.s +++ b/sys/arch/mac68k/mac68k/pramasm.s @@ -1,4 +1,4 @@ -/* $OpenBSD: pramasm.s,v 1.2 1996/05/26 18:36:32 briggs Exp $ */ +/* $OpenBSD: pramasm.s,v 1.3 1997/02/23 06:05:05 briggs Exp $ */ /* $NetBSD: pramasm.s,v 1.4 1995/09/28 03:15:54 briggs Exp $ */ /* @@ -47,6 +47,10 @@ * that are defined later in this file. */ +#ifndef HWDIRECT /* These routines are NOT defined at all + * if using the HWDIRECT method for accessing + * the ADB/PRAM/RTC. */ + .text .even @@ -140,3 +144,281 @@ _setPramTime: unlk a6 | clean up after ourselves rts | and return to caller +#else /* The following routines are the hardware + * specific routines for the machines that + * use the II-like method to access the PRAM, + * and are only defined when the HWDIRECT method + * is used to access the PRAM. */ + +/* + * The following are the C interface functions to RTC access functions + * that are defined later in this file. + */ + + .text + + .even +.globl _readPramII +_readPramII: + link a6,#-4 | create a little home for ourselves + moveq #0,d0 | zero out our future command register + moveb a6@(19),d0 | move the length byte in + swap d0 | and make that the MSW + moveb a6@(15),d0 | now get out PRAM location + oriw #0x0100,d0 | and set up for non-extended read + movel a6@(8),a0 | get our data address + jbsr _PRAMacc | and go read the data + unlk a6 | clean up after ourselves + rts | and return to caller + +.globl _writePramII +_writePramII: + link a6,#-4 | create a little home for ourselves + moveq #0,d0 | zero out our future command register + moveb a6@(19),d0 | move the length byte in + swap d0 | and make that the MSW + moveb a6@(15),d0 | now get out PRAM location + nop | and set up for non-extended write + movel a6@(8),a0 | get our data address + jbsr _PRAMacc | and go write the data + unlk a6 | clean up after ourselves + rts | and return to caller + +.globl _readExtPramII +_readExtPramII: + link a6,#-4 | create a little home for ourselves + moveq #0,d0 | zero out our future command register + moveb a6@(19),d0 | move the length byte in + swap d0 | and make that the MSW + moveb a6@(15),d0 | now get out PRAM location + oriw #0x0300,d0 | and set up for extended read + movel a6@(8),a0 | get our data address + jbsr _PRAMacc | and go read the data + unlk a6 | clean up after ourselves + rts | and return to caller + +.globl _writeExtPramII +_writeExtPramII: + link a6,#-4 | create a little home for ourselves + moveq #0,d0 | zero out our future command register + moveb a6@(19),d0 | move the length byte in + swap d0 | and make that the MSW + moveb a6@(15),d0 | now get out PRAM location + oriw #0x0200,d0 | and set up for extended write + movel a6@(8),a0 | get our data address + jbsr _PRAMacc | and go write the data + unlk a6 | clean up after ourselves + rts | and return to caller + +.globl _getPramTimeII +_getPramTimeII: + link a6,#-4 | create a little home for ourselves + jbsr _readClock | call the routine to read the time + unlk a6 | clean up after ourselves + rts | and return to caller + +.globl _setPramTimeII +_setPramTimeII: + link a6,#-4 | create a little home for ourselves + movel a6@(8),d0 | get the passed in long (seconds since 1904) + jbsr _writeClock | call the routine to write the time + unlk a6 | clean up after ourselves + rts | and return to caller + +/* + * The following are the RTC access functions used by the interface + * routines, above. + */ + +_readClock: + moveml #0x7cc0, sp@- | store off the regs we need + moveq #00,d0 | zero out our result reg +readagan: + moveq #00,d5 | and our temp result reg + moveq #03,d4 | set our count down reg to 4 + movel #0x00000081,d1 | read sec byte 0 first +getSecb: + bsr _Transfer | get that byte + rorl #8,d5 | shift our time to the right + swap d1 | we want to access our new data + moveb d1,d5 | move that byte to the spot we vacated + swap d1 | return our PRAM command to orig. config + addqb #4,d1 | increment to the next sec byte + dbf d4,getSecb | any more bytes to get ? + cmpl d5,d0 | same secs value we as we just got ? + beq gotTime | we got a good time value + movel d5,d0 | copy our current time to the compare reg + bra readagan | read the time again +gotTime: + rorl #8,d0 | make that last shift to correctly order + | time bytes!!! + movel #0x00d50035,d1 | we have to set the write protect bit + | so the clock doesn't run down ! + bsr _Transfer | (so sezs Apple...) + moveml sp@+, #0x033e | restore our regs + rts | and return to caller + +_writeClock: + moveml #0x78c0, sp@- | store off the regs we need + moveq #03,d4 | set our count down reg to 4 + movel #0x00550035,d1 | de-write-protect the PRAM + bsr _Transfer | so we can set our value + moveq #1,d1 | write sec byte 0 first +putSecb: + swap d1 | we want access to data byte of command + moveb d0,d1 | set our first secs byte + swap d1 | and return command to orig. config + bsr _Transfer | write that byte + rorl #8,d0 | shift our time to the right + addqb #4,d1 | increment to the next sec byte + dbf d4,putSecb | any more bytes to put ? + movel #0x00d50035,d1 | we have to set the write protect bit + | so the clock doesn't run down ! + bsr _Transfer | (so sezs Apple...) + moveml sp@+, #0x031e | restore our regs + rts | and return to caller + +_PRAMacc: + moveml #0xf8c0, sp@- | store off the regs we'll use + moveq #00,d3 | zero out our command reg + moveq #00,d4 | zero out our count reg too + swap d0 | we want the length byte + movew d0,d4 | copy length byte to our counter reg + swap d0 | and return command reg to prior state + subqb #1,d4 | predecrement counter for use w/ DBF + movew d0,d2 | copy command to d2 + rorw #8,d2 | rotate copy to examine flags + roxrw #1,d2 | read/write bit out of param. + roxlb #1,d3 | and into command reg + tstb d3 | was it read (1) or write (0) ? + bne NoWrit | go around de-write protect logic + movel #0x00550035,d1 | clear write protect bit of PRAM + | (we really only need to zero the high + | bit, but other patterns don't work! ) + moveml #0x3000, sp@- | store off the regs that'll change + bsr _Transfer | and go de-write protect RTC + moveml sp@+, #0x000c | reclaim our reg values +NoWrit: + andib #1,d2 | isolate the extended command bit + beq oldPRAM | it's zero, so do old PRAM style access +NuPRAM: + moveb d0,d2 | reget our PRAM location + lslw #4,d3 | insert our template blanks + moveq #2,d1 | set bit counter for 3 cycles +threebit: + roxlb #1,d2 | rotate address bit from d2 + roxlw #1,d3 | and into command in d3 + dbf d1,threebit | until we've done bits 7-5 + lslw #1,d3 | and add a bit spacer + moveq #4,d1 | ok, 5 bits to go... +fivebit: + roxlb #1,d2 | another addr bit out of d2 + roxlw #1,d3 | and into command template in d3 + dbf d1,fivebit | til we've done bit 4-0 + lslw #2,d3 | more bit magic + oriw #0x3880,d3 | set extended command bits + bra Loaddata | go load the rest of command for xfer rtn +oldPRAM: + moveb d0,d2 | reget our PRAM location + lslb #1,d3 | add a template blank (bit) + rolb #4,d2 | get low nibble of PRAM loc ready + moveq #3,d1 | set our bit counter for 4 cycles +fourbit: + roxlb #1,d2 | bit out of PRAM loc + roxlb #1,d3 | and bit into PRAM command + dbf d1,fourbit | until we've done the low nibble + lslb #2,d3 | bump bits to type of command byte + orib #0x41,d3 | set command bits (for access to $0-F!) + btst #4,d2 | change to access $10-13 ? + beq Loaddata | nope, should stay the way it is + andib #0x8F,d3 | clear bits 4-6 of current command + orib #0x20,d3 | and set bit 5 (now accesses $10-13) +Loaddata: + moveb a0@,d1 | get our (data/dummy) byte into d1 + swap d1 | move (data/dummy) byte to MSW + movew d3,d1 | now move command into d1 +tagain: + bsr _Transfer | now execute that command + swap d1 | we want access to (data/dummy) byte + moveb d1,a0@+ | move (data/dummy) byte back to a0, + moveb a0@,d1 | NEXT VICTIM!! + swap d1 | now we want to tweak the command + addqw #4,d1 | increment our memory addr by 1 (this even + | works if we want to dump across 32 byte + | boundries for an extended command!!! + | thanks to the oriw #$3880 above !!!) + dbf d4,tagain | repeat until we've got all we want + movel #0x00d50035,d1 | remember that command to write the wp byte ? + | set the high bit in the wp reg (Apple sezs + | this way the battery won't wear down !! ) + bsr _Transfer | so we'll play by the rules + moveml sp@+, #0x031f | restore all our registers + rts | and return to our gracious caller + +_Transfer: + movew sr,sp@- | store the SR (we'll change it!) + oriw #0x0700,sr | disable all interrupts + moveal _Via1Base,a1 | move VIA1 addr in reference reg + moveq #0,d2 | zero out d2 (it'll hold VIA1 reg B contents) + moveb a1@,d2 | and get VIA1 reg B contents + andib #0xF8,d2 | don't touch any but RTC bits + | (and zero all those) + movew d1,d3 | we want to manipulate our command + andiw #0xFF00,d3 | zero the LSB + beq oldPRAMc | do an old PRAM style command +xPRAMc: + rorw #8,d1 | swap the command bytes (1st byte of 2) + bsr writebyte | and write the command byte + rorw #8,d1 | swap the command bytes again (2nd byte of 2) + bsr writebyte | write that byte to RTC too + moveq #0x1F,d3 | r/w bit is $F for an extended command + | (but command is swapped to MSW!! so add $10) + bra Rwbrnch | go figure out if it's a read or a write cmd +oldPRAMc: + bsr writebyte | only one byte for an old PRAM command + moveq #0x17,d3 | r/w bit is $7 for and old PRAM command + | ( command is swapped to MSW, add $10) +Rwbrnch: + swap d1 | better get that (data/dummy) byte ready + btst d3,d1 | test bit no. d3 of reg d1 (read or write ?) + beq Wtrue | 0 = write, 1 = read (branch on write) +Rtrue: + bsr readbyte | read a byte from the RTC + bra Cleanup | and call mom to clean up after us +Wtrue: + bsr writebyte | write the data to the RTC +Cleanup: + swap d1 | move command to LSW again + bset #2,a1@ | bring the RTC enable line high (end of xfer) + movew sp@+,sr | restore prior interrupt status + rts | and return to caller + +writebyte: + moveq #7,d3 | set our bit counter to 8 +wagain: + lsrb #1,d2 | ditch the old data channel value + roxlb #1,d1 | and move a new value to X + roxlb #1,d2 | now move value from X to data channel + moveb d2,a1@ | set our VIA1 reg B contents to match + bset #1,a1@ | and finish strobing the clock line + dbf d3,wagain | do this until we've sent a whole byte + lsrb #1,d2 | ditch the data channel value one last time + roxlb #1,d1 | get rid of the extra X bit we've carried + lslb #1,d2 | and restore d2 to prior status + rts | return to caller + +readbyte: + moveq #7,d3 | set our bit counter to 8 + bclr #0,a1@(0x0400) | set VIA1 reg B data line to input +ragain: + bclr #1,a1@ | strobe the clock line to make + bset #1,a1@ | the data valid + moveb a1@,d2 | and get out data byte + lsrb #1,d2 | get the data channel value to X + roxlb #1,d1 | and move X to data byte + dbf d3,ragain | do this until we've received a whole byte + bset #0,a1@(0x0400) | and return RTC data line to output + rts | return to caller + +#endif /* ifdef HWDIRECT */ + -- 2.20.1