diff options
author | Dale S. Rahn <rahnds@cvs.openbsd.org> | 2000-09-06 02:07:19 +0000 |
---|---|---|
committer | Dale S. Rahn <rahnds@cvs.openbsd.org> | 2000-09-06 02:07:19 +0000 |
commit | cf23170bf45f36b80f9f300b134ae61595b92820 (patch) | |
tree | 0b0526996c3c2ab011e3e44bce73e55aceae97ab /sys/arch/powerpc | |
parent | ff7dba6e0e2f300b2e4a0f5c95369a0cbc08504d (diff) |
Add adb support, no devices attached to adb supported yet, but it
is used to power-off and reboot newer machines (that claim to not have adb).
Diffstat (limited to 'sys/arch/powerpc')
-rw-r--r-- | sys/arch/powerpc/mac/adb.c | 246 | ||||
-rw-r--r-- | sys/arch/powerpc/mac/adb_direct.c | 2173 | ||||
-rw-r--r-- | sys/arch/powerpc/mac/adb_direct.h | 53 | ||||
-rw-r--r-- | sys/arch/powerpc/mac/adbvar.h | 129 | ||||
-rw-r--r-- | sys/arch/powerpc/mac/akbdvar.h | 60 | ||||
-rw-r--r-- | sys/arch/powerpc/mac/pm_direct.c | 1308 | ||||
-rw-r--r-- | sys/arch/powerpc/mac/pm_direct.h | 75 | ||||
-rw-r--r-- | sys/arch/powerpc/mac/viareg.h | 250 |
8 files changed, 4294 insertions, 0 deletions
diff --git a/sys/arch/powerpc/mac/adb.c b/sys/arch/powerpc/mac/adb.c new file mode 100644 index 00000000000..ae507bb84dd --- /dev/null +++ b/sys/arch/powerpc/mac/adb.c @@ -0,0 +1,246 @@ +/* $NetBSD: adb.c,v 1.6 1999/08/16 06:28:09 tsubai Exp $ */ + +/*- + * Copyright (C) 1994 Bradley A. Grantham + * 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 Bradley A. Grantham. + * 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. + */ + +#include <sys/param.h> +#include <sys/device.h> +#include <sys/fcntl.h> +#include <sys/poll.h> +#include <sys/select.h> +#include <sys/proc.h> +#include <sys/signalvar.h> +#include <sys/systm.h> + +#include <machine/autoconf.h> + +#include <powerpc/mac/adbvar.h> +#include <powerpc/mac/akbdvar.h> +#include <powerpc/mac/viareg.h> + +#include "aed.h" + +/* + * Function declarations. + */ +static int adbmatch __P((struct device *, void *, void *)); +static void adbattach __P((struct device *, struct device *, void *)); +static int adbprint __P((void *, const char *)); + +/* + * Global variables. + */ +int adb_polling = 0; /* Are we polling? (Debugger mode) */ +int adb_initted = 0; /* adb_init() has completed successfully */ +#ifdef ADB_DEBUG +int adb_debug = 0; /* Output debugging messages */ +#endif /* ADB_DEBUG */ + +/* + * Driver definition. + */ +struct cfattach adb_ca = { + sizeof(struct adb_softc), adbmatch, adbattach +}; +struct cfdriver adb_cd = { + NULL, "adb", DV_DULL +}; + +extern int adbHardware; + +static int +adbmatch(parent, cf, aux) + struct device *parent; + void *cf; + void *aux; +{ + struct confargs *ca = aux; + + if (ca->ca_nreg < 8) + return 0; + + if (ca->ca_nintr < 4) + return 0; + + if (strcmp(ca->ca_name, "via-cuda") == 0) + return 1; + + if (strcmp(ca->ca_name, "via-pmu") == 0) + return 1; + + return 0; +} + +static void +adbattach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + struct adb_softc *sc = (struct adb_softc *)self; + struct confargs *ca = aux; + + ADBDataBlock adbdata; + struct adb_attach_args aa_args; + int totaladbs; + int adbindex, adbaddr; + + extern adb_intr(); + extern volatile u_char *Via1Base; + + ca->ca_reg[0] += ca->ca_baseaddr; + + sc->sc_regbase = mapiodev(ca->ca_reg[0], ca->ca_reg[1]); + Via1Base = sc->sc_regbase; + + if (strcmp(ca->ca_name, "via-cuda") == 0) + adbHardware = ADB_HW_CUDA; + else if (strcmp(ca->ca_name, "via-pmu") == 0) + adbHardware = ADB_HW_PB; + + adb_polling = 1; + ADBReInit(); + + mac_intr_establish(NULL, ca->ca_intr[0], IST_LEVEL, IPL_HIGH, + adb_intr, sc, "adb"); + +#ifdef ADB_DEBUG + if (adb_debug) + printf("adb: done with ADBReInit\n"); +#endif + totaladbs = CountADBs(); + + printf(" irq %d", ca->ca_intr[0]); + printf(": %d targets\n", totaladbs); + +#if NAED > 0 + /* ADB event device for compatibility */ + aa_args.origaddr = 0; + aa_args.adbaddr = 0; + aa_args.handler_id = 0; + (void)config_found(self, &aa_args, adbprint); +#endif + + /* for each ADB device */ + for (adbindex = 1; adbindex <= totaladbs; adbindex++) { + /* Get the ADB information */ + adbaddr = GetIndADB(&adbdata, adbindex); + + aa_args.origaddr = adbdata.origADBAddr; + aa_args.adbaddr = adbaddr; + aa_args.handler_id = adbdata.devType; + + (void)config_found(self, &aa_args, adbprint); + } + + if (adbHardware == ADB_HW_CUDA) + adb_cuda_autopoll(); + adb_polling = 0; +} + +int +adbprint(args, name) + void *args; + const char *name; +{ + struct adb_attach_args *aa_args = (struct adb_attach_args *)args; + int rv = UNCONF; + + if (name) { /* no configured device matched */ + rv = UNSUPP; /* most ADB device types are unsupported */ + + /* print out what kind of ADB device we have found */ + printf("%s addr %d: ", name, aa_args->origaddr); + switch(aa_args->origaddr) { +#ifdef DIAGNOSTIC + case 0: + printf("ADB event device"); + rv = UNCONF; + break; + case ADBADDR_SECURE: + printf("security dongle (%d)", aa_args->handler_id); + break; +#endif + case ADBADDR_MAP: + printf("mapped device (%d)", aa_args->handler_id); + rv = UNCONF; + break; + case ADBADDR_REL: + printf("relative positioning device (%d)", + aa_args->handler_id); + rv = UNCONF; + break; +#ifdef DIAGNOSTIC + case ADBADDR_ABS: + switch (aa_args->handler_id) { + case ADB_ARTPAD: + printf("WACOM ArtPad II"); + break; + default: + printf("absolute positioning device (%d)", + aa_args->handler_id); + break; + } + break; + case ADBADDR_DATATX: + printf("data transfer device (modem?) (%d)", + aa_args->handler_id); + break; + case ADBADDR_MISC: + switch (aa_args->handler_id) { + case ADB_POWERKEY: + printf("Sophisticated Circuits PowerKey"); + break; + default: + printf("misc. device (remote control?) (%d)", + aa_args->handler_id); + break; + } + break; + default: + printf("unknown type device, (handler %d)", + aa_args->handler_id); + break; +#endif /* DIAGNOSTIC */ + } + } else /* a device matched and was configured */ + printf(" addr %d: ", aa_args->origaddr); + + return (rv); +} + +void +extdms_complete(buffer, compdata, cmd) + caddr_t buffer, compdata; + int cmd; +{ + long *p = (long *)compdata; + + *p= -1; +} diff --git a/sys/arch/powerpc/mac/adb_direct.c b/sys/arch/powerpc/mac/adb_direct.c new file mode 100644 index 00000000000..ae89bd6d551 --- /dev/null +++ b/sys/arch/powerpc/mac/adb_direct.c @@ -0,0 +1,2173 @@ +/* $NetBSD: adb_direct.c,v 1.14 2000/06/08 22:10:45 tsubai Exp $ */ + +/* From: adb_direct.c 2.02 4/18/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 + */ + +/* + * TO DO: + * - We could reduce the time spent in the adb_intr_* routines + * by having them save the incoming and outgoing data directly + * in the adbInbound and adbOutbound queues, as it would reduce + * the number of times we need to copy the data around. It + * would also make the code more readable and easier to follow. + * - (Related to above) Use the header part of adbCommand to + * reduce the number of copies we have to do of the data. + * - (Related to above) Actually implement the adbOutbound queue. + * This is fairly easy once you switch all the intr routines + * over to using adbCommand structs directly. + * - There is a bug in the state machine of adb_intr_cuda + * code that causes hangs, especially on 030 machines, probably + * because of some timing issues. Because I have been unable to + * determine the exact cause of this bug, I used the timeout function + * to check for and recover from this condition. If anyone finds + * the actual cause of this bug, the calls to timeout and the + * adb_cuda_tickle routine can be removed. + */ + +#include <sys/param.h> +#include <sys/cdefs.h> +#include <sys/systm.h> +#include <sys/timeout.h> +#include <sys/device.h> + +#include <machine/param.h> +#include <machine/cpu.h> +#include <machine/adbsys.h> + +#include <powerpc/mac/viareg.h> +#include <powerpc/mac/adbvar.h> + +#define printf_intr printf + +#ifdef DEBUG +#ifndef ADB_DEBUG +#define ADB_DEBUG +#endif +#endif + +/* some misc. leftovers */ +#define vPB 0x0000 +#define vPB3 0x08 +#define vPB4 0x10 +#define vPB5 0x20 +#define vSR_INT 0x04 +#define vSR_OUT 0x10 + +/* the type of ADB action that we are currently preforming */ +#define ADB_ACTION_NOTREADY 0x1 /* has not been initialized yet */ +#define ADB_ACTION_IDLE 0x2 /* the bus is currently idle */ +#define ADB_ACTION_OUT 0x3 /* sending out a command */ +#define ADB_ACTION_IN 0x4 /* receiving data */ +#define ADB_ACTION_POLLING 0x5 /* polling - II only */ + +/* + * 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 0x1 /* we don't know yet - all models */ +#define ADB_BUS_IDLE 0x2 /* bus is idle - all models */ +#define ADB_BUS_CMD 0x3 /* starting a command - II models */ +#define ADB_BUS_ODD 0x4 /* the "odd" state - II models */ +#define ADB_BUS_EVEN 0x5 /* the "even" state - II models */ +#define ADB_BUS_ACTIVE 0x6 /* active state - IIsi models */ +#define ADB_BUS_ACK 0x7 /* 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_or(VIA1, vBufB, (vPB4 | vPB5)) +#define ADB_SET_STATE_IDLE_IISI() via_reg_and(VIA1, vBufB, ~(vPB4 | vPB5)) +#define ADB_SET_STATE_IDLE_CUDA() via_reg_or(VIA1, vBufB, (vPB4 | vPB5)) +#define ADB_SET_STATE_CMD() via_reg_and(VIA1, vBufB, ~(vPB4 | vPB5)) +#define ADB_SET_STATE_EVEN() write_via_reg(VIA1, vBufB, \ + (read_via_reg(VIA1, vBufB) | vPB4) & ~vPB5) +#define ADB_SET_STATE_ODD() write_via_reg(VIA1, vBufB, \ + (read_via_reg(VIA1, vBufB) | vPB5) & ~vPB4 ) +#define ADB_SET_STATE_ACTIVE() via_reg_or(VIA1, vBufB, vPB5) +#define ADB_SET_STATE_INACTIVE() via_reg_and(VIA1, vBufB, ~vPB5) +#define ADB_SET_STATE_TIP() via_reg_and(VIA1, vBufB, ~vPB5) +#define ADB_CLR_STATE_TIP() via_reg_or(VIA1, vBufB, vPB5) +#define ADB_SET_STATE_ACKON() via_reg_or(VIA1, vBufB, vPB4) +#define ADB_SET_STATE_ACKOFF() via_reg_and(VIA1, vBufB, ~vPB4) +#define ADB_TOGGLE_STATE_ACK_CUDA() via_reg_xor(VIA1, vBufB, vPB4) +#define ADB_SET_STATE_ACKON_CUDA() via_reg_and(VIA1, vBufB, ~vPB4) +#define ADB_SET_STATE_ACKOFF_CUDA() via_reg_or(VIA1, vBufB, vPB4) +#define ADB_SET_SR_INPUT() via_reg_and(VIA1, vACR, ~vSR_OUT) +#define ADB_SET_SR_OUTPUT() via_reg_or(VIA1, vACR, vSR_OUT) +#define ADB_SR() read_via_reg(VIA1, vSR) +#define ADB_VIA_INTR_ENABLE() write_via_reg(VIA1, vIER, 0x84) +#define ADB_VIA_INTR_DISABLE() write_via_reg(VIA1, vIER, 0x04) +#define ADB_VIA_CLR_INTR() write_via_reg(VIA1, vIFR, 0x04) +#define ADB_INTR_IS_OFF (vPB3 == (read_via_reg(VIA1, vBufB) & vPB3)) +#define ADB_INTR_IS_ON (0 == (read_via_reg(VIA1, vBufB) & vPB3)) +#define ADB_SR_INTR_IS_OFF (0 == (read_via_reg(VIA1, vIFR) & vSR_INT)) +#define ADB_SR_INTR_IS_ON (vSR_INT == (read_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_DELAY 150 + +/* + * Maximum ADB message length; includes space for data, result, and + * device code - plus a little for safety. + */ +#define ADB_MAX_MSG_LENGTH 16 +#define ADB_MAX_HDR_LENGTH 8 + +#define ADB_QUEUE 32 +#define ADB_TICKLE_TICKS 4 + +/* + * A structure for storing information about each ADB device. + */ +struct ADBDevEntry { + void (*ServiceRtPtr) __P((void)); + void *DataAreaAddr; + int devType; + int origAddr; + int currentAddr; +}; + +/* + * Used to hold ADB commands that are waiting to be sent out. + */ +struct adbCmdHoldEntry { + u_char outBuf[ADB_MAX_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 */ +}; + +/* + * Eventually used for two separate queues, the queue between + * the upper and lower halves, and the outgoing packet queue. + * TO DO: adbCommand can replace all of adbCmdHoldEntry eventually + */ +struct adbCommand { + u_char header[ADB_MAX_HDR_LENGTH]; /* not used yet */ + u_char data[ADB_MAX_MSG_LENGTH]; /* packet data only */ + u_char *saveBuf; /* where to save result */ + u_char *compRout; /* completion routine pointer */ + u_char *compData; /* completion routine data pointer */ + u_int cmd; /* the original command for this data */ + u_int unsol; /* 1 if packet was unsolicited */ + u_int ack_only; /* 1 for no special processing */ +}; + +/* + * 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 adbSoftPower = 0; /* machine supports soft power */ + +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 = 1; /* doing ADBReInit 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[ADB_MAX_MSG_LENGTH]; /* data input buffer */ +u_char adbOutputBuffer[ADB_MAX_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 dev we heard from (II ONLY) */ +int adbLastDevIndex = 0; /* last ADB dev loc in dev table (II ONLY) */ +int adbLastCommand = 0; /* the last ADB command we sent (II) */ + +struct ADBDevEntry ADBDevTable[16]; /* our ADB device table */ +int ADBNumDevices; /* num. of ADB devices found with ADBReInit */ + +struct adbCommand adbInbound[ADB_QUEUE]; /* incoming queue */ +int adbInCount = 0; /* how many packets in in queue */ +int adbInHead = 0; /* head of in queue */ +int adbInTail = 0; /* tail of in queue */ +struct adbCommand adbOutbound[ADB_QUEUE]; /* outgoing queue - not used yet */ +int adbOutCount = 0; /* how many packets in out queue */ +int adbOutHead = 0; /* head of out queue */ +int adbOutTail = 0; /* tail of out queue */ + +int tickle_count = 0; /* how many tickles seen for this packet? */ +int tickle_serial = 0; /* the last packet tickled */ +int adb_cuda_serial = 0; /* the current packet */ + +volatile u_char *Via1Base; +extern int adb_polling; /* Are we polling? */ + +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)); +void pm_init_adb_device __P((void)); + +/* + * The following are private routines. + */ +#ifdef ADB_DEBUG +void print_single __P((u_char *)); +#endif +void adb_intr __P((void)); +void adb_intr_II __P((void)); +void adb_intr_IIsi __P((void)); +void adb_intr_cuda __P((void)); +void adb_soft_intr __P((void)); +int send_adb_II __P((u_char *, u_char *, void *, void *, int)); +int send_adb_IIsi __P((u_char *, u_char *, void *, void *, int)); +int send_adb_cuda __P((u_char *, u_char *, void *, void *, int)); +void adb_intr_cuda_test __P((void)); +void adb_cuda_tickle __P((void)); +void adb_pass_up __P((struct adbCommand *)); +void adb_op_comprout __P((caddr_t, caddr_t, int)); +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)); +int adb_op_sync __P((Ptr, Ptr, Ptr, short)); +void adb_read_II __P((u_char *)); +void adb_hw_setup __P((void)); +void adb_hw_setup_IIsi __P((u_char *)); +void adb_comp_exec __P((void)); +int adb_cmd_result __P((u_char *)); +int adb_cmd_extra __P((u_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((u_char *, void *, void *)); + +#ifdef ADB_DEBUG +/* + * 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(str) + u_char *str; +{ + int x; + + if (str == 0) { + printf_intr("no data - null pointer\n"); + return; + } + if (*str == 0) { + printf_intr("nothing returned\n"); + return; + } + if (*str > 20) { + printf_intr("ADB: ACK > 20 no way!\n"); + *str = 20; + } + printf_intr("(length=0x%x):", *str); + for (x = 1; x <= *str; x++) + printf_intr(" 0x%02x", str[x]); + printf_intr("\n"); +} +#endif + +void +adb_cuda_tickle(void) +{ + volatile int s; + + if (adbActionState == ADB_ACTION_IN) { + if (tickle_serial == adb_cuda_serial) { + if (++tickle_count > 0) { + s = splhigh(); + adbActionState = ADB_ACTION_IDLE; + adbInputBuffer[0] = 0; + ADB_SET_STATE_IDLE_CUDA(); + splx(s); + } + } else { + tickle_serial = adb_cuda_serial; + tickle_count = 0; + } + } else { + tickle_serial = adb_cuda_serial; + tickle_count = 0; + } + + timeout((void *)adb_cuda_tickle, 0, ADB_TICKLE_TICKS); +} + +/* + * called when when an adb interrupt happens + * + * Cuda version of adb_intr + * TO DO: do we want to add some calls to intr_dispatch() here to + * grab serial interrupts? + */ +void +adb_intr_cuda(void) +{ + volatile int i, ending; + volatile unsigned int s; + struct adbCommand packet; + + 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: + /* + * This is an unexpected packet, so grab the first (dummy) + * byte, set up the proper vars, and tell the chip we are + * starting to receive the packet by setting the TIP bit. + */ + adbInputBuffer[1] = ADB_SR(); + adb_cuda_serial++; + if (ADB_INTR_IS_OFF) /* must have been a fake start */ + break; + + ADB_SET_SR_INPUT(); + ADB_SET_STATE_TIP(); + + adbInputBuffer[0] = 1; + adbActionState = ADB_ACTION_IN; +#ifdef ADB_DEBUG + if (adb_debug) + printf_intr("idle 0x%02x ", adbInputBuffer[1]); +#endif + break; + + case ADB_ACTION_IN: + adbInputBuffer[++adbInputBuffer[0]] = ADB_SR(); + /* intr off means this is the last byte (end of frame) */ + if (ADB_INTR_IS_OFF) + ending = 1; + else + ending = 0; + + if (1 == ending) { /* end of message? */ +#ifdef ADB_DEBUG + if (adb_debug) { + printf_intr("in end 0x%02x ", + adbInputBuffer[adbInputBuffer[0]]); + print_single(adbInputBuffer); + } +#endif + + /* + * Are we waiting AND does this packet match what we + * are waiting for AND is it coming from either the + * ADB or RTC/PRAM sub-device? This section _should_ + * recognize all ADB and RTC/PRAM type commands, but + * there may be more... NOTE: commands are always at + * [4], even for RTC/PRAM commands. + */ + /* set up data for adb_pass_up */ + memcpy(packet.data, adbInputBuffer, adbInputBuffer[0] + 1); + + if ((adbWaiting == 1) && + (adbInputBuffer[4] == adbWaitingCmd) && + ((adbInputBuffer[2] == 0x00) || + (adbInputBuffer[2] == 0x01))) { + packet.saveBuf = adbBuffer; + packet.compRout = adbCompRout; + packet.compData = adbCompData; + packet.unsol = 0; + packet.ack_only = 0; + adb_pass_up(&packet); + + adbWaitingCmd = 0; /* reset "waiting" vars */ + adbWaiting = 0; + adbBuffer = (long)0; + adbCompRout = (long)0; + adbCompData = (long)0; + } else { + packet.unsol = 1; + packet.ack_only = 0; + adb_pass_up(&packet); + } + + + /* reset vars and signal the end of this frame */ + adbActionState = ADB_ACTION_IDLE; + adbInputBuffer[0] = 0; + ADB_SET_STATE_IDLE_CUDA(); + /*ADB_SET_SR_INPUT();*/ + + /* + * If there is something waiting to be sent out, + * the set everything up and send the first byte. + */ + if (adbWriteDelay == 1) { + delay(ADB_DELAY); /* required */ + adbSentChars = 0; + adbActionState = ADB_ACTION_OUT; + /* + * If the interrupt is on, we were too slow + * and the chip has already started to send + * something to us, so back out of the write + * and start a read cycle. + */ + if (ADB_INTR_IS_ON) { + ADB_SET_SR_INPUT(); + ADB_SET_STATE_IDLE_CUDA(); + adbSentChars = 0; + adbActionState = ADB_ACTION_IDLE; + adbInputBuffer[0] = 0; + break; + } + /* + * If we got here, it's ok to start sending + * so load the first byte and tell the chip + * we want to send. + */ + ADB_SET_STATE_TIP(); + ADB_SET_SR_OUTPUT(); + write_via_reg(VIA1, vSR, adbOutputBuffer[adbSentChars + 1]); + } + } else { + ADB_TOGGLE_STATE_ACK_CUDA(); +#ifdef ADB_DEBUG + if (adb_debug) + printf_intr("in 0x%02x ", + adbInputBuffer[adbInputBuffer[0]]); +#endif + } + break; + + case ADB_ACTION_OUT: + i = ADB_SR(); /* reset SR-intr in IFR */ +#ifdef ADB_DEBUG + if (adb_debug) + printf_intr("intr out 0x%02x ", i); +#endif + + adbSentChars++; + if (ADB_INTR_IS_ON) { /* ADB intr low during write */ +#ifdef ADB_DEBUG + if (adb_debug) + printf_intr("intr was on "); +#endif + ADB_SET_SR_INPUT(); /* make sure SR is set to IN */ + ADB_SET_STATE_IDLE_CUDA(); + 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_DELAY); + 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 */ + /* set up stuff for adb_pass_up */ + memcpy(packet.data, adbInputBuffer, adbInputBuffer[0] + 1); + packet.saveBuf = adbBuffer; + packet.compRout = adbCompRout; + packet.compData = adbCompData; + packet.cmd = adbWaitingCmd; + packet.unsol = 0; + packet.ack_only = 1; + adb_pass_up(&packet); + + /* reset "waiting" vars, just in case */ + adbWaitingCmd = 0; + 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(); + ADB_SET_STATE_IDLE_CUDA(); +#ifdef ADB_DEBUG + if (adb_debug) + printf_intr("write done "); +#endif + } else { + write_via_reg(VIA1, vSR, adbOutputBuffer[adbSentChars + 1]); /* send next byte */ + ADB_TOGGLE_STATE_ACK_CUDA(); /* signal byte ready to + * shift */ +#ifdef ADB_DEBUG + if (adb_debug) + printf_intr("toggle "); +#endif + } + break; + + case ADB_ACTION_NOTREADY: +#ifdef ADB_DEBUG + if (adb_debug) + printf_intr("adb: not yet initialized\n"); +#endif + break; + + default: +#ifdef ADB_DEBUG + if (adb_debug) + printf_intr("intr: unknown ADB state\n"); +#endif + } + + ADB_VIA_INTR_ENABLE(); /* enable ADB interrupt on IIs. */ + + splx(s); /* restore */ + + return; +} /* end adb_intr_cuda */ + + +int +send_adb_cuda(u_char * in, u_char * buffer, void *compRout, void *data, int + command) +{ + int s, len; + +#ifdef ADB_DEBUG + if (adb_debug) + printf_intr("SEND\n"); +#endif + + if (adbActionState == ADB_ACTION_NOTREADY) + return 1; + + /* Don't interrupt while we are messing with the ADB */ + s = splhigh(); + + 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! */ + } + +#ifdef ADB_DEBUG + if (adb_debug) + printf_intr("QUEUE\n"); +#endif + 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 */ + + /* copy additional output data, if any */ + memcpy(adbOutputBuffer + 3, buffer + 1, len); + } else + /* if data ready, just copy over */ + memcpy(adbOutputBuffer, in, in[0] + 2); + + 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? */ +#ifdef ADB_DEBUG + if (adb_debug) + printf_intr("out start NOW"); +#endif + delay(ADB_DELAY); + adbActionState = ADB_ACTION_OUT; /* set next state */ + ADB_SET_SR_OUTPUT(); /* set shift register for OUT */ + write_via_reg(VIA1, vSR, 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 ((s & (1 << 18)) || adb_polling) /* XXX 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(); /* process it */ + adb_soft_intr(); + } + + return 0; +} /* send_adb_cuda */ + + +void +adb_intr_II(void) +{ + panic("adb_intr_II"); +} + + +/* + * send_adb version for II series machines + */ +int +send_adb_II(u_char * in, u_char * buffer, void *compRout, void *data, int command) +{ + panic("send_adb_II"); +} + + +/* + * 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 = 1; + 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: + pm_intr(); + 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) +{ + panic("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) +{ + panic("send_adb_IIsi"); +} + + +/* + * adb_pass_up is called by the interrupt-time routines. + * It takes the raw packet data that was received from the + * device and puts it into the queue that the upper half + * processes. It then signals for a soft ADB interrupt which + * will eventually call the upper half routine (adb_soft_intr). + * + * If in->unsol is 0, then this is either the notification + * that the packet was sent (on a LISTEN, for example), or the + * response from the device (on a TALK). The completion routine + * is called only if the user specified one. + * + * If in->unsol is 1, then this packet was unsolicited and + * so we look up the device in the ADB device table to determine + * what it's default service routine is. + * + * If in->ack_only is 1, then we really only need to call + * the completion routine, so don't do any other stuff. + * + * Note that in->data contains the packet header AND data, + * while adbInbound[]->data contains ONLY data. + * + * Note: Called only at interrupt time. Assumes this. + */ +void +adb_pass_up(struct adbCommand *in) +{ + int start = 0, len = 0, cmd = 0; + ADBDataBlock block; + + /* temp for testing */ + /*u_char *buffer = 0;*/ + /*u_char *compdata = 0;*/ + /*u_char *comprout = 0;*/ + + if (adbInCount >= ADB_QUEUE) { +#ifdef ADB_DEBUG + if (adb_debug) + printf_intr("adb: ring buffer overflow\n"); +#endif + return; + } + + if (in->ack_only) { + len = in->data[0]; + cmd = in->cmd; + start = 0; + } else { + switch (adbHardware) { + case ADB_HW_II: + cmd = in->data[1]; + if (in->data[0] < 2) + len = 0; + else + len = in->data[0]-1; + start = 1; + break; + + case ADB_HW_IISI: + case ADB_HW_CUDA: + /* If it's unsolicited, accept only ADB data for now */ + if (in->unsol) + if (0 != in->data[2]) + return; + cmd = in->data[4]; + if (in->data[0] < 5) + len = 0; + else + len = in->data[0]-4; + start = 4; + break; + + case ADB_HW_PB: + cmd = in->data[1]; + if (in->data[0] < 2) + len = 0; + else + len = in->data[0]-1; + start = 1; + break; + + case ADB_HW_UNKNOWN: + return; + } + + /* Make sure there is a valid device entry for this device */ + if (in->unsol) { + /* ignore unsolicited data during adbreinit */ + if (adbStarting) + return; + /* get device's comp. routine and data area */ + if (-1 == get_adb_info(&block, ADB_CMDADDR(cmd))) + return; + } + } + + /* + * If this is an unsolicited packet, we need to fill in + * some info so adb_soft_intr can process this packet + * properly. If it's not unsolicited, then use what + * the caller sent us. + */ + if (in->unsol) { + adbInbound[adbInTail].compRout = (void *)block.dbServiceRtPtr; + adbInbound[adbInTail].compData = (void *)block.dbDataAreaAddr; + adbInbound[adbInTail].saveBuf = (void *)adbInbound[adbInTail].data; + } else { + adbInbound[adbInTail].compRout = (void *)in->compRout; + adbInbound[adbInTail].compData = (void *)in->compData; + adbInbound[adbInTail].saveBuf = (void *)in->saveBuf; + } + +#ifdef ADB_DEBUG + if (adb_debug && in->data[1] == 2) + printf_intr("adb: caught error\n"); +#endif + + /* copy the packet data over */ + /* + * TO DO: If the *_intr routines fed their incoming data + * directly into an adbCommand struct, which is passed to + * this routine, then we could eliminate this copy. + */ + memcpy(adbInbound[adbInTail].data + 1, in->data + start + 1, len); + adbInbound[adbInTail].data[0] = len; + adbInbound[adbInTail].cmd = cmd; + + adbInCount++; + if (++adbInTail >= ADB_QUEUE) + adbInTail = 0; + + /* + * If the debugger is running, call upper half manually. + * Otherwise, trigger a soft interrupt to handle the rest later. + */ + if (adb_polling) + adb_soft_intr(); + else + setsoftadb(); + + return; +} + + +/* + * Called to process the packets after they have been + * placed in the incoming queue. + * + */ +void +adb_soft_intr(void) +{ + int s; + int cmd = 0; + u_char *buffer = 0; + u_char *comprout = 0; + u_char *compdata = 0; + +#if 0 + s = splhigh(); + printf_intr("sr: %x\n", (s & 0x0700)); + splx(s); +#endif + +/*delay(2*ADB_DELAY);*/ + + while (adbInCount) { +#ifdef ADB_DEBUG + if (adb_debug & 0x80) + printf_intr("%x %x %x ", + adbInCount, adbInHead, adbInTail); +#endif + /* get the data we need from the queue */ + buffer = adbInbound[adbInHead].saveBuf; + comprout = adbInbound[adbInHead].compRout; + compdata = adbInbound[adbInHead].compData; + cmd = adbInbound[adbInHead].cmd; + + /* copy over data to data area if it's valid */ + /* + * Note that for unsol packets we don't want to copy the + * data anywhere, so buffer was already set to 0. + * For ack_only buffer was set to 0, so don't copy. + */ + if (buffer) + memcpy(buffer, adbInbound[adbInHead].data, + adbInbound[adbInHead].data[0] + 1); + +#ifdef ADB_DEBUG + if (adb_debug & 0x80) { + printf_intr("%p %p %p %x ", + buffer, comprout, compdata, (short)cmd); + printf_intr("buf: "); + print_single(adbInbound[adbInHead].data); + } +#endif + + /* call default completion routine if it's valid */ + if (comprout) { + int (*f)() = (void *)comprout; + + (*f)(buffer, compdata, cmd); +#if 0 +#ifdef __NetBSD__ + asm(" movml #0xffff,sp@- | save all registers + movl %0,a2 | compdata + movl %1,a1 | comprout + movl %2,a0 | buffer + movl %3,d0 | cmd + jbsr a1@ | go call the routine + movml sp@+,#0xffff | restore all registers" + : + : "g"(compdata), "g"(comprout), + "g"(buffer), "g"(cmd) + : "d0", "a0", "a1", "a2"); +#else /* for macos based testing */ + asm + { + movem.l a0/a1/a2/d0, -(a7) + move.l compdata, a2 + move.l comprout, a1 + move.l buffer, a0 + move.w cmd, d0 + jsr(a1) + movem.l(a7)+, d0/a2/a1/a0 + } +#endif +#endif + } + + s = splhigh(); + adbInCount--; + if (++adbInHead >= ADB_QUEUE) + adbInHead = 0; + splx(s); + + } + return; +} + + +/* + * 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); + if (result == 0) + return 0; + else + return -1; + 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); + if (result == 0) + return 0; + else + return -1; + break; + + case ADB_HW_PB: + result = pm_adb_op((u_char *)buffer, (void *)compRout, + (void *)data, (int)command); + + if (result == 0) + return 0; + else + return -1; + break; + + case ADB_HW_CUDA: + result = send_adb_cuda((u_char *)0, (u_char *)buffer, + (void *)compRout, (void *)data, (int)command); + if (result == 0) + return 0; + else + return -1; + break; + + case ADB_HW_UNKNOWN: + default: + return -1; + } +} + + +/* + * adb_hw_setup + * This routine sets up the possible machine specific hardware + * config (mainly VIA settings) for the various models. + */ +void +adb_hw_setup(void) +{ + volatile int i; + u_char send_string[ADB_MAX_MSG_LENGTH]; + + switch (adbHardware) { + case ADB_HW_II: + via_reg_or(VIA1, vDirB, 0x30); /* register B bits 4 and 5: + * outputs */ + via_reg_and(VIA1, vDirB, 0xf7); /* register B bit 3: input */ + via_reg_and(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 */ + write_via_reg(VIA1, vIER, 0x84);/* make sure VIA interrupts + * are on (II, IIsi) */ + ADB_SET_STATE_IDLE_II(); /* set ADB bus state to idle */ + + ADB_VIA_CLR_INTR(); /* clear interrupt */ + break; + + case ADB_HW_IISI: + via_reg_or(VIA1, vDirB, 0x30); /* register B bits 4 and 5: + * outputs */ + via_reg_and(VIA1, vDirB, 0xf7); /* register B bit 3: input */ + via_reg_and(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 */ + write_via_reg(VIA1, vIER, 0x84);/* make sure VIA interrupts + * are on (II, IIsi) */ + ADB_SET_STATE_IDLE_IISI(); /* set ADB bus state to idle */ + + /* get those pesky clock ticks we missed while booting */ + for (i = 0; i < 30; i++) { + delay(ADB_DELAY); + adb_hw_setup_IIsi(send_string); +#ifdef ADB_DEBUG + if (adb_debug) { + printf_intr("adb: cleanup: "); + print_single(send_string); + } +#endif + delay(ADB_DELAY); + if (ADB_INTR_IS_OFF) + break; + } + break; + + case ADB_HW_PB: + /* + * XXX - really PM_VIA_CLR_INTR - should we put it in + * pm_direct.h? + */ + write_via_reg(VIA1, vIFR, 0x90); /* clear interrupt */ + break; + + case ADB_HW_CUDA: + via_reg_or(VIA1, vDirB, 0x30); /* register B bits 4 and 5: + * outputs */ + via_reg_and(VIA1, vDirB, 0xf7); /* register B bit 3: input */ + via_reg_and(VIA1, vACR, ~vSR_OUT); /* make sure SR is set + * to IN */ + write_via_reg(VIA1, vACR, (read_via_reg(VIA1, vACR) | 0x0c) & ~0x10); + adbActionState = ADB_ACTION_IDLE; /* used by all types of + * hardware */ + adbBusState = ADB_BUS_IDLE; /* this var. used in II-series + * code only */ + write_via_reg(VIA1, vIER, 0x84);/* make sure VIA interrupts + * are on */ + ADB_SET_STATE_IDLE_CUDA(); /* set ADB bus state to idle */ + + /* sort of a device reset */ + i = ADB_SR(); /* clear interrupt */ + ADB_VIA_INTR_DISABLE(); /* no interrupts while clearing */ + ADB_SET_STATE_IDLE_CUDA(); /* reset state to idle */ + delay(ADB_DELAY); + ADB_SET_STATE_TIP(); /* signal start of frame */ + delay(ADB_DELAY); + ADB_TOGGLE_STATE_ACK_CUDA(); + delay(ADB_DELAY); + ADB_CLR_STATE_TIP(); + delay(ADB_DELAY); + ADB_SET_STATE_IDLE_CUDA(); /* back to idle state */ + i = ADB_SR(); /* clear interrupt */ + ADB_VIA_INTR_ENABLE(); /* ints ok now */ + break; + + case ADB_HW_UNKNOWN: + default: + write_via_reg(VIA1, vIER, 0x04);/* turn interrupts off - TO + * DO: turn PB ints off? */ + return; + break; + } +} + + +/* + * adb_hw_setup_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_hw_setup_IIsi(u_char * buffer) +{ + panic("adb_hw_setup_IIsi"); +} + + +/* + * adb_reinit sets up the adb stuff + * + */ +void +adb_reinit(void) +{ + u_char send_string[ADB_MAX_MSG_LENGTH]; + ADBDataBlock data; /* temp. holder for getting device info */ + volatile int i, x; + int s; + int command; + int result; + int saveptr; /* point to next free relocation address */ + int device; + int nonewtimes; /* times thru loop w/o any new devices */ + + /* Make sure we are not interrupted while building the table. */ + if (adbHardware != ADB_HW_PB) /* ints must be on for PB? */ + 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 */ + + adb_hw_setup(); /* init the VIA bits and hard reset ADB */ + + delay(1000); + + /* 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++) { + send_string[0] = 0; + command = ADBTALK(i, 3); + result = adb_op_sync((Ptr)send_string, (Ptr)0, + (Ptr)0, (short)command); + + if (send_string[0] != 0) { + /* check for valid device handler */ + switch (send_string[2]) { + case 0: + case 0xfd: + case 0xfe: + case 0xff: + continue; /* invalid, skip */ + } + + /* found a device */ + ++ADBNumDevices; + KASSERT(ADBNumDevices < 16); + ADBDevTable[ADBNumDevices].devType = + (int)send_string[2]; + ADBDevTable[ADBNumDevices].origAddr = i; + ADBDevTable[ADBNumDevices].currentAddr = i; + ADBDevTable[ADBNumDevices].DataAreaAddr = + (long)0; + ADBDevTable[ADBNumDevices].ServiceRtPtr = (void *)0; + pm_check_adb_devices(i); /* tell pm driver device + * is here */ + } + } + + /* find highest unused address */ + for (saveptr = 15; saveptr > 0; saveptr--) + if (-1 == get_adb_info(&data, saveptr)) + break; + +#ifdef ADB_DEBUG + if (adb_debug & 0x80) { + printf_intr("first free is: 0x%02x\n", saveptr); + printf_intr("devices: %i\n", ADBNumDevices); + } +#endif + + nonewtimes = 0; /* no loops w/o new devices */ + while (saveptr > 0 && nonewtimes++ < 11) { + for (i = 1; i <= ADBNumDevices; i++) { + device = ADBDevTable[i].currentAddr; +#ifdef ADB_DEBUG + if (adb_debug & 0x80) + printf_intr("moving device 0x%02x to 0x%02x " + "(index 0x%02x) ", device, saveptr, i); +#endif + + /* send TALK R3 to address */ + command = ADBTALK(device, 3); + adb_op_sync((Ptr)send_string, (Ptr)0, + (Ptr)0, (short)command); + + /* move device to higher address */ + command = ADBLISTEN(device, 3); + 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); + delay(500); + + /* send TALK R3 - anything at new address? */ + command = ADBTALK(saveptr, 3); + adb_op_sync((Ptr)send_string, (Ptr)0, + (Ptr)0, (short)command); + delay(500); + + if (send_string[0] == 0) { +#ifdef ADB_DEBUG + if (adb_debug & 0x80) + printf_intr("failed, continuing\n"); +#endif + continue; + } + + /* send TALK R3 - anything at old address? */ + command = ADBTALK(device, 3); + result = adb_op_sync((Ptr)send_string, (Ptr)0, + (Ptr)0, (short)command); + if (send_string[0] != 0) { + /* check for valid device handler */ + switch (send_string[2]) { + case 0: + case 0xfd: + case 0xfe: + case 0xff: + continue; /* invalid, skip */ + } + + /* new device found */ + /* update data for previously moved device */ + ADBDevTable[i].currentAddr = saveptr; +#ifdef ADB_DEBUG + if (adb_debug & 0x80) + printf_intr("old device at index %i\n",i); +#endif + /* add new device in table */ +#ifdef ADB_DEBUG + if (adb_debug & 0x80) + printf_intr("new device found\n"); +#endif + if (saveptr > ADBNumDevices) { + ++ADBNumDevices; + KASSERT(ADBNumDevices < 16); + } + ADBDevTable[ADBNumDevices].devType = + (int)send_string[2]; + ADBDevTable[ADBNumDevices].origAddr = device; + ADBDevTable[ADBNumDevices].currentAddr = device; + /* These will be set correctly in adbsys.c */ + /* Until then, unsol. data will be ignored. */ + 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; + } + } + if (x == 0) + saveptr = 0; +#ifdef ADB_DEBUG + if (adb_debug & 0x80) + printf_intr("new free is 0x%02x\n", + saveptr); +#endif + nonewtimes = 0; + /* tell pm driver device is here */ + pm_check_adb_devices(device); + } else { +#ifdef ADB_DEBUG + if (adb_debug & 0x80) + printf_intr("moving back...\n"); +#endif + /* move old device back */ + command = ADBLISTEN(saveptr, 3); + 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); + delay(1000); + } + } + } + +#ifdef ADB_DEBUG + if (adb_debug) { + for (i = 1; i <= ADBNumDevices; i++) { + x = get_ind_adb_info(&data, i); + if (x != -1) + printf_intr("index 0x%x, addr 0x%x, type 0x%x\n", + i, x, data.devType); + } + } +#endif + +#ifndef MRG_ADB + /* enable the programmer's switch, if we have one */ + adb_prog_switch_enable(); +#endif + +#ifdef ADB_DEBUG + if (adb_debug) { + if (0 == ADBNumDevices) /* tell user if no devices found */ + printf_intr("adb: no devices found\n"); + } +#endif + + adbStarting = 0; /* not starting anymore */ +#ifdef ADB_DEBUG + if (adb_debug) + printf_intr("adb: ADBReInit complete\n"); +#endif + + if (adbHardware == ADB_HW_CUDA) + timeout((void *)adb_cuda_tickle, 0, ADB_TICKLE_TICKS); + + if (adbHardware != ADB_HW_PB) /* ints must be on for PB? */ + splx(s); +} + + +#if 0 +/* + * adb_comp_exec + * This is a general routine that calls the completion routine if there is one. + * NOTE: This routine is now only used by pm_direct.c + * All the code in this file (adb_direct.c) uses + * the adb_pass_up routine now. + */ +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) + : "d0", "a0", "a1", "a2"); +#else /* for Mac OS-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 +} +#endif + + +/* + * 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; + return 1; + + case ADB_HW_IISI: + case ADB_HW_CUDA: + /* was it an ADB talk command? */ + if ((in[1] == 0x00) && ((in[2] & 0x0c) == 0x0c)) + return 0; + /* was it an RTC/PRAM read date/time? */ + if ((in[1] == 0x01) && (in[2] == 0x03)) + return 0; + return 1; + + case ADB_HW_PB: + return 1; + + 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; + return 1; + + 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; + /* add others later */ + return 1; + + case ADB_HW_PB: + return 1; + + 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. + * + * NOTE: The user specified compRout is ignored, since this routine specifies + * it's own to adb_op, which is why you really called this in the first place + * anyway. + */ +int +adb_op_sync(Ptr buffer, Ptr compRout, Ptr data, short command) +{ + int result; + volatile int flag = 0; + + result = adb_op(buffer, (void *)adb_op_comprout, + (void *)&flag, command); /* send command */ + if (result == 0) /* send ok? */ + while (0 == flag) + /* wait for compl. routine */; + + 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(buffer, compdata, cmd) + caddr_t buffer, compdata; + int cmd; +{ + short *p = (short *)compdata; + + *p = 1; +} + +void +adb_setup_hw_type(void) +{ + switch (adbHardware) { + case ADB_HW_CUDA: + adbSoftPower = 1; + return; + + case ADB_HW_PB: + adbSoftPower = 1; + pm_setup_adb(); + return; + + default: + panic("unknown adb hardware"); + } +#if 0 + response = 0; /*mac68k_machine.machineid;*/ + + /* + * Determine what type of ADB hardware we are running on. + */ + switch (response) { + case MACH_MACC610: /* Centris 610 */ + case MACH_MACC650: /* Centris 650 */ + case MACH_MACII: /* II */ + case MACH_MACIICI: /* IIci */ + case MACH_MACIICX: /* IIcx */ + case MACH_MACIIX: /* IIx */ + case MACH_MACQ610: /* Quadra 610 */ + case MACH_MACQ650: /* Quadra 650 */ + case MACH_MACQ700: /* Quadra 700 */ + case MACH_MACQ800: /* Quadra 800 */ + case MACH_MACSE30: /* SE/30 */ + adbHardware = ADB_HW_II; +#ifdef ADB_DEBUG + if (adb_debug) + printf_intr("adb: using II series hardware support\n"); +#endif + break; + + case MACH_MACCLASSICII: /* Classic II */ + case MACH_MACLCII: /* LC II, Performa 400/405/430 */ + case MACH_MACLCIII: /* LC III, Performa 450 */ + case MACH_MACIISI: /* IIsi */ + case MACH_MACIIVI: /* IIvi */ + case MACH_MACIIVX: /* IIvx */ + case MACH_MACP460: /* Performa 460/465/467 */ + case MACH_MACP600: /* Performa 600 */ + adbHardware = ADB_HW_IISI; +#ifdef ADB_DEBUG + if (adb_debug) + printf_intr("adb: using IIsi series hardware support\n"); +#endif + break; + + case MACH_MACPB140: /* PowerBook 140 */ + case MACH_MACPB145: /* PowerBook 145 */ + case MACH_MACPB150: /* PowerBook 150 */ + case MACH_MACPB160: /* PowerBook 160 */ + case MACH_MACPB165: /* PowerBook 165 */ + case MACH_MACPB165C: /* PowerBook 165c */ + case MACH_MACPB170: /* PowerBook 170 */ + case MACH_MACPB180: /* PowerBook 180 */ + case MACH_MACPB180C: /* PowerBook 180c */ + adbHardware = ADB_HW_PB; + pm_setup_adb(); +#ifdef ADB_DEBUG + if (adb_debug) + printf_intr("adb: using PowerBook 100-series hardware support\n"); +#endif + break; + + case MACH_MACPB210: /* PowerBook Duo 210 */ + case MACH_MACPB230: /* PowerBook Duo 230 */ + case MACH_MACPB250: /* PowerBook Duo 250 */ + case MACH_MACPB270: /* PowerBook Duo 270 */ + case MACH_MACPB280: /* PowerBook Duo 280 */ + case MACH_MACPB280C: /* PowerBook Duo 280c */ + case MACH_MACPB500: /* PowerBook 500 series */ + adbHardware = ADB_HW_PB; + pm_setup_adb(); +#ifdef ADB_DEBUG + if (adb_debug) + printf_intr("adb: using PowerBook Duo-series and PowerBook 500-series hardware support\n"); +#endif + break; + + case MACH_MACC660AV: /* Centris 660AV */ + case MACH_MACCCLASSIC: /* Color Classic */ + case MACH_MACCCLASSICII: /* Color Classic II */ + case MACH_MACLC475: /* LC 475, Performa 475/476 */ + case MACH_MACLC475_33: /* Clock-chipped 47x */ + case MACH_MACLC520: /* LC 520 */ + case MACH_MACLC575: /* LC 575, Performa 575/577/578 */ + case MACH_MACP550: /* LC 550, Performa 550 */ + case MACH_MACP580: /* Performa 580/588 */ + case MACH_MACQ605: /* Quadra 605 */ + case MACH_MACQ605_33: /* Clock-chipped Quadra 605 */ + case MACH_MACQ630: /* LC 630, Performa 630, Quadra 630 */ + case MACH_MACQ840AV: /* Quadra 840AV */ + adbHardware = ADB_HW_CUDA; +#ifdef ADB_DEBUG + if (adb_debug) + printf_intr("adb: using Cuda series hardware support\n"); +#endif + break; + default: + adbHardware = ADB_HW_UNKNOWN; +#ifdef ADB_DEBUG + if (adb_debug) { + printf_intr("adb: hardware type unknown for this machine\n"); + printf_intr("adb: ADB support is disabled\n"); + } +#endif + break; + } + + /* + * Determine whether this machine has ADB based soft power. + */ + switch (response) { + case MACH_MACCCLASSIC: /* Color Classic */ + case MACH_MACCCLASSICII: /* Color Classic II */ + case MACH_MACIISI: /* IIsi */ + case MACH_MACIIVI: /* IIvi */ + case MACH_MACIIVX: /* IIvx */ + case MACH_MACLC520: /* LC 520 */ + case MACH_MACLC575: /* LC 575, Performa 575/577/578 */ + case MACH_MACP550: /* LC 550, Performa 550 */ + case MACH_MACP600: /* Performa 600 */ + case MACH_MACQ630: /* LC 630, Performa 630, Quadra 630 */ + case MACH_MACQ840AV: /* Quadra 840AV */ + adbSoftPower = 1; + break; + } +#endif +} + +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); + +#ifdef ADB_DEBUG + if (adb_debug & 0x80) + printf_intr("index 0x%x devType is: 0x%x\n", index, + ADBDevTable[index].devType); +#endif + 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 */ + +} + +#ifndef MRG_ADB + +/* 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[ADB_MAX_MSG_LENGTH]; + int result; + volatile 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, (int *)&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: + pm_read_date_time(time); + return 0; + + 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 */ + ; + + memcpy(time, output + 1, 4); + 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[ADB_MAX_MSG_LENGTH]; + int result; + volatile int flag = 0; + + switch (adbHardware) { + + 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_PB: + pm_set_date_time(time); + return 0; + + case ADB_HW_II: + case ADB_HW_IISI: + case ADB_HW_UNKNOWN: + default: + return -1; + } +} + + +int +adb_poweroff(void) +{ + u_char output[ADB_MAX_MSG_LENGTH]; + int result; + + if (!adbSoftPower) + return -1; + + adb_polling = 1; + + 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: + pm_adb_poweroff(); + + for (;;); /* wait for power off */ + + return 0; + + case ADB_HW_CUDA: + output[0] = 0x02; /* 2 byte message */ + output[1] = 0x01; /* to pram/rtc/soft-power device */ + output[2] = 0x0a; /* set date/time */ + result = send_adb_cuda((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_II: /* II models don't do ADB soft power */ + case ADB_HW_UNKNOWN: + default: + return -1; + } +} + +int +adb_prog_switch_enable(void) +{ + u_char output[ADB_MAX_MSG_LENGTH]; + int result; + volatile 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 TO DO: verify this */ + case ADB_HW_UNKNOWN: + default: + return -1; + } +} + +int +adb_prog_switch_disable(void) +{ + u_char output[ADB_MAX_MSG_LENGTH]; + int result; + volatile 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; + } +} + +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 + +int +setsoftadb() +{ + timeout((void *)adb_soft_intr, NULL, 1); + return 0; +} + +void +adb_cuda_autopoll() +{ + volatile int flag = 0; + int result; + u_char output[16]; + extern void adb_op_comprout(); + + output[0] = 0x03; /* 3-byte message */ + output[1] = 0x01; /* to pram/rtc device */ + output[2] = 0x01; /* cuda autopoll */ + output[3] = 0x01; + result = send_adb_cuda(output, output, adb_op_comprout, + (void *)&flag, 0); + if (result != 0) /* exit if not sent */ + return; + + while (flag == 0); /* wait for result */ +} + +void +adb_restart() +{ + volatile int flag = 0; + int result; + u_char output[16]; + + adb_polling = 1; + + switch (adbHardware) { + case ADB_HW_CUDA: + output[0] = 0x02; /* 2 byte message */ + output[1] = 0x01; /* to pram/rtc/soft-power device */ + output[2] = 0x11; /* restart */ + result = send_adb_cuda((u_char *)output, (u_char *)0, + (void *)0, (void *)0, (int)0); + if (result != 0) /* exit if not sent */ + return; + while (1); /* not return */ + + case ADB_HW_PB: + pm_adb_restart(); + while (1); /* not return */ + } +} diff --git a/sys/arch/powerpc/mac/adb_direct.h b/sys/arch/powerpc/mac/adb_direct.h new file mode 100644 index 00000000000..76aff051d1b --- /dev/null +++ b/sys/arch/powerpc/mac/adb_direct.h @@ -0,0 +1,53 @@ +/* $NetBSD: adb_direct.h,v 1.1 1998/05/15 10:15:47 tsubai Exp $ */ + +/* + * Copyright (C) 1996 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. + */ +/* From: adb_direct.h 1.4 10/23/96 jpw */ + +/* + * These are public declarations that other routines may need. + */ + +/* 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 */ + +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 *)); +int adb_set_date_time __P((unsigned long)); diff --git a/sys/arch/powerpc/mac/adbvar.h b/sys/arch/powerpc/mac/adbvar.h new file mode 100644 index 00000000000..329ba24e919 --- /dev/null +++ b/sys/arch/powerpc/mac/adbvar.h @@ -0,0 +1,129 @@ +/* $NetBSD: adbvar.h,v 1.3 2000/06/08 22:10:46 tsubai Exp $ */ + +/*- + * Copyright (C) 1994 Bradley A. Grantham + * 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 Bradley A. Grantham. + * 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. + */ + +#include <machine/adbsys.h> + +/* + * Arguments used to attach a device to the Apple Desktop Bus + */ +struct adb_attach_args { + int origaddr; + int adbaddr; + int handler_id; +}; + +#define ADB_MAXTRACE (NBPG / sizeof(int) - 1) +extern int adb_traceq[ADB_MAXTRACE]; +extern int adb_traceq_tail; +extern int adb_traceq_len; + +typedef struct adb_trace_xlate_s { + int params; + char *string; +} adb_trace_xlate_t; + +extern adb_trace_xlate_t adb_trace_xlations[]; + +#ifdef DEBUG +#ifndef ADB_DEBUG +#define ADB_DEBUG +#endif +#endif + +#ifdef ADB_DEBUG +extern int adb_debug; +#endif + +typedef caddr_t Ptr; +typedef caddr_t *Handle; + +/* ADB Manager */ +typedef struct { + Ptr siServiceRtPtr; + Ptr siDataAreaAddr; +} ADBSetInfoBlock; +typedef struct { + unsigned char devType; + unsigned char origADBAddr; + Ptr dbServiceRtPtr; + Ptr dbDataAreaAddr; +} ADBDataBlock; + +struct adb_softc { + struct device sc_dev; + char *sc_regbase; +}; + + +/* adb.c */ +void adb_enqevent __P((adb_event_t *event)); +void adb_handoff __P((adb_event_t *event)); +void adb_autorepeat __P((void *keyp)); +void adb_dokeyupdown __P((adb_event_t *event)); +void adb_keymaybemouse __P((adb_event_t *event)); +void adb_processevent __P((adb_event_t *event)); +int adbopen __P((dev_t dev, int flag, int mode, struct proc *p)); +int adbclose __P((dev_t dev, int flag, int mode, struct proc *p)); +int adbread __P((dev_t dev, struct uio *uio, int flag)); +int adbwrite __P((dev_t dev, struct uio *uio, int flag)); +int adbioctl __P((dev_t , int , caddr_t , int , struct proc *)); +int adbpoll __P((dev_t dev, int events, struct proc *p)); + +/* adbsys.c */ +void adb_complete __P((caddr_t buffer, caddr_t data_area, int adb_command)); +void adb_msa3_complete __P((caddr_t buffer, caddr_t data_area, int adb_command)); +void adb_mm_nonemp_complete __P((caddr_t buffer, caddr_t data_area, int adb_command)); +void extdms_init __P((int)); +void extdms_complete __P((caddr_t, caddr_t, int)); + +/* 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 */ + +#define ADB_CMDADDR(cmd) ((u_int8_t)((cmd) & 0xf0) >> 4) +#define ADBFLUSH(dev) ((((u_int8_t)(dev) & 0x0f) << 4) | 0x01) +#define ADBLISTEN(dev, reg) ((((u_int8_t)(dev) & 0x0f) << 4) | 0x08 | (reg)) +#define ADBTALK(dev, reg) ((((u_int8_t)(dev) & 0x0f) << 4) | 0x0c | (reg)) + +/* 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)); diff --git a/sys/arch/powerpc/mac/akbdvar.h b/sys/arch/powerpc/mac/akbdvar.h new file mode 100644 index 00000000000..ba5905a60d5 --- /dev/null +++ b/sys/arch/powerpc/mac/akbdvar.h @@ -0,0 +1,60 @@ +/* $NetBSD: akbdvar.h,v 1.4 1999/02/17 14:56:56 tsubai Exp $ */ + +/* + * Copyright (C) 1998 Colin Wood + * 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 Colin Wood. + * 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. + */ + +#ifndef _MACPPC_KBDVAR_H_ +#define _MACPPC_KBDVAR_H_ + +#include <machine/adbsys.h> + +/* + * State info, per keyboard instance. + */ +struct akbd_softc { + struct device sc_dev; + + /* ADB info */ + int origaddr; /* ADB device type (ADBADDR_KBD) */ + int adbaddr; /* current ADB address */ + int handler_id; /* type of keyboard */ + + u_int8_t sc_leds; /* current LED state */ + struct device *sc_wskbddev; +}; + +/* LED register bits, inverse of actual register value */ +#define LED_NUMLOCK 0x1 +#define LED_CAPSLOCK 0x2 +#define LED_SCROLL_LOCK 0x4 + +void kbd_adbcomplete __P((caddr_t buffer, caddr_t data_area, int adb_command)); + +#endif /* _MACPPC_KBDVAR_H_ */ diff --git a/sys/arch/powerpc/mac/pm_direct.c b/sys/arch/powerpc/mac/pm_direct.c new file mode 100644 index 00000000000..1fe916d8b7b --- /dev/null +++ b/sys/arch/powerpc/mac/pm_direct.c @@ -0,0 +1,1308 @@ +/* $NetBSD: pm_direct.c,v 1.9 2000/06/08 22:10:46 tsubai Exp $ */ + +/* + * 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. + */ +/* From: pm_direct.c 1.3 03/18/98 Takashi Hamada */ + +#ifdef DEBUG +#ifndef ADB_DEBUG +#define ADB_DEBUG +#endif +#endif + +/* #define PM_GRAB_SI 1 */ + +#include <sys/param.h> +#include <sys/cdefs.h> +#include <sys/device.h> +#include <sys/systm.h> + +#include <machine/adbsys.h> +#include <machine/cpu.h> + +#include <powerpc/mac/adbvar.h> +#include <powerpc/mac/pm_direct.h> +#include <powerpc/mac/viareg.h> + +extern int adb_polling; /* Are we polling? (Debugger mode) */ + +/* hardware dependent values */ +#define ADBDelay 100 /* XXX */ +#define HwCfgFlags3 0x20000 /* XXX */ + +/* 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() read_via_reg(VIA1, vSR) +#define PM_VIA_INTR_ENABLE() write_via_reg(VIA1, vIER, 0x90) +#define PM_VIA_INTR_DISABLE() write_via_reg(VIA1, vIER, 0x10) +#define PM_VIA_CLR_INTR() write_via_reg(VIA1, vIFR, 0x90) +#if 0 +#define PM_SET_STATE_ACKON() via_reg_or(VIA2, vBufB, 0x04) +#define PM_SET_STATE_ACKOFF() via_reg_and(VIA2, vBufB, ~0x04) +#define PM_IS_ON (0x02 == (read_via_reg(VIA2, vBufB) & 0x02)) +#define PM_IS_OFF (0x00 == (read_via_reg(VIA2, vBufB) & 0x02)) +#else +#define PM_SET_STATE_ACKON() via_reg_or(VIA2, vBufB, 0x10) +#define PM_SET_STATE_ACKOFF() via_reg_and(VIA2, vBufB, ~0x10) +#define PM_IS_ON (0x08 == (read_via_reg(VIA2, vBufB) & 0x08)) +#define PM_IS_OFF (0x00 == (read_via_reg(VIA2, vBufB) & 0x08)) +#endif + +/* + * Variables 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 */ +signed char pm_send_cmd_type[] = { + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 0x01, 0x01, -1, -1, -1, -1, -1, -1, + 0x00, 0x00, -1, -1, -1, -1, -1, 0x00, + -1, 0x00, 0x02, 0x01, 0x01, -1, -1, -1, + 0x00, -1, -1, -1, -1, -1, -1, -1, + 0x04, 0x14, -1, 0x03, -1, -1, -1, -1, + 0x00, 0x00, 0x02, 0x02, -1, -1, -1, -1, + 0x01, 0x01, -1, -1, -1, -1, -1, -1, + 0x00, 0x00, -1, -1, 0x01, -1, -1, -1, + 0x01, 0x00, 0x02, 0x02, -1, 0x01, 0x03, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x00, -1, -1, -1, + 0x02, -1, -1, -1, -1, -1, -1, -1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -1, -1, + 0x01, 0x01, 0x01, -1, -1, -1, -1, -1, + 0x00, 0x00, -1, -1, -1, -1, 0x04, 0x04, + 0x04, -1, 0x00, -1, -1, -1, -1, -1, + 0x00, -1, -1, -1, -1, -1, -1, -1, + 0x01, 0x02, -1, -1, -1, -1, -1, -1, + 0x00, 0x00, -1, -1, -1, -1, -1, -1, + 0x02, 0x02, 0x02, 0x04, -1, 0x00, -1, -1, + 0x01, 0x01, 0x03, 0x02, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 0x00, -1, -1, -1, -1, -1, -1, -1, + 0x01, 0x01, -1, -1, 0x00, 0x00, -1, -1, + -1, 0x04, 0x00, -1, -1, -1, -1, -1, + 0x03, -1, 0x00, -1, 0x00, -1, -1, 0x00, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1 +}; + +/* these values shows that number of data returned after 'receive' cmd is sent */ +signed char pm_receive_cmd_type[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + -1, -1, -1, -1, -1, -1, -1, -1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x02, -1, -1, -1, -1, -1, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + -1, -1, -1, -1, -1, -1, -1, -1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x05, 0x15, -1, 0x02, -1, -1, -1, -1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x02, -1, -1, -1, -1, -1, -1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x03, 0x03, -1, -1, -1, -1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x04, 0x03, 0x09, -1, -1, -1, -1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + -1, -1, -1, -1, -1, -1, 0x01, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, -1, -1, -1, -1, -1, -1, -1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x02, -1, -1, -1, -1, -1, -1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, -1, -1, -1, -1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + -1, -1, -1, -1, -1, -1, -1, -1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + -1, -1, -1, -1, -1, -1, -1, -1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x02, -1, -1, 0x02, -1, -1, -1, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + -1, -1, 0x02, -1, -1, -1, -1, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + -1, -1, -1, -1, -1, -1, -1, -1, +}; + + +/* + * Define the private functions + */ + +/* for debugging */ +#ifdef ADB_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 variables 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 variables are in adb_direct.c. + */ +extern u_char *adbBuffer; /* pointer to user data area */ +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 ADB_MAX_MSG_LENGTH 16 +#define ADB_MAX_HDR_LENGTH 8 +struct adbCommand { + u_char header[ADB_MAX_HDR_LENGTH]; /* not used yet */ + u_char data[ADB_MAX_MSG_LENGTH]; /* packet data only */ + u_char *saveBuf; /* where to save result */ + u_char *compRout; /* completion routine pointer */ + u_char *compData; /* completion routine data pointer */ + u_int cmd; /* the original command for this data */ + u_int unsol; /* 1 if packet was unsolicited */ + u_int ack_only; /* 1 for no special processing */ +}; +extern void adb_pass_up __P((struct adbCommand *)); + +#if 0 +/* + * Define the external functions + */ +extern int zshard __P((int)); /* from zs.c */ +#endif + +#ifdef ADB_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() +{ + pmHardware = PM_HW_PB5XX; /* XXX */ +} + + +/* + * 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 +#if 0 + zshard(0); /* grab any serial interrupts */ +#else + (void)intr_dispatch(0x70); +#endif +#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 +#if 0 + zshard(0); /* grab any serial interrupts */ +#else + (void)intr_dispatch(0x70); +#endif +#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; +{ +#if 0 + 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; +#else + panic("pm_receive_pm1"); +#endif +} + + + +/* + * Send data to PM for the PB1XX series + */ +int +pm_send_pm1(data, delay) + u_char data; + int delay; +{ +#if 0 + 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; +#else + panic("pm_send_pm1"); +#endif +} + + +/* + * My PMgrOp routine for the PB1XX series + */ +int +pm_pmgrop_pm1(pmdata) + PMData *pmdata; +{ +#if 0 + 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) + break; /* send command succeeded */ + + 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; + if (s != 0x81815963) + splx(s); + 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; +#else + panic("pm_pmgrop_pm1"); +#endif +} + + +/* + * My PM interrupt routine for PB1XX series + */ +void +pm_intr_pm1() +{ +#if 0 + 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 ADB_DEBUG + if (adb_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 ADB_DEBUG + if (adb_debug) + pm_printerr("driver does not supported this event.", + rval, pmdata.num_data, pmdata.data); +#endif + } + + splx(s); +#else + panic("pm_intr_pm1"); +#endif +} + + + +/* + * 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_or(VIA1, vACR, 0x0c); + via_reg_and(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_or(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_or(VIA1, vACR, 0x1c); + write_via_reg(VIA1, vSR, data); /* PM_SR() = data; */ + + PM_SET_STATE_ACKOFF(); + rval = 0xffffcd36; + if (pm_wait_busy((int)ADBDelay*32) != 0) { + PM_SET_STATE_ACKON(); + + via_reg_or(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_or(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 &= read_via_reg(VIA1, vIER); + write_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; + + write_via_reg(VIA2, vDirA, 0x00); + while ((read_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 */ + write_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() +{ + 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 ADB_DEBUG + if (adb_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 < 0x08) + pm_LCD_brightness = 0x08; + if (pm_LCD_brightness > 0x78) + pm_LCD_brightness = 0x78; + pmdata.data[0] = pm_LCD_brightness; + rval = pm_pmgrop_pm2(&pmdata); + break; + case 0x10: /* ADB data that were requested by TALK command */ + case 0x14: + pm_adb_get_TALK_result(&pmdata); + break; + case 0x16: /* ADB device event */ + case 0x18: + case 0x1e: + pm_adb_get_ADB_data(&pmdata); + break; + default: +#ifdef ADB_DEBUG + if (adb_debug) + pm_printerr("driver does not supported this event.", + pmdata.data[2], pmdata.num_data, + pmdata.data); +#endif + break; + } + + splx(s); +} + + +#if 0 +/* + * 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; +} +#endif + + +/* + * 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() +{ + 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; + int s; + int rval; + int delay; + PMData pmdata; + struct adbCommand packet; + + if (adbWaiting == 1) + return 1; + + s = splhigh(); + write_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 the command is LISTEN, add number of ADB data to number of PM data */ + if ((command & 0xc) == 0x8) { + 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; + + if ((command & 0xc) != 0xc) { /* if the command is not TALK */ + /* set up stuff for adb_pass_up */ + packet.data[0] = 1 + pmdata.data[2]; + packet.data[1] = command; + for (i = 0; i < pmdata.data[2]; i++) + packet.data[i+2] = pmdata.data[i+3]; + packet.saveBuf = adbBuffer; + packet.compRout = adbCompRout; + packet.compData = adbCompData; + packet.cmd = command; + packet.unsol = 0; + packet.ack_only = 1; + adb_polling = 1; + adb_pass_up(&packet); + adb_polling = 0; + } + + rval = pmgrop(&pmdata); + if (rval != 0) { + splx(s); + return 1; + } + + adbWaiting = 1; + adbWaitingCmd = command; + + PM_VIA_INTR_ENABLE(); + + /* wait until the PM interrupt is occured */ + delay = 0x80000; + while (adbWaiting == 1) { + if (read_via_reg(VIA1, vIFR) & 0x14) + pm_intr(); +#ifdef PM_GRAB_SI +#if 0 + zshard(0); /* grab any serial interrupts */ +#else + (void)intr_dispatch(0x70); +#endif +#endif + if ((--delay) < 0) { + splx(s); + return 1; + } + } + + /* this command enables the interrupt by operating ADB devices */ + if (HwCfgFlags3 & 0x00020000) { /* PB Duo series, PB 5XX 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 1XX 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; + struct adbCommand packet; + + /* set up data for adb_pass_up */ + packet.data[0] = pmdata->num_data-1; + packet.data[1] = pmdata->data[3]; + for (i = 0; i <packet.data[0]-1; i++) + packet.data[i+2] = pmdata->data[i+4]; + + packet.saveBuf = adbBuffer; + packet.compRout = adbCompRout; + packet.compData = adbCompData; + packet.unsol = 0; + packet.ack_only = 0; + adb_polling = 1; + adb_pass_up(&packet); + adb_polling = 0; + + adbWaiting = 0; + adbBuffer = (long)0; + adbCompRout = (long)0; + adbCompData = (long)0; +} + + +void +pm_adb_get_ADB_data(pmdata) + PMData *pmdata; +{ + int i; + struct adbCommand packet; + + /* set up data for adb_pass_up */ + packet.data[0] = pmdata->num_data-1; /* number of raw data */ + packet.data[1] = pmdata->data[3]; /* ADB command */ + for (i = 0; i <packet.data[0]-1; i++) + packet.data[i+2] = pmdata->data[i+4]; + packet.unsol = 1; + packet.ack_only = 0; + adb_pass_up(&packet); +} + + +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 = (ADB_CMDADDR(pmdata->data[3]) + 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); +} + +void +pm_adb_restart() +{ + PMData p; + + p.command = PMU_RESET_CPU; + p.num_data = 0; + p.s_buf = p.data; + p.r_buf = p.data; + pmgrop(&p); +} + +void +pm_adb_poweroff() +{ + PMData p; + + p.command = PMU_POWER_OFF; + p.num_data = 4; + p.s_buf = p.data; + p.r_buf = p.data; + strcpy(p.data, "MATT"); + pmgrop(&p); +} + +void +pm_read_date_time(time) + u_long *time; +{ + PMData p; + + p.command = PMU_READ_RTC; + p.num_data = 0; + p.s_buf = p.data; + p.r_buf = p.data; + pmgrop(&p); + + bcopy(p.data, time, 4); +} + +void +pm_set_date_time(time) + u_long time; +{ + PMData p; + + p.command = PMU_SET_RTC; + p.num_data = 4; + p.s_buf = p.r_buf = p.data; + bcopy(&time, p.data, 4); + pmgrop(&p); +} + +int +pm_read_brightness() +{ + PMData p; + + p.command = PMU_READ_BRIGHTNESS; + p.num_data = 1; /* XXX why 1? */ + p.s_buf = p.r_buf = p.data; + p.data[0] = 0; + pmgrop(&p); + + return p.data[0]; +} + +void +pm_set_brightness(val) + int val; +{ + PMData p; + + val = 0x7f - val / 2; + if (val < 0x08) + val = 0x08; + if (val > 0x78) + val = 0x78; + + p.command = PMU_SET_BRIGHTNESS; + p.num_data = 1; + p.s_buf = p.r_buf = p.data; + p.data[0] = val; + pmgrop(&p); +} + +void +pm_init_brightness() +{ + int val; + + val = pm_read_brightness(); + pm_set_brightness(val); +} + +void +pm_eject_pcmcia(slot) + int slot; +{ + PMData p; + + if (slot != 0 && slot != 1) + return; + + p.command = PMU_EJECT_PCMCIA; + p.num_data = 1; + p.s_buf = p.r_buf = p.data; + p.data[0] = 5 + slot; /* XXX */ + pmgrop(&p); +} + +int +pm_read_nvram(addr) + int addr; +{ + PMData p; + + p.command = PMU_READ_NVRAM; + p.num_data = 2; + p.s_buf = p.r_buf = p.data; + p.data[0] = addr >> 8; + p.data[1] = addr; + pmgrop(&p); + + return p.data[0]; +} + +void +pm_write_nvram(addr, val) + int addr, val; +{ + PMData p; + + p.command = PMU_WRITE_NVRAM; + p.num_data = 3; + p.s_buf = p.r_buf = p.data; + p.data[0] = addr >> 8; + p.data[1] = addr; + p.data[2] = val; + pmgrop(&p); +} diff --git a/sys/arch/powerpc/mac/pm_direct.h b/sys/arch/powerpc/mac/pm_direct.h new file mode 100644 index 00000000000..4000b820dd1 --- /dev/null +++ b/sys/arch/powerpc/mac/pm_direct.h @@ -0,0 +1,75 @@ +/* $NetBSD: pm_direct.h,v 1.5 1999/07/12 15:54:55 tsubai Exp $ */ + +/* + * 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. + */ +/* From: pm_direct.h 1.0 01/02/97 Takashi Hamada */ + +/* + * 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 __P((PMData *)); +void pm_adb_restart __P((void)); +void pm_adb_poweroff __P((void)); +void pm_read_date_time __P((u_long *)); +void pm_set_date_time __P((u_long)); +int pm_read_nvram __P((int)); +void pm_write_nvram __P((int, int)); +int pm_read_brightness __P((void)); +void pm_set_brightness __P((int)); +void pm_init_brightness __P((void)); +void pm_eject_pcmcia __P((int)); + +/* PMU commands */ +#define PMU_POWER_OFF 0x7e /* Turn Power off */ +#define PMU_RESET_CPU 0xd0 /* Reset CPU */ + +#define PMU_SET_RTC 0x30 /* Set realtime clock */ +#define PMU_READ_RTC 0x38 /* Read realtime clock */ + +#define PMU_WRITE_PRAM 0x32 /* Write PRAM */ +#define PMU_READ_PRAM 0x3a /* Read PRAM */ + +#define PMU_WRITE_NVRAM 0x33 /* Write NVRAM */ +#define PMU_READ_NVRAM 0x3b /* Read NVRAM */ + +#define PMU_EJECT_PCMCIA 0x4c /* Eject PCMCIA slot */ + +#define PMU_SET_BRIGHTNESS 0x41 /* Set backlight brightness */ +#define PMU_READ_BRIGHTNESS 0xd9 /* Read brightness button position */ diff --git a/sys/arch/powerpc/mac/viareg.h b/sys/arch/powerpc/mac/viareg.h new file mode 100644 index 00000000000..be9ff506efe --- /dev/null +++ b/sys/arch/powerpc/mac/viareg.h @@ -0,0 +1,250 @@ +/* $NetBSD: viareg.h,v 1.2 1998/10/20 14:56:30 tsubai Exp $ */ + +/*- + * Copyright (C) 1993 Allen K. Briggs, Chris P. Caputo, + * Michael L. Finch, Bradley A. Grantham, and + * Lawrence A. Kesteloot + * 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 the Alice Group. + * 4. The names of the Alice Group or any of its members may not be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE ALICE GROUP ``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 ALICE GROUP 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. + * + */ +/* + + Prototype VIA control definitions + + 06/04/92,22:33:57 BG Let's see what I can do. + +*/ + + + /* VIA1 data register A */ +#define DA1I_vSCCWrReq 0x80 +#define DA1O_vPage2 0x40 +#define DA1I_CPU_ID1 0x40 +#define DA1O_vHeadSel 0x20 +#define DA1O_vOverlay 0x10 +#define DA1O_vSync 0x08 +#define DA1O_RESERVED2 0x04 +#define DA1O_RESERVED1 0x02 +#define DA1O_RESERVED0 0x01 + + /* VIA1 data register B */ +#define DB1I_Par_Err 0x80 +#define DB1O_vSndEnb 0x80 +#define DB1O_Par_Enb 0x40 +#define DB1O_vFDesk2 0x20 +#define DB1O_vFDesk1 0x10 +#define DB1I_vFDBInt 0x08 +#define DB1O_rTCEnb 0x04 +#define DB1O_rTCCLK 0x02 +#define DB1O_rTCData 0x01 +#define DB1I_rTCData 0x01 + + /* VIA2 data register A */ +#define DA2O_v2Ram1 0x80 +#define DA2O_v2Ram0 0x40 +#define DA2I_v2IRQ0 0x40 +#define DA2I_v2IRQE 0x20 +#define DA2I_v2IRQD 0x10 +#define DA2I_v2IRQC 0x08 +#define DA2I_v2IRQB 0x04 +#define DA2I_v2IRQA 0x02 +#define DA2I_v2IRQ9 0x01 + + /* VIA2 data register B */ +#define DB2O_v2VBL 0x80 +#define DB2O_Par_Test 0x80 +#define DB2I_v2SNDEXT 0x40 +#define DB2I_v2TM0A 0x20 +#define DB2I_v2TM1A 0x10 +#define DB2I_vFC3 0x08 +#define DB2O_vFC3 0x08 +#define DB2O_v2PowerOff 0x04 +#define DB2O_v2BusLk 0x02 +#define DB2O_vCDis 0x01 +#define DB2O_CEnable 0x01 + +/* + * VIA1 interrupts + */ +#define VIA1_T1 6 +#define VIA1_T2 5 +#define VIA1_ADBCLK 4 +#define VIA1_ADBDATA 3 +#define VIA1_ADBRDY 2 +#define VIA1_VBLNK 1 +#define VIA1_ONESEC 0 + +/* VIA1 interrupt bits */ +#define V1IF_IRQ 0x80 +#define V1IF_T1 (1 << VIA1_T1) +#define V1IF_T2 (1 << VIA1_T2) +#define V1IF_ADBCLK (1 << VIA1_ADBCLK) +#define V1IF_ADBDATA (1 << VIA1_ADBDATA) +#define V1IF_ADBRDY (1 << VIA1_ADBRDY) +#define V1IF_VBLNK (1 << VIA1_VBLNK) +#define V1IF_ONESEC (1 << VIA1_ONESEC) + +/* + * VIA2 interrupts + */ +#define VIA2_T1 6 +#define VIA2_T2 5 +#define VIA2_ASC 4 +#define VIA2_SCSIIRQ 3 +#define VIA2_EXPIRQ 2 +#define VIA2_SLOTINT 1 +#define VIA2_SCSIDRQ 0 + +/* VIA2 interrupt bits */ +#define V2IF_IRQ 0x80 +#define V2IF_T1 (1 << VIA2_T1) +#define V2IF_T2 (1 << VIA2_T2) +#define V2IF_ASC (1 << VIA2_ASC) +#define V2IF_SCSIIRQ (1 << VIA2_SCSIIRQ) +#define V2IF_EXPIRQ (1 << VIA2_EXPIRQ) +#define V2IF_SLOTINT (1 << VIA2_SLOTINT) +#define V2IF_SCSIDRQ (1 << VIA2_SCSIDRQ) + +#define VIA1_INTS (V1IF_T1 | V1IF_ADBRDY) +#define VIA2_INTS (V2IF_T1 | V2IF_ASC | V2IF_SCSIIRQ | V2IF_SLOTINT | \ + V2IF_SCSIDRQ) + +#define RBV_INTS (V2IF_T1 | V2IF_ASC | V2IF_SCSIIRQ | V2IF_SLOTINT | \ + V2IF_SCSIDRQ | V1IF_ADBRDY) + +#define ACR_T1LATCH 0x40 + +extern volatile unsigned char *Via1Base; +#define VIA1_addr Via1Base /* at PA 0x50f00000 */ +#define VIA2OFF 1 /* VIA2 addr = VIA1_addr * 0x2000 */ +#define RBVOFF 0x13 /* RBV addr = VIA1_addr * 0x13000 */ + +#define VIA1 0 +#define VIA2 0 + + /* VIA interface registers */ +#define vBufA 0x1e00 /* register A */ +#define vBufB 0 /* register B */ +#define vDirA 0x0600 /* data direction register */ +#define vDirB 0x0400 /* data direction register */ +#define vT1C 0x0800 +#define vT1CH 0x0a00 +#define vT1L 0x0c00 +#define vT1LH 0x0e00 +#define vT2C 0x1000 +#define vT2CH 0x1200 +#define vSR 0x1400 /* shift register */ +#define vACR 0x1600 /* aux control register */ +#define vPCR 0x1800 /* peripheral control register */ +#define vIFR 0x1a00 /* interrupt flag register */ +#define vIER 0x1c00 /* interrupt enable register */ + + /* RBV interface registers */ +#define rBufB 0 /* register B */ +#define rBufA 2 /* register A */ +#define rIFR 0x3 /* interrupt flag register (writes?) */ +#define rIER 0x13 /* interrupt enable register */ +#define rMonitor 0x10 /* Monitor type */ +#define rSlotInt 0x12 /* Slot interrupt */ + + /* RBV monitor type flags and masks */ +#define RBVDepthMask 0x07 /* depth in bits */ +#define RBVMonitorMask 0x38 /* Type numbers */ +#define RBVOff 0x40 /* monitor turn off */ +#define RBVMonIDNone 0x38 /* What RBV actually has for no video */ +#define RBVMonIDOff 0x0 /* What rbv_vidstatus() returns for no video */ +#define RBVMonID15BWP 0x08 /* BW portrait */ +#define RBVMonIDRGB 0x10 /* color monitor */ +#define RBVMonIDRGB15 0x28 /* 15 inch RGB */ +#define RBVMonIDBW 0x30 /* No internal video */ + +#define via_reg(v, r) (*(Via1Base + (r))) + +#include <machine/pio.h> + +static __inline void +via_reg_and(ign, reg, val) + int ign, reg, val; +{ + volatile unsigned char *addr = Via1Base + reg; + + out8(addr, in8(addr) & val); +} + +static __inline void +via_reg_or(ign, reg, val) + int ign, reg, val; +{ + volatile unsigned char *addr = Via1Base + reg; + + out8(addr, in8(addr) | val); +} + +static __inline void +via_reg_xor(ign, reg, val) + int ign, reg, val; +{ + volatile unsigned char *addr = Via1Base + reg; + + out8(addr, in8(addr) ^ val); +} + +static __inline int +read_via_reg(ign, reg) + int ign, reg; +{ + volatile unsigned char *addr = Via1Base + reg; + + return in8(addr); +} + +static __inline void +write_via_reg(ign, reg, val) + int ign, reg, val; +{ + volatile unsigned char *addr = Via1Base + reg; + + out8(addr, val); +} + + + +#define vDirA_ADBState 0x30 + +void via_init __P((void)); +int rbv_vidstatus __P((void)); +void via_shutdown __P((void)); +void via_set_modem __P((int)); +int add_nubus_intr __P((int, void (*) __P((void *, int)), void *)); +void enable_nubus_intr __P((void)); +void via1_register_irq __P((int, void (*)(void *), void *)); +void via2_register_irq __P((int, void (*)(void *), void *)); + +extern void (*via1itab[7]) __P((void *)); +extern void (*via2itab[7]) __P((void *)); |