diff options
Diffstat (limited to 'sys/arch/mac68k')
-rw-r--r-- | sys/arch/mac68k/conf/TIGER | 3 | ||||
-rw-r--r-- | sys/arch/mac68k/conf/files.mac68k | 10 | ||||
-rw-r--r-- | sys/arch/mac68k/dev/adb.c | 9 | ||||
-rw-r--r-- | sys/arch/mac68k/dev/adb_direct.c | 2204 | ||||
-rw-r--r-- | sys/arch/mac68k/dev/adbsys.c | 23 | ||||
-rw-r--r-- | sys/arch/mac68k/dev/adbvar.h | 26 | ||||
-rw-r--r-- | sys/arch/mac68k/dev/pm_direct.c | 1098 | ||||
-rw-r--r-- | sys/arch/mac68k/dev/pm_direct.h | 53 | ||||
-rw-r--r-- | sys/arch/mac68k/mac68k/machdep.c | 5 | ||||
-rw-r--r-- | sys/arch/mac68k/mac68k/macrom.c | 47 | ||||
-rw-r--r-- | sys/arch/mac68k/mac68k/macrom.h | 9 | ||||
-rw-r--r-- | sys/arch/mac68k/mac68k/macromasm.s | 6 | ||||
-rw-r--r-- | sys/arch/mac68k/mac68k/pram.c | 80 | ||||
-rw-r--r-- | sys/arch/mac68k/mac68k/pram.h | 10 | ||||
-rw-r--r-- | sys/arch/mac68k/mac68k/pramasm.s | 284 |
15 files changed, 3824 insertions, 43 deletions
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 <sys/signalvar.h> #include <sys/systm.h> -#include <machine/adbsys.h> #include <machine/autoconf.h> #include <machine/keyboard.h> -#include "adbvar.h" -#include "itevar.h" -#include "../mac68k/macrom.h" +#include <arch/mac68k/mac68k/macrom.h> +#include <arch/mac68k/dev/adbvar.h> +#include <arch/mac68k/dev/itevar.h> /* * Function declarations. diff --git a/sys/arch/mac68k/dev/adb_direct.c b/sys/arch/mac68k/dev/adb_direct.c new file mode 100644 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 <sys/types.h> +#include <sys/cdefs.h> +#include <sys/param.h> +#include <sys/systm.h> + +#include <machine/cpu.h> +#include <machine/macinfo.h> +#include <machine/viareg.h> + +#include <arch/mac68k/mac68k/macrom.h> +#include <arch/mac68k/dev/adbvar.h> + +#include "pm_direct.h" + +/* more verbose for testing */ +/*#define HWDIRECT_TEST*/ + +/* some misc. leftovers */ +#define vPB 0x0000 +#define vPB3 0x08 +#define vPB4 0x10 +#define vPB5 0x20 +#define vSR_INT 0x04 +#define vSR_OUT 0x10 + +/* types of adb hardware that we (will eventually) support */ +#define ADB_HW_UNKNOWN 0x01 /* don't know */ +#define ADB_HW_II 0x02 /* Mac II series */ +#define ADB_HW_IISI 0x03 /* Mac IIsi series */ +#define ADB_HW_PB 0x04 /* PowerBook series */ +#define ADB_HW_CUDA 0x05 /* Machines with a Cuda chip */ + +/* the type of ADB action that we are currently preforming */ +#define ADB_ACTION_NOTREADY 0x01 /* has not been initialized yet */ +#define ADB_ACTION_IDLE 0x02 /* the bus is currently idle */ +#define ADB_ACTION_OUT 0x03 /* sending out a command */ +#define ADB_ACTION_IN 0x04 /* receiving data */ + +/* + * These describe the state of the ADB bus itself, although they + * don't necessarily correspond directly to ADB states. + * Note: these are not really used in the IIsi code. + */ +#define ADB_BUS_UNKNOWN 0x01 /* we don't know yet - all models */ +#define ADB_BUS_IDLE 0x02 /* bus is idle - all models */ +#define ADB_BUS_CMD 0x03 /* starting a command - II models */ +#define ADB_BUS_ODD 0x04 /* the "odd" state - II models */ +#define ADB_BUS_EVEN 0x05 /* the "even" state - II models */ +#define ADB_BUS_ACTIVE 0x06 /* active state - IIsi models */ +#define ADB_BUS_ACK 0x07 /* currently ACKing - IIsi models */ + +/* + * Shortcuts for setting or testing the VIA bit states. + * Not all shortcuts are used for every type of ADB hardware. + */ +#define ADB_SET_STATE_IDLE_II() via_reg(VIA1, vBufB) |= (vPB4 | vPB5) +#define ADB_SET_STATE_IDLE_IISI() via_reg(VIA1, vBufB) &= ~(vPB4 | vPB5) +#define ADB_SET_STATE_IDLE_CUDA() via_reg(VIA1, vBufB) |= (vPB4 | vPB5) +#define ADB_SET_STATE_CMD() via_reg(VIA1, vBufB) &= ~(vPB4 | vPB5) +#define ADB_SET_STATE_EVEN() via_reg(VIA1, vBufB) = ( (via_reg(VIA1, \ + vBufB) | vPB4) & ~vPB5 ) +#define ADB_SET_STATE_ODD() via_reg(VIA1, vBufB) = ( (via_reg(VIA1, \ + vBufB) | vPB5) & ~vPB4 ) +#define ADB_SET_STATE_ACTIVE() via_reg(VIA1, vBufB) |= vPB5 +#define ADB_SET_STATE_INACTIVE() via_reg(VIA1, vBufB) &= ~vPB5 +#define ADB_SET_STATE_TIP() via_reg(VIA1, vBufB) &= ~vPB5 +#define ADB_CLR_STATE_TIP() via_reg(VIA1, vBufB) |= vPB5 +#define ADB_SET_STATE_ACKON() via_reg(VIA1, vBufB) |= vPB4 +#define ADB_SET_STATE_ACKOFF() via_reg(VIA1, vBufB) &= ~vPB4 +#define ADB_TOGGLE_STATE_ACK_CUDA() via_reg(VIA1, vBufB) ^= vPB4 +#define ADB_SET_STATE_ACKON_CUDA() via_reg(VIA1, vBufB) &= ~vPB4 +#define ADB_SET_STATE_ACKOFF_CUDA() via_reg(VIA1, vBufB) |= vPB4 +#define ADB_SET_SR_INPUT() via_reg(VIA1, vACR) &= ~vSR_OUT +#define ADB_SET_SR_OUTPUT() via_reg(VIA1, vACR) |= vSR_OUT +#define ADB_SR() via_reg(VIA1, vSR) +#define ADB_VIA_INTR_ENABLE() via_reg(VIA1, vIER) = 0x84 +#define ADB_VIA_INTR_DISABLE() via_reg(VIA1, vIER) = 0x04 +#define ADB_VIA_CLR_INTR() via_reg(VIA1, vIFR) = 0x04 +#define ADB_INTR_IS_OFF ( vPB3 == (via_reg(VIA1, vBufB) & vPB3) ) +#define ADB_INTR_IS_ON ( 0 == (via_reg(VIA1, vBufB) & vPB3) ) +#define ADB_SR_INTR_IS_OFF ( 0 == (via_reg(VIA1, vIFR) & vSR_INT) ) +#define ADB_SR_INTR_IS_ON ( vSR_INT == (via_reg(VIA1, vIFR) & vSR_INT) ) + +/* + * This is the delay that is required (in uS) between certain + * ADB transactions. The actual timing delay for for each uS is + * calculated at boot time to account for differences in machine speed. + */ +#define ADB_ACK_DELAY 150 + +/* + * Maximum ADB message length; includes space for data, result, and + * device code - plus a little for safety. + */ +#define MAX_ADB_MSG_LENGTH 20 + +/* + * A structure for storing information about each ADB device. + */ +struct ADBDevEntry { + void (*ServiceRtPtr) __P((void)); + void *DataAreaAddr; + char devType; + char origAddr; + char currentAddr; +}; + +/* + * Used to hold ADB commands that are waiting to be sent out. + */ +struct adbCmdHoldEntry { + u_char outBuf[MAX_ADB_MSG_LENGTH]; /* our message */ + u_char *saveBuf; /* buffer to know where to save result */ + u_char *compRout; /* completion routine pointer */ + u_char *data; /* completion routine data pointer */ +}; + +/* + * A few variables that we need and their initial values. + */ +int adbHardware = ADB_HW_UNKNOWN; +int adbActionState = ADB_ACTION_NOTREADY; +int adbBusState = ADB_BUS_UNKNOWN; +int adbWaiting = 0; /* waiting for return data from the device */ +int adbWriteDelay = 0; /* working on (or waiting to do) a write */ +int adbOutQueueHasData = 0; /* something in the "queue" waiting to go out */ +int adbNextEnd = 0; /* the next incoming bute is the last (II) */ + +int adbWaitingCmd = 0; /* ADB command we are waiting for */ +u_char *adbBuffer = (long) 0; /* pointer to user data area */ +void *adbCompRout = (long) 0; /* pointer to the completion routine */ +void *adbCompData = (long) 0; /* pointer to the completion routine data */ +long adbFakeInts = 0; /* keeps track of fake ADB interrupts for + * timeouts (II) */ +int adbStarting = 0; /* doing ADB reinit, so do "polling" differently */ +int adbSendTalk = 0; /* the intr routine is sending the talk, not + * the user (II) */ +int adbPolling = 0; /* we are polling for service request */ +int adbPollCmd = 0; /* the last poll command we sent */ + +u_char adbInputBuffer[MAX_ADB_MSG_LENGTH]; /* data input buffer */ +u_char adbOutputBuffer[MAX_ADB_MSG_LENGTH]; /* data output buffer */ +struct adbCmdHoldEntry adbOutQueue; /* our 1 entry output "queue" */ + +int adbSentChars = 0; /* how many characters we have sent */ +int adbLastDevice = 0; /* last ADB device we heard from (II ONLY) */ +int adbLastDevIndex = 0; /* last ADB device loc. in device table (II ONLY) */ +int adbLastCommand = 0; /* the last ADB command we sent (II) */ +int adbWaitingSubDev = 0; /* ADB sub-device (RTC, PRAM, etc) - IIsi ONLY - unused */ +int adbWaitingDevice = 0; /* ADB device we are waiting for - unused */ + +struct ADBDevEntry ADBDevTable[16]; /* our ADB device table */ +int ADBNumDevices; /* number of ADB devices found with ADBReInit */ + +extern struct mac68k_machine_S mac68k_machine; +extern int zshard(int); + + +/* + * The following are private routines. + */ +void print_single __P((unsigned char *)); +void adb_intr __P((void)); +void adb_intr_II __P((void)); +void adb_intr_IIsi __P((void)); +void adb_intr_cuda __P((void)); +int send_adb_II __P((unsigned char *, unsigned char *, void *, void *, int)); +int send_adb_IIsi __P((unsigned char *, unsigned char *, void *, void *, int)); +int send_adb_cuda __P((unsigned char *, unsigned char *, void *, void *, int)); +void adb_handle_unsol __P((unsigned char *)); +void adb_op_comprout __P((void)); +void adb_reinit __P((void)); +int count_adbs __P((void)); +int get_ind_adb_info __P((ADBDataBlock *, int)); +int get_adb_info __P((ADBDataBlock *, int)); +int set_adb_info __P((ADBSetInfoBlock *, int)); +void adb_setup_hw_type __P((void)); +int adb_op __P((Ptr, Ptr, Ptr, short)); +void adb_handle_unsol __P((unsigned char *)); +int adb_op_sync __P((Ptr, Ptr, Ptr, short)); +void adb_read_II __P((unsigned char *)); +void adb_cleanup __P((unsigned char *)); +void adb_cleanup_IIsi __P((unsigned char *)); +void adb_comp_exec __P((void)); +int adb_cmd_result __P((unsigned char *)); +int adb_cmd_extra __P((unsigned char *)); +int adb_guess_next_device __P((void)); +int adb_prog_switch_enable __P((void)); +int adb_prog_switch_disable __P((void)); +/* we should create this and it will be the public version */ +int send_adb __P((unsigned char *, void *, void *)); + + +/* + * print_single + * Diagnostic display routine. Displays the hex values of the + * specified elements of the u_char. The length of the "string" + * is in [0]. + */ +void +print_single(thestring) + u_char *thestring; +{ + int x; + + if ((int)(thestring[0]) == 0) { + printf("nothing returned\n"); + return; + } + if (thestring == 0) { + printf("no data - null pointer\n"); + return; + } + if (thestring[0] > 20) { + printf("ADB: ACK > 20 no way!\n"); + thestring[0] = 20; + } + printf("(length=0x%x):", thestring[0]); + for (x = 0; x < thestring[0]; x++) + printf(" 0x%02x", thestring[x + 1]); + printf("\n"); +} + + +/* + * called when when an adb interrupt happens + * + * Cuda version of adb_intr + * TO DO: can probably reduce the number of zshard calls in here + */ +void +adb_intr_cuda(void) +{ + int i, ending, len; + unsigned int s; + + s = splhigh(); /* can't be too careful - might be called */ + /* from a routine, NOT an interrupt */ + + ADB_VIA_CLR_INTR(); /* clear interrupt */ + + ADB_VIA_INTR_DISABLE(); /* disable ADB interrupt on IIs. */ + +switch_start: + switch (adbActionState) { + case ADB_ACTION_IDLE: + adbInputBuffer[1] = ADB_SR(); /* get byte */ + ADB_SET_SR_INPUT(); /* make sure SR is set to IN */ + ADB_SET_STATE_TIP(); /* signal start of data frame */ + printf("idle 0x%02x ", adbInputBuffer[1]); + adbInputBuffer[0] = 1; + adbActionState = ADB_ACTION_IN; /* set next state */ + break; + + case ADB_ACTION_IN: + adbInputBuffer[++adbInputBuffer[0]] = ADB_SR(); /* get byte */ + ADB_SET_SR_INPUT(); /* make sure SR is set to IN */ + if (ADB_INTR_IS_OFF) /* check for end of frame */ + ending = 1; + else + ending = 0; + + if (1 == ending) { /* end of message? */ + ADB_CLR_STATE_TIP(); /* signal end of frame */ + printf("in end 0x%02x ", adbInputBuffer[adbInputBuffer[0]]); + print_single(adbInputBuffer); + /* this section _should_ handle all ADB and RTC/PRAM type commands, */ + /* but there may be more... */ + /* note: commands are always at [4], even for rtc/pram commands */ + if ((adbWaiting == 1) && /* are we waiting AND */ + (adbInputBuffer[4] == adbWaitingCmd) && /* the cmd we sent AND */ + ((adbInputBuffer[2] == 0x00) || /* it's from the + * ADB device OR */ + (adbInputBuffer[2] == 0x01))) { /* it's from the PRAM/RTC device */ + + /* is this data we are waiting for? */ + if (adbBuffer != (long) 0) { /* if valid return data pointer */ + /* get return length minus extras */ + len = adbInputBuffer[0] - 4; + /* if adb_op is ever made to be called from a user + * routine, we should use a copyout or copyin + * here to be sure we're in the correct context */ + for (i = 1; i <= len; i++) + adbBuffer[i] = adbInputBuffer[4 + i]; + if (len < 0) + len = 0; + adbBuffer[0] = len; + } + adb_comp_exec(); /* call completion routine */ + + adbWaitingCmd = 0; /* reset "waiting" vars */ + adbWaiting = 0; + adbBuffer = (long) 0; + adbCompRout = (long) 0; + adbCompData = (long) 0; + } else { + /* pass the data off to the handler */ + /* This section IGNORES all data that is not from + * the ADB sub-device. That is, not from rtc or pram. + * Maybe we should fix later, but do the other + * devices every send things without + * being asked? */ + if (adbStarting == 0) /* ignore if during adbreinit */ + if (adbInputBuffer[2] == 0x00) + adb_handle_unsol(adbInputBuffer); + } + + adbActionState = ADB_ACTION_IDLE; + adbInputBuffer[0] = 0; /* reset length */ + + if (adbWriteDelay == 1) { /* were we waiting to write? */\ + printf("WRITE DELAY "); + adbSentChars = 0; /* nothing sent yet */ + adbActionState = ADB_ACTION_OUT; /* set next state */ + + if (ADB_INTR_IS_ON) { /* ADB intr low during write */ + ADB_CLR_STATE_TIP(); /* reset */ + ADB_SET_SR_INPUT(); /* make sure SR is set to IN */ + adbSentChars = 0; /* must start all over */ + adbActionState = ADB_ACTION_IDLE; /* new state */ + adbInputBuffer[0] = 0; + break; + } + ADB_SET_SR_OUTPUT(); /* set shift register for OUT */ + ADB_SR() = adbOutputBuffer[adbSentChars + 1]; + ADB_SET_STATE_TIP(); /* tell ADB that we want to send */ + } + } else { + ADB_TOGGLE_STATE_ACK_CUDA(); + printf("in 0x%02x ", adbInputBuffer[adbInputBuffer[0]]); + } + + break; + + case ADB_ACTION_OUT: + i = ADB_SR(); /* reset SR-intr in IFR */ + printf("intr out 0x%02x ", i); + ADB_SET_SR_OUTPUT(); /* set shift register for OUT */ + + adbSentChars++; + if (ADB_INTR_IS_ON) { /* ADB intr low during write */ + printf("intr was on "); + ADB_CLR_STATE_TIP(); /* reset */ + ADB_SET_SR_INPUT(); /* make sure SR is set to IN */ + adbSentChars = 0; /* must start all over */ + adbActionState = ADB_ACTION_IDLE; /* new state */ + adbInputBuffer[0] = 0; + adbWriteDelay = 1; /* must retry when done with read */ + delay(ADB_ACK_DELAY); /* delay */ + /* TO DO: not sure if this is the right thing to do for Cuda */ + goto switch_start; /* process next state right now */ + break; + } + + if (adbOutputBuffer[0] == adbSentChars) { /* check for done */ + if (0 == adb_cmd_result(adbOutputBuffer)) { /* do we expect data back? */ + adbWaiting = 1; /* signal waiting for return */ + adbWaitingCmd = adbOutputBuffer[2]; /* save waiting command */ + } else { /* no talk, so done */ + adb_comp_exec(); /* call completion routine */ + adbWaitingCmd = 0; /* reset "waiting" vars, just in case */ + adbBuffer = (long) 0; + adbCompRout = (long) 0; + adbCompData = (long) 0; + } + + adbWriteDelay = 0; /* done writing */ + adbActionState = ADB_ACTION_IDLE; /* signal bus is idle */ + /*ADB_SET_SR_INPUT(); make sure SR is set to IN */ + ADB_TOGGLE_STATE_ACK_CUDA(); + ADB_CLR_STATE_TIP(); /* end of frame */ + printf("write done "); + } else { + ADB_SR() = adbOutputBuffer[adbSentChars + 1]; /* send next byte */ + ADB_TOGGLE_STATE_ACK_CUDA(); /* signal byte ready to shift */ + printf("toggle "); + } + break; + + case ADB_ACTION_NOTREADY: + printf("adb: not yet initialized\n"); + break; + + default: + printf("intr: unknown ADB state\n"); + } + + ADB_VIA_INTR_ENABLE(); /* enable ADB interrupt on IIs. */ + + splx(s); /* restore */ + + return; +} /* end adb_intr_IIsi */ + + +int +send_adb_cuda(u_char *in, u_char *buffer, void *compRout, void *data, int +command) +{ + int i, s, len; + + if (adbActionState == ADB_ACTION_NOTREADY) + return 1; + + s = splhigh(); /* don't interrupt while we are messing with the ADB */ + + if ((adbActionState == ADB_ACTION_IDLE) && /* ADB available? */ + (ADB_INTR_IS_OFF)) { /* and no incoming interrupt? */ + + } else if (adbWriteDelay == 0) /* it's busy, but is anything waiting? */ + adbWriteDelay = 1; /* if no, then we'll "queue" it up */ + else { + splx(s); + return 1; /* really busy! */ + } + + if ((long) in == (long) 0) { /* need to convert? */ + /* don't need to use adb_cmd_extra here because this section will be called */ + /* ONLY when it is an ADB command (no RTC or PRAM) */ + if ((command & 0x0c) == 0x08) /* copy addl data ONLY if doing a listen! */ + len = buffer[0]; /* length of additional data */ + else + len = 0; /* no additional data */ + + adbOutputBuffer[0] = 2 + len; /* dev. type + command + addl. data */ + adbOutputBuffer[1] = 0x00; /* mark as an ADB command */ + adbOutputBuffer[2] = (u_char) command; /* load command */ + + for (i = 1; i <= len; i++) /* copy additional output data, if any */ + adbOutputBuffer[2 + i] = buffer[i]; + } else + for (i = 0; i <= (adbOutputBuffer[0] + 1); i++) + adbOutputBuffer[i] = in[i]; + + adbSentChars = 0; /* nothing sent yet */ + adbBuffer = buffer; /* save buffer to know where to save result */ + adbCompRout = compRout; /* save completion routine pointer */ + adbCompData = data; /* save completion routine data pointer */ + adbWaitingCmd = adbOutputBuffer[2]; /* save wait command */ + + if (adbWriteDelay != 1) { /* start command now? */ + printf("out start "); + adbActionState = ADB_ACTION_OUT; /* set next state */ + ADB_SET_SR_OUTPUT(); /* set shift register for OUT */ + ADB_SR() = adbOutputBuffer[adbSentChars + 1]; /* load byte for output */ + ADB_SET_STATE_ACKOFF_CUDA(); + ADB_SET_STATE_TIP(); /* tell ADB that we want to send */ + } + adbWriteDelay = 1; /* something in the write "queue" */ + + splx(s); + + if (0x0100 <= (s & 0x0700)) /* were VIA1 interrupts blocked ? */ + /* poll until byte done */ + while ((adbActionState != ADB_ACTION_IDLE) || (ADB_INTR_IS_ON) + || (adbWaiting == 1)) + if (ADB_SR_INTR_IS_ON) /* wait for "interrupt" */ + adb_intr_cuda(); /* go process "interrupt" */ + + return 0; +} /* send_adb_cuda */ + + +/* TO DO: add one or two zshard calls in here */ +void +adb_intr_II(void) +{ + int i, len, intr_on = 0; + int send = 0, do_srq = 0; + unsigned int s; + + s = splhigh(); /* can't be too careful - might be called */ + /* from a routine, NOT an interrupt */ + + ADB_VIA_CLR_INTR(); /* clear interrupt */ + + ADB_VIA_INTR_DISABLE(); /* disable ADB interrupt on IIs. */ + +/*if (ADB_INTR_IS_ON)*/ +/* printf("INTR ON ");*/ +if (ADB_INTR_IS_ON) + intr_on=1; /* save for later */ + + switch (adbActionState) { + case ADB_ACTION_IDLE: + if ( !intr_on ) { + /*printf("FAKE DROPPED \n");*/ + /*printf(" XX ");*/ + i=ADB_SR(); + break; + } + adbNextEnd=0; + /*printf("idle ");*/ + adbInputBuffer[0] = 1; + adbInputBuffer[1] = ADB_SR(); /* get first byte */ + /*printf("0x%02x ", adbInputBuffer[1]);*/ + ADB_SET_SR_INPUT(); /* make sure SR is set to IN */ + adbActionState = ADB_ACTION_IN; /* set next state */ + ADB_SET_STATE_EVEN(); /* set bus state to even */ + adbBusState = ADB_BUS_EVEN; + break; + + case ADB_ACTION_IN: + adbInputBuffer[++adbInputBuffer[0]] = ADB_SR(); /* get byte */ + /*printf("in 0x%02x ", adbInputBuffer[adbInputBuffer[0]]);*/ + ADB_SET_SR_INPUT(); /* make sure SR is set to IN */ + + /* + * Check for an unsolicited Service Request (SRQ). + * An empty SRQ packet NEVER ends, so we must manually + * check for the following condition. + */ + if ( adbInputBuffer[0]==4 && adbInputBuffer[2]==0xff && + adbInputBuffer[3]==0xff && adbInputBuffer[4]==0xff && + intr_on && !adbNextEnd ) + do_srq=1; + + if (adbNextEnd==1) { /* process last byte of packet */ + adbNextEnd=0; + /*printf("done: ");*/ + + /* + * If the following conditions are true (4 byte + * message, last 3 bytes are 0xff) then we + * basically got a "no response" from the ADB chip, + * so change the message to an empty one. + * We also clear intr_on to stop the SRQ send later + * on because these packets normally have the SRQ + * bit set even when there is NOT a pending SRQ. + */ + if ( adbInputBuffer[0]==4 && adbInputBuffer[2]==0xff && + adbInputBuffer[3]==0xff && adbInputBuffer[4]==0xff ) { + /*printf("NO RESP ");*/ + intr_on=0; + adbInputBuffer[0]=0; + } + + adbLastDevice=(adbInputBuffer[1] & 0xf0) >> 4; + + if ((!adbWaiting || adbPolling ) + && (adbInputBuffer[0] != 0)) { + /* unsolicided - ignore if starting */ + if (!adbStarting) + adb_handle_unsol(adbInputBuffer); + } else if ( !adbPolling ) { /* someone asked for it */ + /*printf("SOL: ");*/ + /*print_single(adbInputBuffer);*/ + if (adbBuffer != (long) 0) { /* if valid return data pointer */ + /* get return length minus extras */ + len = adbInputBuffer[0] - 1; + + /* if adb_op is ever made to be called from a user + * routine, we should use a copyout or copyin + * here to be sure we're in the correct context. */ + for (i = 1; i <= len; i++) + adbBuffer[i] = adbInputBuffer[i + 1]; + if (len < 0) + len = 0; + adbBuffer[0] = len; + } + adb_comp_exec(); + } + + adbWaiting=0; + adbPolling=0; + adbInputBuffer[0]=0; + adbBuffer = (long) 0; + adbCompRout = (long) 0; + adbCompData = (long) 0; + /* + * Since we are done, check whether there is any data + * waiting to do out. If so, start the sending the data. + */ + if (adbOutQueueHasData == 1) { + /*printf("XXX: DOING OUT QUEUE\n");*/ + /* copy over data */ + for (i = 0; i <= (adbOutQueue.outBuf[0] + 1); i++) + adbOutputBuffer[i] = adbOutQueue.outBuf[i]; + adbBuffer = adbOutQueue.saveBuf; /* user data area */ + adbCompRout = adbOutQueue.compRout; /* completion routine */ + adbCompData = adbOutQueue.data; /* comp. rout. data */ + adbOutQueueHasData = 0; /* currently processing "queue" entry */ + adbPolling=0; + send=1; + /* if intr_on is true, then it's a SRQ + * so poll other devices. */ + } else if (intr_on) { + /*printf("starting POLL ");*/ + do_srq=1; + adbPolling=1; + } else if ( (adbInputBuffer[1] & 0x0f) != 0x0c) { + /*printf("xC HACK ");*/ + adbPolling=1; + send=1; + adbOutputBuffer[0]=1; + adbOutputBuffer[1]=(adbInputBuffer[1] & 0xf0) | 0x0c; + } else { + /*printf("ending ");*/ + adbBusState=ADB_BUS_IDLE; + adbActionState=ADB_ACTION_IDLE; + ADB_SET_STATE_IDLE_II(); + break; + } + } + + /* + * If do_srq is true then something above determined that + * the message has ended and some device is sending a + * service request. So we need to determine the next device + * and send a poll to it. (If the device we send to isn't the + * one that sent the SRQ, that ok as it will be caught + * the next time though.) + */ + if ( do_srq ) { + /*printf("SRQ! ");*/ + adbPolling=1; + adb_guess_next_device(); + adbOutputBuffer[0]=1; + adbOutputBuffer[1]=((adbLastDevice & 0x0f) << 4) | 0x0c; + send=1; + } + + /* + * If send is true then something above determined that + * the message has ended and we need to start sending out + * a new message immediately. This could be because there + * is data waiting to go out or because an SRQ was seen. + */ + if ( send ) { + adbNextEnd = 0; + adbSentChars = 0; /* nothing sent yet */ + adbActionState = ADB_ACTION_OUT; /* set next state */ + ADB_SET_SR_OUTPUT(); /* set shift register for OUT */ + ADB_SR() = adbOutputBuffer[1]; /* load byte for output */ + adbBusState = ADB_BUS_CMD; /* set bus to cmd state */ + ADB_SET_STATE_CMD(); /* tell ADB that we want to send */ + break; + } + + /* + * We only get this far if the message hasn't + * ended yet. + */ + if (!intr_on) /* if adb intr. on then the */ + adbNextEnd=1; /* NEXT byte is the last */ + + switch (adbBusState) { /* set to next state */ + case ADB_BUS_EVEN: + ADB_SET_STATE_ODD(); /* set state to odd */ + adbBusState = ADB_BUS_ODD; + break; + + case ADB_BUS_ODD: + ADB_SET_STATE_EVEN(); /* set state to even */ + adbBusState = ADB_BUS_EVEN; + break; + default: + printf("strange state!!!\n"); /* huh? */ + break; + } + break; + + case ADB_ACTION_OUT: + adbNextEnd=0; + if (!adbPolling) + adbWaiting=1; /* not unsolicited */ + i=ADB_SR(); /* clear interrupt */ + adbSentChars++; + /* + * If the outgoing data was a TALK, we must + * switch to input mode to get the result. + */ + if ( (adbOutputBuffer[1] & 0x0c) == 0x0c ) { + adbInputBuffer[0]=1; + adbInputBuffer[1]=i; + adbActionState=ADB_ACTION_IN; + ADB_SET_SR_INPUT(); + adbBusState= ADB_BUS_EVEN; + ADB_SET_STATE_EVEN(); + /*printf("talk out 0x%02x ", i);*/ + break; + } + + /* + * If it's not a TALK, check whether all data has been + * sent. If so, call the completion routine and clean up. + * If not, advance to the next state. + */ + /*printf("non-talk out 0x%0x ", i);*/ + ADB_SET_SR_OUTPUT(); + if (adbOutputBuffer[0] == adbSentChars) { /* check for done */ + /*printf("done \n");*/ + adb_comp_exec(); + adbBuffer = (long) 0; + adbCompRout = (long) 0; + adbCompData = (long) 0; + if (adbOutQueueHasData == 1) { + /* copy over data */ + for (i = 0; i <= (adbOutQueue.outBuf[0] + 1); i++) + adbOutputBuffer[i] = adbOutQueue.outBuf[i]; + adbBuffer = adbOutQueue.saveBuf; /* user data area */ + adbCompRout = adbOutQueue.compRout; /* completion routine */ + adbCompData = adbOutQueue.data; /* comp. rout. data */ + adbOutQueueHasData = 0; /* currently processing "queue" entry */ + adbPolling=0; + } else { + adbOutputBuffer[0]=1; + adbOutputBuffer[1]=(adbOutputBuffer[1] & 0xf0) | 0x0c; + adbPolling=1; /* non-user poll */ + } + adbNextEnd = 0; + adbSentChars = 0; /* nothing sent yet */ + adbActionState = ADB_ACTION_OUT; /* set next state */ + ADB_SET_SR_OUTPUT(); /* set shift register for OUT */ + ADB_SR() = adbOutputBuffer[1]; /* load byte for output */ + adbBusState = ADB_BUS_CMD; /* set bus to cmd state */ + ADB_SET_STATE_CMD(); /* tell ADB that we want to send */ + break; + } + + ADB_SR() = adbOutputBuffer[adbSentChars + 1]; + switch (adbBusState) { /* advance to next state */ + case ADB_BUS_EVEN: + ADB_SET_STATE_ODD(); /* set state to odd */ + adbBusState = ADB_BUS_ODD; + break; + + case ADB_BUS_CMD: + case ADB_BUS_ODD: + ADB_SET_STATE_EVEN(); /* set state to even */ + adbBusState = ADB_BUS_EVEN; + break; + + default: + printf("strange state!!! (0x%x)\n", adbBusState); + break; + } + break; + + default: + printf("adb: unknown ADB state (during intr)\n"); + } + + ADB_VIA_INTR_ENABLE(); /* enable ADB interrupt on IIs. */ + + splx(s); /* restore */ + + return; + +} + + +/* + * send_adb version for II series machines + */ +int +send_adb_II(u_char *in, u_char *buffer, void *compRout, void *data, int command) +{ + int i, s, len; + + if (adbActionState == ADB_ACTION_NOTREADY) /* return if ADB not available */ + return 1; + + s = splhigh(); /* don't interrupt while we are messing with the ADB */ + + if (0 != adbOutQueueHasData) { /* right now, "has data" means "full" */ + splx(s); /* sorry, try again later */ + return 1; + } + if ((long) in == (long) 0) { /* need to convert? */ + /* + * Don't need to use adb_cmd_extra here because this section + * will be called ONLY when it is an ADB command (no RTC or + * PRAM), especially on II series! + */ + if ((command & 0x0c) == 0x08) /* copy addl data ONLY if doing a listen! */ + len = buffer[0]; /* length of additional data */ + else + len = 0; /* no additional data */ + + adbOutQueue.outBuf[0] = 1 + len; /* command + addl. data */ + adbOutQueue.outBuf[1] = (u_char) command; /* load command */ + + for (i = 1; i <= len; i++) /* copy additional output data, if any */ + adbOutQueue.outBuf[1 + i] = buffer[i]; + } else + /* if data ready, just copy over */ + for (i = 0; i <= (adbOutQueue.outBuf[0] + 1); i++) + adbOutQueue.outBuf[i] = in[i]; + + adbOutQueue.saveBuf = buffer; /* save buffer to know where to save result */ + adbOutQueue.compRout = compRout; /* save completion routine pointer */ + adbOutQueue.data = data; /* save completion routine data pointer */ + + if ((adbActionState == ADB_ACTION_IDLE) && /* is ADB available? */ + (ADB_INTR_IS_OFF) && /* and no incoming interrupts? */ + (adbPolling == 0)) { /* and we are not currently polling */ + /* then start command now */ + for (i = 0; i <= (adbOutQueue.outBuf[0] + 1); i++) /* copy over data */ + adbOutputBuffer[i] = adbOutQueue.outBuf[i]; + + adbBuffer = adbOutQueue.saveBuf; /* pointer to user data area */ + adbCompRout = adbOutQueue.compRout; /* pointer to the completion routine */ + adbCompData = adbOutQueue.data; /* pointer to the completion routine data */ + + adbSentChars = 0; /* nothing sent yet */ + adbActionState = ADB_ACTION_OUT; /* set next state */ + adbBusState = ADB_BUS_CMD; /* set bus to cmd state */ + + ADB_SET_SR_OUTPUT(); /* set shift register for OUT */ + + ADB_SR() = adbOutputBuffer[adbSentChars + 1]; /* load byte for output */ + ADB_SET_STATE_CMD(); /* tell ADB that we want to send */ + adbOutQueueHasData = 0; /* currently processing "queue" entry */ + } else + adbOutQueueHasData = 1; /* something in the write "queue" */ + + splx(s); + + if (0x0100 <= (s & 0x0700)) /* were VIA1 interrupts blocked ? */ + /* poll until message done */ + while ((adbActionState != ADB_ACTION_IDLE) || (ADB_INTR_IS_ON) + || (adbWaiting == 1) || (adbPolling == 1)) + if (ADB_SR_INTR_IS_ON) /* wait for "interrupt" */ + adb_intr_II(); /* go process "interrupt" */ + + return 0; +} + + +/* + * This routine is called from the II series interrupt routine + * to determine what the "next" device is that should be polled. + */ +int +adb_guess_next_device(void) +{ + int last, i, dummy; + + if (adbStarting) { + /* start polling EVERY device, since we can't + * be sure there is anything in the device table yet */ + if (adbLastDevice < 1 || adbLastDevice > 15) + adbLastDevice = 1; + if (++adbLastDevice > 15) /* point to next one */ + adbLastDevice = 1; + } else { + /* find the next device using the device table */ + if (adbLastDevice < 1 || adbLastDevice > 15) /* let's be parinoid */ + adbLastDevice = 2; + last = 1; /* default index location */ + + for (i = 1; i < 16; i++) /* find index entry */ + if (ADBDevTable[i].currentAddr == adbLastDevice) { /* look for device */ + last = i; /* found it */ + break; + } + + dummy = last; /* index to start at */ + for (;;) { /* find next device in index */ + if (++dummy > 15) /* wrap around if needed */ + dummy = 1; + if (dummy == last) { /* didn't find any other + * device! This can happen if there + * are no devices on the bus */ + dummy = 2; + break; + } + /* found the next device */ + if (ADBDevTable[dummy].devType != 0) + break; + } + adbLastDevice=ADBDevTable[dummy].currentAddr; + } + return adbLastDevice; +} + +/* + * Called when when an adb interrupt happens. + * This routine simply transfers control over to the appropriate + * code for the machine we are running on. + */ +void +adb_intr(void) +{ + switch (adbHardware) { + case ADB_HW_II: + adb_intr_II(); + break; + + case ADB_HW_IISI: + adb_intr_IIsi(); + break; + + case ADB_HW_PB: + break; + + case ADB_HW_CUDA: + adb_intr_cuda(); + break; + + case ADB_HW_UNKNOWN: + break; + } +} + + +/* + * called when when an adb interrupt happens + * + * IIsi version of adb_intr + * + */ +void +adb_intr_IIsi(void) +{ + int i, ending, len; + unsigned int s; + + s = splhigh(); /* can't be too careful - might be called */ + /* from a routine, NOT an interrupt */ + + ADB_VIA_CLR_INTR(); /* clear interrupt */ + + ADB_VIA_INTR_DISABLE(); /* disable ADB interrupt on IIs. */ + +switch_start: + switch (adbActionState) { + case ADB_ACTION_IDLE: + delay(ADB_ACK_DELAY); /* short delay is required + * before the first byte */ + + ADB_SET_SR_INPUT(); /* make sure SR is set to IN */ + ADB_SET_STATE_ACTIVE(); /* signal start of data frame */ + adbInputBuffer[1] = ADB_SR(); /* get byte */ + adbInputBuffer[0] = 1; + adbActionState = ADB_ACTION_IN; /* set next state */ + + ADB_SET_STATE_ACKON(); /* start ACK to ADB chip */ + delay(ADB_ACK_DELAY); /* delay */ + ADB_SET_STATE_ACKOFF(); /* end ACK to ADB chip */ + zshard(0); /* grab any serial interrupts */ + break; + + case ADB_ACTION_IN: + ADB_SET_SR_INPUT(); /* make sure SR is set to IN */ + adbInputBuffer[++adbInputBuffer[0]] = ADB_SR(); /* get byte */ + if (ADB_INTR_IS_OFF) /* check for end of frame */ + ending = 1; + else + ending = 0; + + ADB_SET_STATE_ACKON(); /* start ACK to ADB chip */ + delay(ADB_ACK_DELAY); /* delay */ + ADB_SET_STATE_ACKOFF(); /* end ACK to ADB chip */ + zshard(0); /* grab any serial interrupts */ + + if (1 == ending) { /* end of message? */ + ADB_SET_STATE_INACTIVE(); /* signal end of frame */ + /* this section _should_ handle all ADB and RTC/PRAM type commands, */ + /* but there may be more... */ + /* note: commands are always at [4], even for rtc/pram commands */ + if ((adbWaiting == 1) && /* are we waiting AND */ + (adbInputBuffer[4] == adbWaitingCmd) && /* the cmd we sent AND */ + ((adbInputBuffer[2] == 0x00) || /* it's from the + * ADB device OR */ + (adbInputBuffer[2] == 0x01))) { /* it's from the PRAM/RTC device */ + + /* is this data we are waiting for? */ + if (adbBuffer != (long) 0) { /* if valid return data pointer */ + /* get return length minus extras */ + len = adbInputBuffer[0] - 4; + /* if adb_op is ever made to be called from a user + * routine, we should use a copyout or copyin + * here to be sure we're in the correct context */ + for (i = 1; i <= len; i++) + adbBuffer[i] = adbInputBuffer[4 + i]; + if (len < 0) + len = 0; + adbBuffer[0] = len; + } + adb_comp_exec(); /* call completion routine */ + + adbWaitingCmd = 0; /* reset "waiting" vars */ + adbWaiting = 0; + adbBuffer = (long) 0; + adbCompRout = (long) 0; + adbCompData = (long) 0; + } else { + /* pass the data off to the handler */ + /* This section IGNORES all data that is not from + * the ADB sub-device. That is, not from rtc or pram. + * Maybe we should fix later, but do the other + * devices every send things without + * being asked? */ + if (adbStarting == 0) /* ignore if during adbreinit */ + if (adbInputBuffer[2] == 0x00) + adb_handle_unsol(adbInputBuffer); + } + + adbActionState = ADB_ACTION_IDLE; + adbInputBuffer[0] = 0; /* reset length */ + + if (adbWriteDelay == 1) { /* were we waiting to write? */ + adbSentChars = 0; /* nothing sent yet */ + adbActionState = ADB_ACTION_OUT; /* set next state */ + + delay(ADB_ACK_DELAY); /* delay */ + zshard(0); /* grab any serial interrupts */ + + if (ADB_INTR_IS_ON) { /* ADB intr low during write */ + ADB_SET_STATE_IDLE_IISI(); /* reset */ + ADB_SET_SR_INPUT(); /* make sure SR is set to IN */ + adbSentChars = 0; /* must start all over */ + adbActionState = ADB_ACTION_IDLE; /* new state */ + adbInputBuffer[0] = 0; + /* may be able to take this out later */ + delay(ADB_ACK_DELAY); /* delay */ + break; + } + ADB_SET_STATE_ACTIVE(); /* tell ADB that we want to send */ + ADB_SET_STATE_ACKOFF(); /* make sure */ + ADB_SET_SR_OUTPUT(); /* set shift register for OUT */ + ADB_SR() = adbOutputBuffer[adbSentChars + 1]; + ADB_SET_STATE_ACKON(); /* tell ADB byte ready to shift */ + } + } + break; + + case ADB_ACTION_OUT: + i = ADB_SR(); /* reset SR-intr in IFR */ + ADB_SET_SR_OUTPUT(); /* set shift register for OUT */ + + ADB_SET_STATE_ACKOFF(); /* finish ACK */ + adbSentChars++; + if (ADB_INTR_IS_ON) { /* ADB intr low during write */ + ADB_SET_STATE_IDLE_IISI(); /* reset */ + ADB_SET_SR_INPUT(); /* make sure SR is set to IN */ + adbSentChars = 0; /* must start all over */ + adbActionState = ADB_ACTION_IDLE; /* new state */ + adbInputBuffer[0] = 0; + adbWriteDelay = 1; /* must retry when done with read */ + delay(ADB_ACK_DELAY); /* delay */ + zshard(0); /* grab any serial interrupts */ + goto switch_start; /* process next state right now */ + break; + } + delay(ADB_ACK_DELAY); /* required delay */ + zshard(0); /* grab any serial interrupts */ + + if (adbOutputBuffer[0] == adbSentChars) { /* check for done */ + if (0 == adb_cmd_result(adbOutputBuffer)) { /* do we expect data back? */ + adbWaiting = 1; /* signal waiting for return */ + adbWaitingCmd = adbOutputBuffer[2]; /* save waiting command */ + } else { /* no talk, so done */ + adb_comp_exec(); /* call completion routine */ + adbWaitingCmd = 0; /* reset "waiting" vars, just in case */ + adbBuffer = (long) 0; + adbCompRout = (long) 0; + adbCompData = (long) 0; + } + + adbWriteDelay = 0; /* done writing */ + adbActionState = ADB_ACTION_IDLE; /* signal bus is idle */ + ADB_SET_SR_INPUT(); /* make sure SR is set to IN */ + ADB_SET_STATE_INACTIVE(); /* end of frame */ + } else { + ADB_SR() = adbOutputBuffer[adbSentChars + 1]; /* send next byte */ + ADB_SET_STATE_ACKON(); /* signal byte ready to shift */ + } + break; + + case ADB_ACTION_NOTREADY: + printf("adb: not yet initialized\n"); + break; + + default: + printf("intr: unknown ADB state\n"); + } + + ADB_VIA_INTR_ENABLE(); /* enable ADB interrupt on IIs. */ + + splx(s); /* restore */ + + return; +} /* end adb_intr_IIsi */ + + +/***************************************************************************** + * if the device is currently busy, and there is no data waiting to go out, then + * the data is "queued" in the outgoing buffer. If we are already waiting, then + * we return. + * in: if (in==0) then the command string is built from command and buffer + * if (in!=0) then in is used as the command string + * buffer: additional data to be sent (used only if in==0) + * this is also where return data is stored + * compRout: the completion routine that is called when then return value + * is received (if a return value is expected) + * data: a data pointer that can be used by the completion routine + * command: an ADB command to be sent (used only if in==0) + * + */ +int +send_adb_IIsi(u_char *in, u_char *buffer, void *compRout, void *data, int +command) +{ + int i, s, len; + + if (adbActionState == ADB_ACTION_NOTREADY) + return 1; + + s = splhigh(); /* don't interrupt while we are messing with the ADB */ + + if ((adbActionState == ADB_ACTION_IDLE) && /* ADB available? */ + (ADB_INTR_IS_OFF)) { /* and no incoming interrupt? */ + + } else if (adbWriteDelay == 0) /* it's busy, but is anything waiting? */ + adbWriteDelay = 1; /* if no, then we'll "queue" it up */ + else { + splx(s); + return 1; /* really busy! */ + } + + if ((long) in == (long) 0) { /* need to convert? */ + /* don't need to use adb_cmd_extra here because this section will be called */ + /* ONLY when it is an ADB command (no RTC or PRAM) */ + if ((command & 0x0c) == 0x08) /* copy addl data ONLY if doing a listen! */ + len = buffer[0]; /* length of additional data */ + else + len = 0; /* no additional data */ + + adbOutputBuffer[0] = 2 + len; /* dev. type + command + addl. data */ + adbOutputBuffer[1] = 0x00; /* mark as an ADB command */ + adbOutputBuffer[2] = (u_char) command; /* load command */ + + for (i = 1; i <= len; i++) /* copy additional output data, if any */ + adbOutputBuffer[2 + i] = buffer[i]; + } else + for (i = 0; i <= (adbOutputBuffer[0] + 1); i++) + adbOutputBuffer[i] = in[i]; + + adbSentChars = 0; /* nothing sent yet */ + adbBuffer = buffer; /* save buffer to know where to save result */ + adbCompRout = compRout; /* save completion routine pointer */ + adbCompData = data; /* save completion routine data pointer */ + adbWaitingCmd = adbOutputBuffer[2]; /* save wait command */ + + if (adbWriteDelay != 1) { /* start command now? */ + adbActionState = ADB_ACTION_OUT; /* set next state */ + + ADB_SET_STATE_ACTIVE(); /* tell ADB that we want to send */ + ADB_SET_STATE_ACKOFF(); /* make sure */ + + ADB_SET_SR_OUTPUT(); /* set shift register for OUT */ + + ADB_SR() = adbOutputBuffer[adbSentChars + 1]; /* load byte for output */ + + ADB_SET_STATE_ACKON(); /* tell ADB byte ready to shift */ + } + adbWriteDelay = 1; /* something in the write "queue" */ + + splx(s); + + if (0x0100 <= (s & 0x0700)) /* were VIA1 interrupts blocked ? */ + /* poll until byte done */ + while ((adbActionState != ADB_ACTION_IDLE) || (ADB_INTR_IS_ON) + || (adbWaiting == 1)) + if (ADB_SR_INTR_IS_ON) /* wait for "interrupt" */ + adb_intr_IIsi(); /* go process "interrupt" */ + + return 0; +} /* send_adb_IIsi */ + + +/* + * adb_comp_exec + * This is a general routine that calls the completion routine if there is one. + */ +void adb_comp_exec(void) +{ + if ( (long)0 != adbCompRout ) /* don't call if empty return location */ + #ifdef __NetBSD__ + asm ( " + movml #0xffff, sp@- | save all registers + movl %0,a2 | adbCompData + movl %1,a1 | adbCompRout + movl %2,a0 | adbBuffer + movl %3,d0 | adbWaitingCmd + jbsr a1@ | go call the routine + movml sp@+, #0xffff | restore all registers" + : : "g" (adbCompData), "g" (adbCompRout), "g" (adbBuffer), "g" (adbWaitingCmd) ); + #else /* for macos based testing */ + asm + { + movem.l a0/a1/a2/d0,-(a7) + move.l adbCompData,a2 + move.l adbCompRout,a1 + move.l adbBuffer,a0 + move.w adbWaitingCmd,d0 + jsr (a1) + movem.l (a7)+,d0/a2/a1/a0 + } + #endif +} + + +/* + * this routine handles what needs to be done after a message is read + * from the adb data points to the raw data received from the device, + * including device number (on IIsi) and result code. + */ +void +adb_handle_unsol(u_char *in) +{ + int i, cmd; + u_char data[MAX_ADB_MSG_LENGTH]; + + /* make local copy so we don't destroy the real one - it may + * be needed later. */ + for (i = 0; i <= (in[0] + 1); i++) + data[i] = in[i]; + + switch (adbHardware) { + case ADB_HW_II: + /* adjust the "length" byte */ + cmd = data[1]; + if (data[0] < 2) + data[1] = 0; + else + data[1] = data[0] - 1; + + adb_complete((data + 1), (long) 0, cmd); + + break; + + case ADB_HW_IISI: + case ADB_HW_CUDA: + /* only handles ADB for now */ + if (0 != *(data + 2)) + return; + + /* adjust the "length" byte */ + cmd = data[4]; + if (data[0] < 5) + data[4] = 0; + else + data[4] = data[0] - 4; + + adb_complete((data + 4), (long) 0, cmd); + + break; + + case ADB_HW_PB: + return; /* how does PM handle "unsolicited" messages? */ + case ADB_HW_UNKNOWN: + return; + } + + return; + +#if 0 + /* this should really be used later, once it is set up properly */ + /* AND we need to make sure that we DON'T call it if it is zero! */ + if ( 0 != ADBDevTable[i].devType ) + (*(ADBDevTable[i].ServiceRtPtr))(); +#endif +} + + +/* + * This is my version of the ADBOp routine. It mainly just calls the hardware-specific + * routine. + * + * data : pointer to data area to be used by compRout + * compRout : completion routine + * buffer : for LISTEN: points to data to send - MAX 8 data bytes, byte 0 = # of bytes + * : for TALK: points to place to save return data + * command : the adb command to send + + * result : 0 = success + * : -1 = could not complete + */ +int +adb_op(Ptr buffer, Ptr compRout, Ptr data, short command) +{ + int result; + + switch (adbHardware) { + case ADB_HW_II: + result = send_adb_II((u_char *) 0, + (u_char *) buffer, (void *) compRout, + (void *) data, (int) command); + break; + + case ADB_HW_IISI: + result = send_adb_IIsi((u_char *) 0, + (u_char *) buffer, (void *) compRout, + (void *) data, (int) command); + /* + * I wish I knew why this delay is needed. It usually needs to + * be here when several commands are sent in close succession, + * especially early in device probes when doing collision + * detection. It must be some race condition. Sigh. - jpw + */ + delay(100); + break; + + case ADB_HW_PB: + result = pm_adb_op( + (u_char *) buffer, (void *) compRout, + (void *) data, (int) command); + break; + + case ADB_HW_CUDA: + result = send_adb_cuda((u_char *) 0, + (u_char *) buffer, (void *) compRout, + (void *) data, (int) command); + break; + + case ADB_HW_UNKNOWN: + default: + return -1; + } + if (result == 0) + return 0; + else + return -1; +} + + +/* + * adb_cleanup + * This routine simply calls the appropriate version of the adb_cleanup routine. + */ +void +adb_cleanup(u_char *in) +{ + switch (adbHardware) { + case ADB_HW_II: + ADB_VIA_CLR_INTR(); /* clear interrupt */ + break; + + case ADB_HW_IISI: + /* get those pesky clock ticks we missed while booting */ + adb_cleanup_IIsi(in); + break; + + case ADB_HW_PB: + /* TO DO: really PM_VIA_CLR_INTR - should we put it in pm_direct.h? */ + via_reg(VIA1, vIFR) = 0x90; /* clear interrupt */ + break; + + case ADB_HW_CUDA: + /* TO DO: probably need some sort of cleanup for Cuda */ + ADB_VIA_CLR_INTR(); + ADB_SET_STATE_IDLE_CUDA(); + break; + + case ADB_HW_UNKNOWN: + return; + } +} + + +/* + * adb_cleanup_IIsi + * This is sort of a "read" routine that forces the adb hardware through a read cycle + * if there is something waiting. This helps "clean up" any commands that may have gotten + * stuck or stopped during the boot process. + * + */ +void +adb_cleanup_IIsi(u_char *buffer) +{ + int i; + int dummy; + int s; + long my_time; + int endofframe; + + delay(ADB_ACK_DELAY); + + i = 1; /* skip over [0] */ + s = splhigh(); /* block ALL interrupts while we are working */ + ADB_SET_SR_INPUT(); /* make sure SR is set to IN */ + ADB_VIA_INTR_DISABLE(); /* disable ADB interrupt on IIs. */ + /* this is required, especially on faster machines */ + delay(ADB_ACK_DELAY); + + if (ADB_INTR_IS_ON) { + ADB_SET_STATE_ACTIVE(); /* signal start of data frame */ + + endofframe = 0; + while (0 == endofframe) { + /* poll for ADB interrupt and watch for timeout */ + /* if time out, keep going in hopes of not hanging the ADB chip - I think */ + my_time = ADB_ACK_DELAY * 5; + while ((ADB_SR_INTR_IS_OFF) && (my_time-- > 0)) + dummy = via_reg(VIA1, vBufB); + + buffer[i++] = ADB_SR(); /* reset interrupt flag by reading vSR */ + /* perhaps put in a check here that ignores all data + * after the first MAX_ADB_MSG_LENGTH bytes ??? */ + if (ADB_INTR_IS_OFF) /* check for end of frame */ + endofframe = 1; + + ADB_SET_STATE_ACKON(); /* send ACK to ADB chip */ + delay(ADB_ACK_DELAY); /* delay */ + ADB_SET_STATE_ACKOFF(); /* send ACK to ADB chip */ + } + ADB_SET_STATE_INACTIVE(); /* signal end of frame and delay */ + + /* probably don't need to delay this long */ + delay(ADB_ACK_DELAY); + } + buffer[0] = --i; /* [0] is length of message */ + ADB_VIA_INTR_ENABLE(); /* enable ADB interrupt on IIs. */ + splx(s); /* restore interrupts */ + + return; +} /* adb_cleanup_IIsi */ + + +/* + * adb_reinit sets up the adb stuff + * + */ +void +adb_reinit(void) +{ + u_char send_string[MAX_ADB_MSG_LENGTH]; + int s; + int i, x; + int command; + int result; + int saveptr; /* point to next free relocation address */ + int device; + int nonewtimes; /* times thru loop w/o any new devices */ + ADBDataBlock data; /* temp. holder for getting device info */ + + /* Make sure we are not interrupted while building the table. */ + s = splhigh(); + + ADBNumDevices=0; /* no devices yet */ + + /* Let intr routines know we are running reinit */ + adbStarting = 1; + + /* Initialize the ADB table. For now, we'll always use the same + * table that is defined at the beginning of this file - no mallocs. + */ + for (i = 0; i < 16; i++) + ADBDevTable[i].devType = 0; + + adb_setup_hw_type(); /* setup hardware type */ + + /* Set up all the VIA bits we need to do the ADB stuff. + */ + switch (adbHardware) { + case ADB_HW_II: + via_reg(VIA1, vDirB) |= 0x30; /* register B bits 4 and 5: outputs */ + via_reg(VIA1, vDirB) &= 0xf7; /* register B bit 3: input */ + via_reg(VIA1, vACR) &= ~vSR_OUT; /* make sure SR is set to IN (II, IIsi) */ + adbActionState = ADB_ACTION_IDLE; /* used by all types of hardware (II, IIsi) */ + adbBusState = ADB_BUS_IDLE; /* this var. used in II-series code only */ + via_reg(VIA1, vIER) = 0x84; /* make sure VIA interrupts are on (II, IIsi) */ + ADB_SET_STATE_IDLE_II(); /* set ADB bus state to idle */ + break; + + case ADB_HW_IISI: + via_reg(VIA1, vDirB) |= 0x30; /* register B bits 4 and 5: outputs */ + via_reg(VIA1, vDirB) &= 0xf7; /* register B bit 3: input */ + via_reg(VIA1, vACR) &= ~vSR_OUT; /* make sure SR is set to IN (II, IIsi) */ + adbActionState = ADB_ACTION_IDLE; /* used by all types of hardware (II, IIsi) */ + adbBusState = ADB_BUS_IDLE; /* this var. used in II-series code only */ + via_reg(VIA1, vIER) = 0x84; /* make sure VIA interrupts are on (II, IIsi) */ + ADB_SET_STATE_IDLE_IISI(); /* set ADB bus state to idle */ + break; + + case ADB_HW_PB: + break; /* there has to be more than this? */ + + case ADB_HW_CUDA: + via_reg(VIA1, vDirB) |= 0x30; /* register B bits 4 and 5: outputs */ + via_reg(VIA1, vDirB) &= 0xf7; /* register B bit 3: input */ + via_reg(VIA1, vACR) &= ~vSR_OUT; /* make sure SR is set to IN */ + adbActionState = ADB_ACTION_IDLE; /* used by all types of hardware */ + adbBusState = ADB_BUS_IDLE; /* this var. used in II-series code only */ + via_reg(VIA1, vIER) = 0x84; /* make sure VIA interrupts are on */ + ADB_SET_STATE_IDLE_CUDA(); /* set ADB bus state to idle */ + break; + + case ADB_HW_UNKNOWN: /* if type unknown then skip out */ + default: + via_reg(VIA1, vIER) = 0x04; /* turn interrupts off - TO DO: turn PB ints off? */ + return; + break; + } + + /* + * Clear out any "leftover" commands. Remember that up until this + * point, the interrupt routine will be either off or it should be + * able to ignore inputs until the device table is built. + */ + for (i = 0; i < 30; i++) { + delay(ADB_ACK_DELAY); + adb_cleanup(send_string); + printf("adb: cleanup: "); + print_single(send_string); + delay(ADB_ACK_DELAY); + if (ADB_INTR_IS_OFF) + break; + } + + /* send an ADB reset first */ + adb_op_sync((Ptr) 0, (Ptr) 0, (Ptr) 0, (short) 0x00); + + /* + * Probe for ADB devices. + * Probe devices 1-15 quickly to determine which + * device addresses are in use and which are free. + * For each address that is in use, move the device + * at that address to a higher free address. + * Continue doing this at that address until + * no device responds at that address. Then move + * the last device that was moved back to the + * original address. Do this for the remaining + * addresses that we determined were in use. + * + * When finished, do this entire process over again + * with the updated list of in use addresses. Do this + * until no new devices have been found in 20 passes + * though the in use address list. + * (This probably seems long and complicated, but it's + * the best way to detect multiple devices at the + * same address - sometimes it takes a couple of tries + * before the collision is detected.) + */ + + /* initial scan through the devices */ + for ( i=1; i<16; i++) { + command = (int) (0x0f | ((int) (i & 0x000f) << 4)); /* talk R3 */ + result = adb_op_sync((Ptr) send_string, (Ptr) 0, (Ptr) 0, (short) command); + if (0x00 != send_string[0]) { /* anything come back ?? */ + ADBDevTable[++ADBNumDevices].devType = (u_char) send_string[2]; + ADBDevTable[ADBNumDevices].origAddr = i; + ADBDevTable[ADBNumDevices].currentAddr = i; + ADBDevTable[ADBNumDevices].DataAreaAddr = (long) 0; + ADBDevTable[ADBNumDevices].ServiceRtPtr = (void *) 0; + /*printf("initial device found (at index %d)\n", ADBNumDevices);*/ + pm_check_adb_devices(i); + } + } + + /* find highest unused address */ + for ( saveptr=15; saveptr>0; saveptr-- ) + if ( -1 == get_adb_info(&data, saveptr) ) + break; + + if ( saveptr==0 ) /* no free addresses??? */ + saveptr=15; + + /*printf("first free is: 0x%02x\n", saveptr);*/ + /*printf("devices: %d\n", ADBNumDevices);*/ + + nonewtimes=0; /* no loops w/o new devices */ + while ( nonewtimes++ < 11 ) { + for ( i=1; i <= ADBNumDevices; i++ ) { + device=ADBDevTable[i].currentAddr; + /*printf("moving device 0x%02x to 0x%02x (index 0x%02x) ", device, saveptr, i);*/ + + /* send TALK R3 to address */ + command = (int) (0x0f | ((int) (device & 0x000f) << 4)); + adb_op_sync((Ptr) send_string, (Ptr) 0, (Ptr) 0, (short) command); + + /* move device to higher address */ + command = (int) (0x0b | ((int) (device & 0x000f) << 4)); + send_string[0]=2; + send_string[1]=(u_char) (saveptr | 0x60 ); + send_string[2]=0xfe; + adb_op_sync((Ptr) send_string, (Ptr) 0, (Ptr) 0, (short) command); + + /* send TALK R3 - anything at old address? */ + command = (int) (0x0f | ((int) (device & 0x000f) << 4)); + result = adb_op_sync((Ptr) send_string, (Ptr) 0, (Ptr) 0, (short) command); + if ( send_string[0] != 0 ) { + /* new device found */ + /* update data for previously moved device */ + ADBDevTable[i].currentAddr=saveptr; + /*printf("old device at index %d\n",i);*/ + /* add new device in table */ + /*printf("new device found\n");*/ + ADBDevTable[++ADBNumDevices].devType = (u_char) send_string[2]; + ADBDevTable[ADBNumDevices].origAddr = device; + ADBDevTable[ADBNumDevices].currentAddr = device; + ADBDevTable[ADBNumDevices].DataAreaAddr = (long) 0; + ADBDevTable[ADBNumDevices].ServiceRtPtr = (void *) 0; + /* find next unused address */ + for ( x=saveptr; x>0; x-- ) + if ( -1 == get_adb_info(&data, x) ) { + saveptr=x; + break; + } + /*printf("new free is 0x%02x\n", saveptr);*/ + nonewtimes=0; + } else { + /*printf("moving back...\n");*/ + /* move old device back */ + command = (int) (0x0b | ((int) (saveptr & 0x000f) << 4)); + send_string[0]=2; + send_string[1]=(u_char) (device | 0x60 ); + send_string[2]=0xfe; + adb_op_sync((Ptr) send_string, (Ptr) 0, (Ptr) 0, (short) command); + } + } + } + + adb_prog_switch_enable(); /* enable the programmer's switch, if we have one */ + + if (0 == ADBNumDevices) /* tell user if no devices found */ + printf("adb: no devices found\n"); + + adbStarting = 0; /* not starting anymore */ + printf("adb: ADBReInit complete\n"); + + splx(s); + + return; +} + + +/* adb_cmd_result + * This routine lets the caller know whether the specified adb command string should + * expect a returned result, such as a TALK command. + * returns: 0 if a result should be expected + * 1 if a result should NOT be expected + */ +int +adb_cmd_result(u_char *in) +{ + switch (adbHardware) { + case ADB_HW_II: + /* was it an ADB talk command? */ + if ((in[1] & 0x0c) == 0x0c) + return 0; + else + return 1; + break; + + case ADB_HW_IISI: + case ADB_HW_CUDA: + /* was is an ADB talk command? */ + if ((in[1] == 0x00) && ((in[2] & 0x0c) == 0x0c)) + return 0; + else + /* was is an RTC/PRAM read date/time? */ + if ((in[1] == 0x01) && (in[2] == 0x03)) + return 0; + else + return 1; + break; + + case ADB_HW_PB: + return 1; + break; + + case ADB_HW_UNKNOWN: + default: + return 1; + } +} + + +/* adb_cmd_extra + * This routine lets the caller know whether the specified adb command string may have + * extra data appended to the end of it, such as a LISTEN command. + * returns: 0 if extra data is allowed + * 1 if extra data is NOT allowed + */ +int +adb_cmd_extra(u_char *in) +{ + switch (adbHardware) { + case ADB_HW_II: + if ((in[1] & 0x0c) == 0x08) /* was it a listen command? */ + return 0; + else + return 1; + break; + + case ADB_HW_IISI: + case ADB_HW_CUDA: + /* TO DO: support needs to be added to recognize RTC + * and PRAM commands */ + if ((in[2] & 0x0c) == 0x08) /* was it a listen command? */ + return 0; + else /* add others later */ + return 1; + break; + + case ADB_HW_PB: + return 1; + break; + + case ADB_HW_UNKNOWN: + default: + return 1; + } +} + + +/* adb_op_sync + * This routine does exactly what the adb_op routine does, except that after the + * adb_op is called, it waits until the return value is present before returning + */ +int +adb_op_sync(Ptr buffer, Ptr compRout, Ptr data, short command) +{ + int result; + int flag; + + flag = 0; + result = adb_op(buffer, (void *) adb_op_comprout, + (void *) &flag, command); /* send command */ + if (result == 0) { /* send ok? */ + /* Don't need to use adb_cmd_result since this section is + * hardware independent, and for ADB commands only (no RTC or PRAM) */ + /*if ((command & 0x0c) == 0x0c) was it a talk? */ + while (0 == flag) ; + + return 0; + } else + return result; +} + + +/* adb_op_comprout + * This function is used by the adb_op_sync routine so it knows when the function is + * done. + */ +void adb_op_comprout(void) +{ + #ifdef __NetBSD__ + asm ( "movw #1,a2@ | update flag value" ); + #else /* for macos based testing */ + asm { move.w #1,(a2) } /* update flag value */ + #endif +} + +void +adb_setup_hw_type(void) +{ + long response; + + response = mac68k_machine.machineid; + + switch (response) { + case 6: /* II */ + case 7: /* IIx */ + case 8: /* IIcx */ + case 9: /* SE/30 */ + case 11: /* IIci */ + case 22: /* Quadra 700 */ + case 30: /* Centris 650 */ + case 35: /* Quadra 800 */ + case 36: /* Quadra 650 */ + case 52: /* Centris 610 */ + case 53: /* Centris 650 */ + adbHardware = ADB_HW_II; + printf("adb: using II series hardware support\n"); + break; + case 18: /* IIsi */ + case 20: /* Quadra 900 - not sure if IIsi or not */ + case 23: /* Classic II */ + case 26: /* Quadra 950 - not sure if IIsi or not */ + case 27: /* LC III, Performa 450 */ + case 37: /* LC II, Performa 400/405/430 */ + case 44: /* IIvi */ + case 45: /* Performa 600 */ + case 48: /* IIvx */ + case 49: /* Color Classic - not sure if IIsi or not */ + case 62: /* Performa 460/465/467 */ + case 83: /* Color Classic II (number right?) - not sure if IIsi or not */ + adbHardware = ADB_HW_IISI; + printf("adb: using IIsi series hardware support\n"); + break; + case 21: /* PowerBook 170 */ + case 25: /* PowerBook 140 */ + case 54: /* PowerBook 145 */ + case 34: /* PowerBook 160 */ + case 84: /* PowerBook 165 */ + case 50: /* PowerBook 165c */ + case 33: /* PowerBook 180 */ + case 71: /* PowerBook 180c */ + case 115: /* PowerBook 150 */ + adbHardware=ADB_HW_PB; + pm_setup_adb(); + printf("adb: using PowerBook 100-series hardware support\n"); + break; + case 29: /* PowerBook Duo 210 */ + case 32: /* PowerBook Duo 230 */ + case 38: /* PowerBook Duo 250 */ + case 72: /* PowerBook 500 series */ + case 77: /* PowerBook Duo 270 */ + case 102: /* PowerBook Duo 280 */ + case 103: /* PowerBook Duo 280c */ + adbHardware=ADB_HW_PB; + pm_setup_adb(); + printf("adb: using PowerBook Duo-series and PowerBook 500-series hardware support\n"); + break; + case 60: /* Centris 660AV */ + case 78: /* Quadra 840AV */ + case 89: /* LC 475, Performa 475/476 */ + case 92: /* LC 575, Performa 575/577/578 */ + case 94: /* Quadra 605 */ + case 98: /* LC 630, Performa 630, Quadra 630 */ + adbHardware = ADB_HW_CUDA; + printf("adb: using Cuda series hardware support\n"); + break; + default: + adbHardware = ADB_HW_UNKNOWN; + printf("adb: hardware type unknown for this machine\n"); + printf("adb: ADB support is disabled\n"); + break; + } +} + +int +count_adbs(void) +{ + int i; + int found; + + found = 0; + + for (i = 1; i < 16; i++) + if (0 != ADBDevTable[i].devType) + found++; + + return found; +} + +int +get_ind_adb_info(ADBDataBlock * info, int index) +{ + if ((index < 1) || (index > 15)) /* check range 1-15 */ + return (-1); + + /* printf("index 0x%x devType is: 0x%x\n", index, + ADBDevTable[index].devType); */ + if (0 == ADBDevTable[index].devType) /* make sure it's a valid entry */ + return (-1); + + info->devType = ADBDevTable[index].devType; + info->origADBAddr = ADBDevTable[index].origAddr; + info->dbServiceRtPtr = (Ptr) ADBDevTable[index].ServiceRtPtr; + info->dbDataAreaAddr = (Ptr) ADBDevTable[index].DataAreaAddr; + + return (ADBDevTable[index].currentAddr); +} + +int +get_adb_info(ADBDataBlock * info, int adbAddr) +{ + int i; + + if ((adbAddr < 1) || (adbAddr > 15)) /* check range 1-15 */ + return (-1); + + for (i = 1; i < 15; i++) + if (ADBDevTable[i].currentAddr == adbAddr) { + info->devType = ADBDevTable[i].devType; + info->origADBAddr = ADBDevTable[i].origAddr; + info->dbServiceRtPtr = (Ptr)ADBDevTable[i].ServiceRtPtr; + info->dbDataAreaAddr = ADBDevTable[i].DataAreaAddr; + return 0; /* found */ + } + + return (-1); /* not found */ +} + +int +set_adb_info(ADBSetInfoBlock * info, int adbAddr) +{ + int i; + + if ((adbAddr < 1) || (adbAddr > 15)) /* check range 1-15 */ + return (-1); + + for (i = 1; i < 15; i++) + if (ADBDevTable[i].currentAddr == adbAddr) { + ADBDevTable[i].ServiceRtPtr = + (void *) (info->siServiceRtPtr); + ADBDevTable[i].DataAreaAddr = info->siDataAreaAddr; + return 0; /* found */ + } + + return (-1); /* not found */ + +} + +#ifdef HWDIRECT +long +mrg_adbintr(void) +{ + adb_intr(); + return 1; /* mimic mrg_adbintr in macrom.h just in case */ +} + +long +mrg_pmintr(void) /* we don't do this yet */ +{ + pm_intr(); + return 1; /* mimic mrg_pmintr in macrom.h just in case */ +} +#endif + +/* caller should really use machine-independant version: getPramTime */ +/* this version does pseudo-adb access only */ +int +adb_read_date_time(unsigned long *time) +{ + u_char output[MAX_ADB_MSG_LENGTH]; + int result; + int flag = 0; + + switch (adbHardware) { + case ADB_HW_II: + return -1; + + case ADB_HW_IISI: + output[0] = 0x02; /* 2 byte message */ + output[1] = 0x01; /* to pram/rtc device */ + output[2] = 0x03; /* read date/time */ + result = send_adb_IIsi((u_char *) output, + (u_char *) output, (void *) adb_op_comprout, + (void *) &flag, (int) 0); + if (result != 0) /* exit if not sent */ + return -1; + + while (0 == flag) ; /* wait for result */ + + *time = (long) (*(long *) (output + 1)); + return 0; + + case ADB_HW_PB: + return -1; + + case ADB_HW_CUDA: + output[0] = 0x02; /* 2 byte message */ + output[1] = 0x01; /* to pram/rtc device */ + output[2] = 0x03; /* read date/time */ + result = send_adb_cuda((u_char *) output, + (u_char *) output, (void *) adb_op_comprout, + (void *) &flag, (int) 0); + if (result != 0) /* exit if not sent */ + return -1; + + while (0 == flag) ; /* wait for result */ + + *time = (long) (*(long *) (output + 1)); + return 0; + + case ADB_HW_UNKNOWN: + default: + return -1; + } +} + +/* caller should really use machine-independant version: setPramTime */ +/* this version does pseudo-adb access only */ +int +adb_set_date_time(unsigned long time) +{ + u_char output[MAX_ADB_MSG_LENGTH]; + int result; + int flag = 0; + + switch (adbHardware) { + case ADB_HW_II: + return -1; + + case ADB_HW_IISI: + output[0] = 0x06; /* 6 byte message */ + output[1] = 0x01; /* to pram/rtc device */ + output[2] = 0x09; /* set date/time */ + output[3] = (u_char) (time >> 24); + output[4] = (u_char) (time >> 16); + output[5] = (u_char) (time >> 8); + output[6] = (u_char) (time); + result = send_adb_IIsi((u_char *) output, + (u_char *) 0, (void *) adb_op_comprout, + (void *) &flag, (int) 0); + if (result != 0) /* exit if not sent */ + return -1; + + while (0 == flag) ; /* wait for send to finish */ + + return 0; + + case ADB_HW_PB: + return -1; + + case ADB_HW_CUDA: + output[0] = 0x06; /* 6 byte message */ + output[1] = 0x01; /* to pram/rtc device */ + output[2] = 0x09; /* set date/time */ + output[3] = (u_char) (time >> 24); + output[4] = (u_char) (time >> 16); + output[5] = (u_char) (time >> 8); + output[6] = (u_char) (time); + result = send_adb_cuda((u_char *) output, + (u_char *) 0, (void *) adb_op_comprout, + (void *) &flag, (int) 0); + if (result != 0) /* exit if not sent */ + return -1; + + while (0 == flag) ; /* wait for send to finish */ + + return 0; + + case ADB_HW_UNKNOWN: + default: + return -1; + } +} + + +int +adb_poweroff(void) +{ + u_char output[MAX_ADB_MSG_LENGTH]; + int result; + + switch (adbHardware) { + case ADB_HW_IISI: + output[0] = 0x02; /* 2 byte message */ + output[1] = 0x01; /* to pram/rtc/soft-power device */ + output[2] = 0x0a; /* set date/time */ + result = send_adb_IIsi((u_char *) output, + (u_char *) 0, (void *) 0, (void *) 0, (int) 0); + if (result != 0) /* exit if not sent */ + return -1; + + for (;;) ; /* wait for power off */ + + return 0; + + case ADB_HW_PB: + return -1; + + /* TO DO: some cuda models claim to do soft power - check out */ + case ADB_HW_II: /* II models don't do soft power */ + case ADB_HW_CUDA: /* cuda doesn't do soft power */ + case ADB_HW_UNKNOWN: + default: + return -1; + } +} /* adb_poweroff */ + +int +adb_prog_switch_enable(void) +{ + u_char output[MAX_ADB_MSG_LENGTH]; + int result; + int flag = 0; + + switch (adbHardware) { + case ADB_HW_IISI: + output[0] = 0x03; /* 3 byte message */ + output[1] = 0x01; /* to pram/rtc/soft-power device */ + output[2] = 0x1c; /* prog. switch control */ + output[3] = 0x01; /* enable */ + result = send_adb_IIsi((u_char *) output, + (u_char *) 0, (void *) adb_op_comprout, + (void *) &flag, (int) 0); + if (result != 0) /* exit if not sent */ + return -1; + + while (0 == flag) ; /* wait for send to finish */ + + return 0; + + case ADB_HW_PB: + return -1; + + case ADB_HW_II: /* II models don't do prog. switch */ + case ADB_HW_CUDA: /* cuda doesn't do prog. switch */ + case ADB_HW_UNKNOWN: + default: + return -1; + } +} /* adb_prog_switch_enable */ + +int +adb_prog_switch_disable(void) +{ + u_char output[MAX_ADB_MSG_LENGTH]; + int result; + int flag = 0; + + switch (adbHardware) { + case ADB_HW_IISI: + output[0] = 0x03; /* 3 byte message */ + output[1] = 0x01; /* to pram/rtc/soft-power device */ + output[2] = 0x1c; /* prog. switch control */ + output[3] = 0x01; /* disable */ + result = send_adb_IIsi((u_char *) output, + (u_char *) 0, (void *) adb_op_comprout, + (void *) &flag, (int) 0); + if (result != 0) /* exit if not sent */ + return -1; + + while (0 == flag) ; /* wait for send to finish */ + + return 0; + + case ADB_HW_PB: + return -1; + + case ADB_HW_II: /* II models don't do prog. switch */ + case ADB_HW_CUDA: /* cuda doesn't do prog. switch */ + case ADB_HW_UNKNOWN: + default: + return -1; + } +} /* adb_prog_switch_disable */ + +#ifdef HWDIRECT + +int +CountADBs(void) +{ + return (count_adbs()); +} + +void +ADBReInit(void) +{ + adb_reinit(); +} + +int +GetIndADB(ADBDataBlock * info, int index) +{ + return (get_ind_adb_info(info, index)); +} + +int +GetADBInfo(ADBDataBlock * info, int adbAddr) +{ + return (get_adb_info(info, adbAddr)); +} + +int +SetADBInfo(ADBSetInfoBlock * info, int adbAddr) +{ + return (set_adb_info(info, adbAddr)); +} + +int +ADBOp(Ptr buffer, Ptr compRout, Ptr data, short commandNum) +{ + return (adb_op(buffer, compRout, data, commandNum)); +} + +#endif 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 <sys/param.h> #include <sys/systm.h> -#include <machine/adbsys.h> #include <machine/cpu.h> #include <machine/macinfo.h> #include <machine/viareg.h> -#include "adbvar.h" -#include "../mac68k/macrom.h" +#include <arch/mac68k/mac68k/macrom.h> +#include <arch/mac68k/dev/adbvar.h> extern struct mac68k_machine_S mac68k_machine; @@ -182,10 +181,13 @@ adb_init() return; } +#ifndef HWDIRECT /* We don't care about ADB ROM driver if we are + * using the HWDIRECT method for ADB/PRAM/RTC. */ if (!mrg_romready()) { printf("adb: no ROM ADB driver in this kernel for this machine\n"); return; } +#endif printf("adb: bus subsystem\n"); #ifdef MRG_DEBUG printf("adb: call mrg_initadbintr\n"); @@ -199,12 +201,21 @@ adb_init() /* ADBReInit pre/post-processing */ JADBProc = adb_jadbproc; - /* Initialize ADB */ + /* + * Initialize ADB + * + * If using HWDIRECT method to access ADB, then call + * ADBReInit directly. Otherwise use ADB AlternateInit() + */ +#ifdef HWDIRECT + printf("adb: calling ADBReInit\n"); + ADBReInit(); +#else #ifdef MRG_DEBUG printf("adb: calling ADBAlternateInit.\n"); #endif - ADBAlternateInit(); +#endif #ifdef MRG_DEBUG printf("adb: done with ADBReInit\n"); 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 <machine/adbsys.h> + #define ADB_MAXTRACE (NBPG / sizeof(int) - 1) extern int adb_traceq[ADB_MAXTRACE]; extern int adb_traceq_tail; @@ -64,3 +66,25 @@ void extdms_complete __P((void)); /* adbsys.c */ void adb_complete __P((caddr_t buffer, caddr_t data_area, int adb_command)); void extdms_init __P((int)); + +#ifdef HWDIRECT + +/* types of adb hardware that we (will eventually) support */ +#define ADB_HW_UNKNOWN 0x01 /* don't know */ +#define ADB_HW_II 0x02 /* Mac II series */ +#define ADB_HW_IISI 0x03 /* Mac IIsi series */ +#define ADB_HW_PB 0x04 /* PowerBook series */ +#define ADB_HW_CUDA 0x05 /* Machines with a Cuda chip */ + +/* adb_direct.c */ +int adb_poweroff __P((void)); +int CountADBs __P((void)); +void ADBReInit __P((void)); +int GetIndADB __P((ADBDataBlock * info, int index)); +int GetADBInfo __P((ADBDataBlock * info, int adbAddr)); +int SetADBInfo __P((ADBSetInfoBlock * info, int adbAddr)); +int ADBOp __P((Ptr buffer, Ptr compRout, Ptr data, short commandNum)); +int adb_read_date_time __P((unsigned long *t)); +int adb_set_date_time __P((unsigned long t)); + +#endif diff --git a/sys/arch/mac68k/dev/pm_direct.c b/sys/arch/mac68k/dev/pm_direct.c new file mode 100644 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 <sys/types.h> +#include <sys/cdefs.h> +#include <sys/systm.h> + +#include <machine/adbsys.h> +#include <machine/cpu.h> +#include <machine/macinfo.h> +#include <machine/param.h> +#include <machine/viareg.h> + +#include <arch/mac68k/mac68k/macrom.h> +#include <arch/mac68k/dev/adbvar.h> + +#include "pm_direct.h" + +/* hardware dependent values */ +extern u_short ADBDelay; +extern u_int32_t HwCfgFlags3; + +/* define the types of the Power Manager */ +#define PM_HW_UNKNOWN 0x00 /* don't know */ +#define PM_HW_PB1XX 0x01 /* PowerBook 1XX series */ +#define PM_HW_PB5XX 0x02 /* PowerBook Duo and 5XX series */ + +/* useful macros */ +#define PM_SR() via_reg(VIA1, vSR) +#define PM_VIA_INTR_ENABLE() via_reg(VIA1, vIER) = 0x90 +#define PM_VIA_INTR_DISABLE() via_reg(VIA1, vIER) = 0x10 +#define PM_VIA_CLR_INTR() via_reg(VIA1, vIFR) = 0x90 +#define PM_SET_STATE_ACKON() via_reg(VIA2, vBufB) |= 0x04 +#define PM_SET_STATE_ACKOFF() via_reg(VIA2, vBufB) &= ~0x04 +#define PM_IS_ON ( 0x02 == (via_reg(VIA2, vBufB) & 0x02) ) +#define PM_IS_OFF ( 0x00 == (via_reg(VIA2, vBufB) & 0x02) ) + +/* + * Valiables for internal use + */ +int pmHardware = PM_HW_UNKNOWN; +u_short pm_existent_ADB_devices = 0x0; /* each bit expresses the existent ADB device */ +u_int pm_LCD_brightness = 0x0; +u_int pm_LCD_contrast = 0x0; +u_int pm_counter = 0; /* clock count */ + +/* these values shows that number of data returned after 'send' cmd is sent */ +char pm_send_cmd_type[] = { + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x01,0x01,0xff,0xff,0xff,0xff,0xff,0xff, 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0x00, + 0xff,0x00,0x02,0x01,0x01,0xff,0xff,0xff, 0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x04,0x14,0xff,0xff,0xff,0xff,0xff,0xff, 0x00,0x00,0x02,0xff,0xff,0xff,0xff,0xff, + 0x01,0x01,0xff,0xff,0xff,0xff,0xff,0xff, 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff, + 0x01,0x00,0x02,0x02,0xff,0x01,0x03,0x01, 0x00,0x01,0x00,0x00,0x00,0xff,0xff,0xff, + 0x02,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff, + 0x01,0x01,0x01,0xff,0xff,0xff,0xff,0xff, 0x00,0x00,0xff,0xff,0xff,0xff,0x04,0x04, + 0x04,0xff,0x00,0xff,0xff,0xff,0xff,0xff, 0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x01,0x02,0xff,0xff,0xff,0xff,0xff,0xff, 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff, + 0x02,0x02,0x02,0x04,0xff,0x00,0xff,0xff, 0x01,0x01,0x03,0x02,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x01,0x01,0xff,0xff,0x00,0x00,0xff,0xff, + 0xff,0x04,0x00,0xff,0xff,0xff,0xff,0xff, 0x03,0xff,0x00,0xff,0x00,0xff,0xff,0x00, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff +}; + +/* these values shows that number of data returned after 'receive' cmd is sent */ +char pm_receive_cmd_type[] = { + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x02,0x02,0xff,0xff,0xff,0xff,0xff,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x05,0x15,0xff,0xff,0xff,0xff,0xff,0xff, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x02,0x02,0xff,0xff,0xff,0xff,0xff,0xff, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x02,0x00,0x03,0x03,0xff,0xff,0xff,0xff, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x04,0x04,0x03,0x09,0xff,0xff,0xff,0xff, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x01, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x06,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x02,0x02,0xff,0xff,0xff,0xff,0xff,0xff, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x02,0x00,0x00,0x00,0xff,0xff,0xff,0xff, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x02,0x02,0xff,0xff,0x02,0xff,0xff,0xff, + 0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00, 0xff,0xff,0x02,0xff,0xff,0xff,0xff,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +}; + + +/* + * Define the private functions + */ + +/* for debugging */ +#ifdef PM_DEBUG +void pm_printerr __P(( char *, int, int, char * )); +#endif + +int pm_wait_busy __P((int)); +int pm_wait_free __P((int)); + +/* these functions are for the PB1XX series */ +int pm_receive_pm1 __P((u_char *)); +int pm_send_pm1 __P((u_char,int)); +int pm_pmgrop_pm1 __P((PMData *)); +void pm_intr_pm1 __P((void)); + +/* these functions are for the PB Duo series and the PB 5XX series */ +int pm_receive_pm2 __P((u_char *)); +int pm_send_pm2 __P((u_char)); +int pm_pmgrop_pm2 __P((PMData *)); +void pm_intr_pm2 __P((void)); + +/* this function is MRG-Based (for testing) */ +int pm_pmgrop_mrg __P((PMData *)); + +/* these functions are called from adb_direct.c */ +void pm_setup_adb __P((void)); +void pm_check_adb_devices __P((int)); +void pm_intr __P((void)); +int pm_adb_op __P((u_char *, void *, void *, int)); + +/* these functions also use the valiables of adb_direct.c */ +void pm_adb_get_TALK_result __P((PMData *)); +void pm_adb_get_ADB_data __P((PMData *)); +void pm_adb_poll_next_device_pm1 __P((PMData *)); + + +/* + * These valiables are in adb_direct.c. + */ +extern u_char *adbBuffer; /* pointer to user data area */ +#define MAX_ADB_MSG_LENGTH 20 +extern u_char adbInputBuffer[MAX_ADB_MSG_LENGTH]; /* data input buffer */ +extern void *adbCompRout; /* pointer to the completion routine */ +extern void *adbCompData; /* pointer to the completion routine data */ +extern int adbWaiting; /* waiting for return data from the device */ +extern int adbWaitingCmd; /* ADB command we are waiting for */ +extern int adbStarting; /* doing ADB reinit, so do "polling" differently */ + +/* + * Define the external functions + */ +extern int zshard(int); /* from zs.c */ +extern void adb_comp_exec(void); /* from adb_direct.c */ + + +#ifdef PM_DEBUG +/* + * This function dumps contents of the PMData + */ +void +pm_printerr(ttl, rval, num, data) + char *ttl; + int rval; + int num; + char *data; +{ + int i; + + printf( "pm: %s:%04x %02x ", ttl, rval, num ); + for( i=0; i<num; i++ ) + printf( "%02x ", data[i] ); + printf( "\n" ); +} +#endif + + + +/* + * Check the hardware type of the Power Manager + */ +void +pm_setup_adb(void) +{ + switch (mac68k_machine.machineid) { + case MACH_MACPB140: + case MACH_MACPB145: + case MACH_MACPB150: + case MACH_MACPB160: + case MACH_MACPB165: + case MACH_MACPB165C: + case MACH_MACPB170: + case MACH_MACPB180: + case MACH_MACPB180C: + pmHardware = PM_HW_PB1XX; + break; + case MACH_MACPB210: + case MACH_MACPB230: + case MACH_MACPB250: + case MACH_MACPB270: + case MACH_MACPB280: + case MACH_MACPB280C: + case MACH_MACPB500: + pmHardware = PM_HW_PB5XX; + break; + default: + break; + } +} + + +/* + * Check the existent ADB devices + */ +void +pm_check_adb_devices(id) + int id; +{ + u_short ed = 0x1; + + ed <<= id; + pm_existent_ADB_devices |= ed; +} + + +/* + * Wait until PM IC is busy + */ +int +pm_wait_busy(delay) + int delay; +{ + while(PM_IS_ON) { +#ifdef PM_GRAB_SI + zshard(0); /* grab any serial interrupts */ +#endif + if ((--delay) < 0) + return( 1 ); /* timeout */ + } + return( 0 ); +} + + +/* + * Wait until PM IC is free + */ +int +pm_wait_free(delay) + int delay; +{ + while(PM_IS_OFF) { +#ifdef PM_GRAB_SI + zshard(0); /* grab any serial interrupts */ +#endif + if ((--delay) < 0) + return( 0 ); /* timeout */ + } + return( 1 ); +} + + + +/* + * Functions for the PB1XX series + */ + +/* + * Receive data from PM for the PB1XX series + */ +int +pm_receive_pm1(data) + u_char *data; +{ + int rval = 0xffffcd34; + + via_reg(VIA2, vDirA) = 0x00; + + switch( 1 ) { + default: + if (pm_wait_busy( 0x40 ) != 0) + break; /* timeout */ + + PM_SET_STATE_ACKOFF(); + *data = via_reg(VIA2, 0x200); + + rval = 0xffffcd33; + if (pm_wait_free( 0x40 ) == 0) + break; /* timeout */ + + rval = 0x00; + break; + } + + PM_SET_STATE_ACKON(); + via_reg(VIA2, vDirA) = 0x00; + + return( rval ); +} + + + +/* + * Send data to PM for the PB1XX series + */ +int +pm_send_pm1(data, delay) + u_char data; + int delay; +{ + int rval; + + via_reg(VIA2, vDirA) = 0xff; + via_reg(VIA2, 0x200) = data; + + PM_SET_STATE_ACKOFF(); + if (pm_wait_busy( 0x400 ) != 0) { + PM_SET_STATE_ACKON(); + via_reg(VIA2, vDirA) = 0x00; + + return( 0xffffcd36 ); + } + + rval = 0x0; + PM_SET_STATE_ACKON(); + if (pm_wait_free( 0x40 ) == 0) + rval = 0xffffcd35; + + PM_SET_STATE_ACKON(); + via_reg(VIA2, vDirA) = 0x00; + + return( rval ); +} + + +/* + * My PMgrOp routine for the PB1XX series + */ +int +pm_pmgrop_pm1(pmdata) + PMData *pmdata; +{ + int i; + int s = 0x81815963; + u_char via1_vIER, via1_vDirA; + int rval = 0; + int num_pm_data = 0; + u_char pm_cmd; + u_char pm_data; + u_char *pm_buf; + + /* disable all inetrrupts but PM */ + via1_vIER = via_reg(VIA1, vIER); + PM_VIA_INTR_DISABLE(); + + via1_vDirA = via_reg(VIA1, vDirA); + + switch( pmdata->command ) { + default: + for( i=0; i<7; i++ ) { + via_reg(VIA2, vDirA) = 0x00; + + /* wait until PM is free */ + if (pm_wait_free( ADBDelay ) == 0) { /* timeout */ + via_reg(VIA2, vDirA) = 0x00; + /* restore formar value */ + via_reg(VIA1, vDirA) = via1_vDirA; + via_reg(VIA1, vIER) = via1_vIER; + return( 0xffffcd38 ); + } + + switch( mac68k_machine.machineid ) { + case MACH_MACPB160: + case MACH_MACPB165: + case MACH_MACPB165C: + case MACH_MACPB180: + case MACH_MACPB180C: + { + int delay = ADBDelay * 16; + + via_reg(VIA2, vDirA) = 0x00; + while((via_reg(VIA2, 0x200) == 0x7f) && (delay >= 0)) + delay--; + + if (delay < 0) { /* timeout */ + via_reg(VIA2, vDirA) = 0x00; + /* restore formar value */ + via_reg(VIA1, vIER) = via1_vIER; + return( 0xffffcd38 ); + } + } + } /* end switch */ + + s=splhigh(); + + via1_vDirA = via_reg(VIA1, vDirA); + via_reg(VIA1, vDirA) &= 0x7f; + + pm_cmd = (u_char)(pmdata->command & 0xff); + if ((rval = pm_send_pm1( pm_cmd, ADBDelay*8 )) == 0) /* succeeded to send PM command */ + break; + + via_reg(VIA1, vDirA) = via1_vDirA; + splx(s); + } /* end for */ + + /* failed to send a command */ + if (i == 7) { + via_reg(VIA2, vDirA) = 0x00; + /* restore formar value */ + via_reg(VIA1, vDirA) = via1_vDirA; + via_reg(VIA1, vIER) = via1_vIER; + return( 0xffffcd38 ); + } + + /* send # of PM data */ + num_pm_data = pmdata->num_data; + if ((rval = pm_send_pm1( (u_char)(num_pm_data & 0xff), ADBDelay*8 )) != 0) + break; /* timeout */ + + /* send PM data */ + pm_buf = (u_char *)pmdata->s_buf; + for( i=0; i<num_pm_data; i++ ) + if((rval = pm_send_pm1( pm_buf[i], ADBDelay*8 )) != 0) + break; /* timeout */ + if ((i != num_pm_data) && (num_pm_data != 0)) + break; /* timeout */ + + /* Will PM IC return data? */ + if ((pm_cmd & 0x08) == 0) { + rval = 0; + break; /* no returned data */ + } + + rval = 0xffffcd37; + if (pm_wait_busy( ADBDelay ) != 0) { + break; /* timeout */ + } + + /* receive PM command */ + if ((rval = pm_receive_pm1( &pm_data )) != 0) + break; + + pmdata->command = pm_data; + + /* receive number of PM data */ + if ((rval = pm_receive_pm1( &pm_data )) != 0) + break; /* timeout */ + num_pm_data = pm_data; + pmdata->num_data = num_pm_data; + + /* receive PM data */ + pm_buf = (u_char *)pmdata->r_buf; + for( i=0; i<num_pm_data; i++ ) { + if ((rval = pm_receive_pm1( &pm_data )) != 0) + break; /* timeout */ + pm_buf[i] = pm_data; + } + + rval = 0; + } + + via_reg(VIA2, vDirA) = 0x00; + + /* restore formar value */ + via_reg(VIA1, vDirA) = via1_vDirA; + via_reg(VIA1, vIER) = via1_vIER; + if (s != 0x81815963) + splx(s); + + return( rval ); +} + + +/* + * My PM interrupt routine for PB100-series + */ +void +pm_intr_pm1(void) +{ + int s; + int rval; + PMData pmdata; + + s = splhigh(); + + PM_VIA_CLR_INTR(); /* clear VIA1 interrupt */ + + /* ask PM what happend */ + pmdata.command = 0x78; + pmdata.num_data = 0; + pmdata.data[0] = pmdata.data[1] = 0; + pmdata.s_buf = &pmdata.data[2]; + pmdata.r_buf = &pmdata.data[2]; + rval = pm_pmgrop_pm1( &pmdata ); + if (rval != 0) { +#ifdef PM_DEBUG + printf( "pm: PM is not ready. error code=%08x\n", rval ); +#endif + splx(s); + } + + if ((pmdata.data[2] & 0x10) == 0x10) { + if ((pmdata.data[2] & 0x0f) == 0) { /* ADB data that were requested by TALK command */ + pm_adb_get_TALK_result(&pmdata); + } else if ((pmdata.data[2] & 0x08) == 0x8) { /* PM is requesting to poll */ + pm_adb_poll_next_device_pm1(&pmdata); + } else if ((pmdata.data[2] & 0x04) == 0x4) { /* ADB device event */ + pm_adb_get_ADB_data(&pmdata); + } + } else { +#ifdef PM_DEBUG + pm_printerr( "driver does not supported this event.", rval, pmdata.num_data, pmdata.data ); +#endif + } + + splx(s); +} + + + +/* + * Functions for the PB Duo series and the PB 5XX series + */ + +/* + * Receive data from PM for the PB Duo series and the PB 5XX series + */ +int +pm_receive_pm2(data) + u_char *data; +{ + int i; + int rval; + + rval = 0xffffcd34; + + switch( 1 ) { + default: + /* set VIA SR to input mode */ + via_reg(VIA1, vACR) |= 0x0c; + via_reg(VIA1, vACR) &= ~0x10; + i = PM_SR(); + + PM_SET_STATE_ACKOFF(); + if (pm_wait_busy((int)ADBDelay*32) != 0) + break; /* timeout */ + + PM_SET_STATE_ACKON(); + rval = 0xffffcd33; + if (pm_wait_free((int)ADBDelay*32) == 0) + break; /* timeout */ + + *data = PM_SR(); + rval = 0; + + break; + } + + PM_SET_STATE_ACKON(); + via_reg(VIA1, vACR) |= 0x1c; + + return( rval ); +} + + + +/* + * Send data to PM for the PB Duo series and the PB 5XX series + */ +int +pm_send_pm2(data) + u_char data; +{ + int rval; + + via_reg(VIA1, vACR) |= 0x1c; + PM_SR() = data; + + PM_SET_STATE_ACKOFF(); + rval = 0xffffcd36; + if (pm_wait_busy((int)ADBDelay*32) != 0) { + PM_SET_STATE_ACKON(); + + via_reg(VIA1, vACR) |= 0x1c; + + return( rval ); + } + + PM_SET_STATE_ACKON(); + rval = 0xffffcd35; + if (pm_wait_free((int)ADBDelay*32) != 0) + rval = 0; + + PM_SET_STATE_ACKON(); + via_reg(VIA1, vACR) |= 0x1c; + + return( rval ); +} + + + +/* + * My PMgrOp routine for the PB Duo series and the PB 5XX series + */ +int +pm_pmgrop_pm2(pmdata) + PMData *pmdata; +{ + int i; + int s; + u_char via1_vIER; + int rval = 0; + int num_pm_data = 0; + u_char pm_cmd; + short pm_num_rx_data; + u_char pm_data; + u_char *pm_buf; + + s=splhigh(); + + /* disable all inetrrupts but PM */ + via1_vIER = 0x10; + via1_vIER &= via_reg(VIA1, vIER); + via_reg(VIA1, vIER) = via1_vIER; + if (via1_vIER != 0x0) + via1_vIER |= 0x80; + + switch( pmdata->command ) { + default: + /* wait until PM is free */ + pm_cmd = (u_char)(pmdata->command & 0xff); + rval = 0xcd38; + if (pm_wait_free( ADBDelay * 4 ) == 0) + break; /* timeout */ + + if (HwCfgFlags3 & 0x00200000) { /* PB 160, PB 165(c), PB 180(c) ? */ + int delay = ADBDelay * 16; + + via_reg(VIA2, vDirA) = 0x00; + while((via_reg(VIA2, 0x200) == 0x07) && (delay >= 0)) + delay--; + + if (delay < 0) { + rval = 0xffffcd38; + break; /* timeout */ + } + } + + /* send PM command */ + if ((rval = pm_send_pm2( (u_char)(pm_cmd & 0xff) ))) + break; /* timeout */ + + /* send number of PM data */ + num_pm_data = pmdata->num_data; + if (HwCfgFlags3 & 0x00020000) { /* PB Duo, PB 5XX */ + if (pm_send_cmd_type[pm_cmd] < 0) { + if ((rval = pm_send_pm2( (u_char)(num_pm_data & 0xff) )) != 0) + break; /* timeout */ + pmdata->command = 0; + } + } else { /* PB 1XX series ? */ + if ((rval = pm_send_pm2( (u_char)(num_pm_data & 0xff) )) != 0) + break; /* timeout */ + } + /* send PM data */ + pm_buf = (u_char *)pmdata->s_buf; + for( i=0; i<num_pm_data; i++ ) + if((rval = pm_send_pm2( pm_buf[i] )) != 0) + break; /* timeout */ + if (i != num_pm_data) + break; /* timeout */ + + + /* check if PM will send me data */ + pm_num_rx_data = pm_receive_cmd_type[pm_cmd]; + pmdata->num_data = pm_num_rx_data; + if (pm_num_rx_data == 0) { + rval = 0; + break; /* no return data */ + } + + /* receive PM command */ + pm_data = pmdata->command; + if (HwCfgFlags3 & 0x00020000) { /* PB Duo, PB 5XX */ + pm_num_rx_data--; + if (pm_num_rx_data == 0) + if ((rval = pm_receive_pm2( &pm_data )) != 0) { + rval = 0xffffcd37; + break; + } + pmdata->command = pm_data; + } else { /* PB 1XX series ? */ + if ((rval = pm_receive_pm2( &pm_data )) != 0) { + rval = 0xffffcd37; + break; + } + pmdata->command = pm_data; + } + + /* receive number of PM data */ + if (HwCfgFlags3 & 0x00020000) { /* PB Duo, PB 5XX */ + if (pm_num_rx_data < 0) { + if ((rval = pm_receive_pm2( &pm_data )) != 0) + break; /* timeout */ + num_pm_data = pm_data; + } else + num_pm_data = pm_num_rx_data; + pmdata->num_data = num_pm_data; + } else { /* PB 1XX serias ? */ + if ((rval = pm_receive_pm2( &pm_data )) != 0) + break; /* timeout */ + num_pm_data = pm_data; + pmdata->num_data = num_pm_data; + } + + /* receive PM data */ + pm_buf = (u_char *)pmdata->r_buf; + for( i=0; i<num_pm_data; i++ ) { + if ((rval = pm_receive_pm2( &pm_data )) != 0) + break; /* timeout */ + pm_buf[i] = pm_data; + } + + rval = 0; + } + + /* restore former value */ + via_reg(VIA1, vIER) = via1_vIER; + splx(s); + + return( rval ); +} + + +/* + * My PM interrupt routine for the PB Duo series and the PB 5XX series + */ +void +pm_intr_pm2(void) +{ + int s; + int rval; + PMData pmdata; + + s = splhigh(); + + PM_VIA_CLR_INTR(); /* clear VIA1 interrupt */ + /* ask PM what happend */ + pmdata.command = 0x78; + pmdata.num_data = 0; + pmdata.s_buf = &pmdata.data[2]; + pmdata.r_buf = &pmdata.data[2]; + rval = pm_pmgrop_pm2( &pmdata ); + if (rval != 0) { +#ifdef PM_DEBUG + printf( "pm: PM is not ready. error code: %08x\n", rval ); +#endif + splx(s); + } + + switch( (u_int)(pmdata.data[2] & 0xff) ) { + case 0x00: /* 1 sec interrupt? */ + { + break; + } + case 0x80: /* 1 sec interrupt? */ + { + pm_counter++; + break; + } + case 0x08: /* Brightness/Contrast button on LCD panel */ + { + /* get brightness and contrast of the LCD */ + pm_LCD_brightness = (u_int)pmdata.data[3] & 0xff; + pm_LCD_contrast = (u_int)pmdata.data[4] & 0xff; +/* + pm_printerr( "#08", rval, pmdata.num_data, pmdata.data ); + pmdata.command = 0x33; + pmdata.num_data = 1; + pmdata.s_buf = pmdata.data; + pmdata.r_buf = pmdata.data; + pmdata.data[0] = pm_LCD_contrast; + rval = pm_pmgrop_pm2( &pmdata ); + pm_printerr( "#33", rval, pmdata.num_data, pmdata.data ); +*/ + /* this is an experimental code */ + pmdata.command = 0x41; + pmdata.num_data = 1; + pmdata.s_buf = pmdata.data; + pmdata.r_buf = pmdata.data; + pm_LCD_brightness = 0x7f - pm_LCD_brightness / 2; + if (pm_LCD_brightness < 0x25) pm_LCD_brightness = 0x25; + if (pm_LCD_brightness > 0x5a) pm_LCD_brightness = 0x7f; + pmdata.data[0] = pm_LCD_brightness; + rval = pm_pmgrop_pm2( &pmdata ); + break; + } + /* ADB data that were requested by TALK command */ + case 0x10: + case 0x14: + pm_adb_get_TALK_result(&pmdata); + break; + /* ADB device event */ + case 0x16: + case 0x18: + case 0x1e: + pm_adb_get_ADB_data(&pmdata); + break; + default: + { +#ifdef PM_DEBUG + pm_printerr( "driver does not supported this event.", pmdata.data[2], pmdata.num_data, pmdata.data ); +#endif + } + break; + } + + splx(s); +} + + +/* + * MRG-based PMgrOp routine + */ +int +pm_pmgrop_mrg(pmdata) + PMData *pmdata; +{ + u_int32_t rval=0; + + asm(" + movl %1, a0 + .word 0xa085 + movl d0, %0" + : "=g" (rval) + : "g" (pmdata) + : "a0", "d0" ); + + return rval; +} + + +/* + * My PMgrOp routine + */ +int +pmgrop(pmdata) + PMData *pmdata; +{ + switch( pmHardware ) { + case PM_HW_PB1XX: + { + return( pm_pmgrop_pm1(pmdata) ); + break; + } + case PM_HW_PB5XX: + { + return( pm_pmgrop_pm2(pmdata) ); + break; + } + default: +/* return( pmgrop_mrg(pmdata) ); */ + return( -1 ); + } +} + + +/* + * My PM interrupt routine + */ +void +pm_intr(void) +{ + switch( pmHardware ) { + case PM_HW_PB1XX: + { + pm_intr_pm1(); + break; + } + case PM_HW_PB5XX: + { + pm_intr_pm2(); + break; + } + default: + break; + } +} + + + +/* + * Synchronous ADBOp routine for the Power Manager + */ +int +pm_adb_op(buffer, compRout, data, command) + u_char *buffer; + void *compRout; + void *data; + int command; +{ + int i,len; + int s; + int rval; + int delay; + PMData pmdata; + + if (adbWaiting == 1) + return( -1 ); + + s = splhigh(); + via_reg(VIA1, vIER) = 0x10; + + adbBuffer = buffer; + adbCompRout = compRout; + adbCompData = data; + + pmdata.command = 0x20; + pmdata.s_buf = pmdata.data; + pmdata.r_buf = pmdata.data; + + if ((command & 0xc) == 0x8) { /* if the command is LISTEN, add number of ADB data to number of PM data */ + if (buffer != (u_char *)0) + pmdata.num_data = buffer[0] + 3; + } else { + pmdata.num_data = 3; + } + + pmdata.data[0] = (u_char)(command & 0xff); + pmdata.data[1] = 0; + if ((command & 0xc) == 0x8) { /* if the command is LISTEN, copy ADB data to PM buffer */ + if ((buffer != (u_char *)0) && (buffer[0] <= 24)) { + pmdata.data[2] = buffer[0]; /* number of data */ + for( i=0; i<buffer[0]; i++ ) + pmdata.data[3 + i] = buffer[1 + i]; + } else + pmdata.data[2] = 0; + } else + pmdata.data[2] = 0; + + rval = pmgrop( &pmdata ); + if (rval != 0) + return( -1 ); + + if (adbWaiting == 0) { + adbWaiting = 1; + adbWaitingCmd = command; + } + + PM_VIA_INTR_ENABLE(); + + /* wait until the PM interrupt is occured */ + delay = 0x80000; + while(adbWaiting == 1) { + if ((via_reg(VIA1, vIFR) & 0x10) == 0x10) + pm_intr(); +#ifdef PM_GRAB_SI + zshard(0); /* grab any serial interrupts */ +#endif + if ((--delay) < 0) + return( -1 ); + } + + if (buffer != (u_char *)0) { + len = adbInputBuffer[3]; + for (i=0; i<=len; i++) + buffer[i] = adbInputBuffer[3 + i]; + if (len < 0) + buffer[0] = 0; + } + + /* this command enables the interrupt by operating ADB devices */ + if (HwCfgFlags3 & 0x00020000) { /* PB Duo series, PB 500 series */ + pmdata.command = 0x20; + pmdata.num_data = 4; + pmdata.s_buf = pmdata.data; + pmdata.r_buf = pmdata.data; + pmdata.data[0] = 0x00; + pmdata.data[1] = 0x86; /* magic spell for awaking the PM */ + pmdata.data[2] = 0x00; + pmdata.data[3] = 0x0c; /* each bit may express the existent ADB device */ + } else { /* PB 100-series */ + pmdata.command = 0x20; + pmdata.num_data = 3; + pmdata.s_buf = pmdata.data; + pmdata.r_buf = pmdata.data; + pmdata.data[0] = (u_char)(command & 0xf0) | 0xc; + pmdata.data[1] = 0x04; + pmdata.data[2] = 0x00; + } + rval = pmgrop( &pmdata ); + + splx(s); + return( rval ); +} + + +void +pm_adb_get_TALK_result(pmdata) + PMData *pmdata; +{ + int i; + int rx_pm_adb_cmd; + + rx_pm_adb_cmd = (u_int)pmdata->data[3] & 0xff; + + pmdata->data[2] &= 0xf; + pmdata->data[1] = pmdata->data[3]; + pmdata->data[3] = pmdata->num_data - 2; + + adbInputBuffer[0] = pmdata->num_data + 1; + for( i=1; i<pmdata->num_data+2; i++ ) + adbInputBuffer[i] = pmdata->data[i]; + + if ((adbWaiting == 1) && (rx_pm_adb_cmd == adbWaitingCmd)) { + if (adbStarting == 0) + adb_complete( &pmdata->data[3] , (long)0, adbWaitingCmd ); + adbWaitingCmd = 0x0; + + adbWaiting = 0; + adb_comp_exec(); + adbBuffer = (long)0; + adbCompRout = (long)0; + adbCompData = (long)0; + } +} + + +void +pm_adb_get_ADB_data(pmdata) + PMData *pmdata; +{ + int i; + + i = (u_int)pmdata->data[3] & 0xff; + pmdata->data[2] &= 0xf; + pmdata->data[1] = pmdata->data[3]; + pmdata->data[3] = pmdata->num_data - 2; + + adbInputBuffer[0] = pmdata->num_data + 1; + if (adbStarting == 0) + adb_complete( &pmdata->data[3] , (long)0, i ); +} + + +void +pm_adb_poll_next_device_pm1(pmdata) + PMData *pmdata; +{ + int i; + int ndid; + u_short bendid = 0x1; + int rval; + PMData tmp_pmdata; + + /* find another existent ADB device to poll */ + for( i=1; i<16; i++ ) { + ndid = (((pmdata->data[3] & 0xf0) >> 4) + i) & 0xf; + bendid <<= ndid; + if ((pm_existent_ADB_devices & bendid) != 0) + break; + } + + /* poll the other device */ + tmp_pmdata.command = 0x20; + tmp_pmdata.num_data = 3; + tmp_pmdata.s_buf = tmp_pmdata.data; + tmp_pmdata.r_buf = tmp_pmdata.data; + tmp_pmdata.data[0] = (u_char)(ndid << 4) | 0xc; + tmp_pmdata.data[1] = 0x04; /* magic spell for awaking the PM */ + tmp_pmdata.data[2] = 0x00; + rval = pmgrop( &tmp_pmdata ); +} + + diff --git a/sys/arch/mac68k/dev/pm_direct.h b/sys/arch/mac68k/dev/pm_direct.h new file mode 100644 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 <vm/vm_page.h> #include <dev/cons.h> +#include <arch/mac68k/mac68k/macrom.h> +#include <arch/mac68k/dev/adbvar.h> #include <machine/viareg.h> -#include "macrom.h" #include "ether.h" /* The following is used externally (sysctl_hw) */ 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 <sys/systm.h> #endif +#include <sys/param.h> + #include <machine/viareg.h> -#include "pram.h" -#include "macrom.h" + +#include <arch/mac68k/mac68k/pram.h> +#include <arch/mac68k/mac68k/macrom.h> +#ifdef HWDIRECT +#include <arch/mac68k/dev/adbvar.h> +#endif #if DEBUG static char *convtime(unsigned long t) @@ -146,3 +152,71 @@ pram_settime(unsigned long time) else return setPramTime(time); } + +#ifdef HWDIRECT /* These routines are defined here only + * when the HWDIRECT method for accessing + * the ADB/PRAM/RTC is enabled. */ + +extern int adbHardware; /* from newadb.c */ + +/* + * getPramTime + * This function can be called regrardless of the machine + * type. It calls the correct hardware-specific code. + * (It's sort of redundant with the above, but it was + * added later.) + */ +unsigned long +getPramTime(void) +{ + unsigned long time; + + switch (adbHardware) { + case ADB_HW_II: /* access PRAM via VIA interface */ + time=(long)getPramTimeII(); + return time; + + case ADB_HW_IISI: /* access PRAM via pseudo-adb functions */ + if (0 != adb_read_date_time(&time)) + return 0; + else + return time; + + case ADB_HW_PB: /* don't know how to access this yet */ + return 0; + + case ADB_HW_UNKNOWN: + default: + return 0; + } +} + +/* + * setPramTime + * This function can be called regrardless of the machine + * type. It calls the correct hardware-specific code. + * (It's sort of redundant with the above, but it was + * added later.) + */ +void +setPramTime(unsigned long time) +{ + switch (adbHardware) { + case ADB_HW_II: /* access PRAM via ADB interface */ + setPramTimeII(time); + return; + + case ADB_HW_IISI: /* access PRAM via pseudo-adb functions */ + adb_set_date_time(time); + return; + + case ADB_HW_PB: /* don't know how to access this yet */ + return; + + case ADB_HW_UNKNOWN: + return; + } + +} + +#endif /* ifdef HWDIRECT */ 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 */ + |