summaryrefslogtreecommitdiffstats
path: root/arch/m68k/mac
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1998-03-17 22:05:47 +0000
committerRalf Baechle <ralf@linux-mips.org>1998-03-17 22:05:47 +0000
commit27cfca1ec98e91261b1a5355d10a8996464b63af (patch)
tree8e895a53e372fa682b4c0a585b9377d67ed70d0e /arch/m68k/mac
parent6a76fb7214c477ccf6582bd79c5b4ccc4f9c41b1 (diff)
Look Ma' what I found on my harddisk ...
o New faster syscalls for 2.1.x, too o Upgrade to 2.1.89. Don't try to run this. It's flaky as hell. But feel free to debug ...
Diffstat (limited to 'arch/m68k/mac')
-rw-r--r--arch/m68k/mac/Makefile16
-rw-r--r--arch/m68k/mac/adb-bus.c2134
-rw-r--r--arch/m68k/mac/bootparse.c121
-rw-r--r--arch/m68k/mac/config.c575
-rw-r--r--arch/m68k/mac/debug.c366
-rw-r--r--arch/m68k/mac/ksyms.c7
-rw-r--r--arch/m68k/mac/macboing.c92
-rw-r--r--arch/m68k/mac/macints.c979
-rw-r--r--arch/m68k/mac/mackeyb.c765
-rw-r--r--arch/m68k/mac/via6522.c590
-rw-r--r--arch/m68k/mac/via6522.h111
11 files changed, 5756 insertions, 0 deletions
diff --git a/arch/m68k/mac/Makefile b/arch/m68k/mac/Makefile
new file mode 100644
index 000000000..458a01f44
--- /dev/null
+++ b/arch/m68k/mac/Makefile
@@ -0,0 +1,16 @@
+#
+# Makefile for Linux arch/m68k/mac source directory
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+EXTRA_CFLAGS := -Wa,-m68020
+
+O_TARGET := mac.o
+O_OBJS := config.o ksyms.o bootparse.o macints.o via6522.o \
+ mackeyb.o adb-bus.o macboing.o debug.o
+
+include $(TOPDIR)/Rules.make
diff --git a/arch/m68k/mac/adb-bus.c b/arch/m68k/mac/adb-bus.c
new file mode 100644
index 000000000..ddd5176c4
--- /dev/null
+++ b/arch/m68k/mac/adb-bus.c
@@ -0,0 +1,2134 @@
+/*
+ * MACII ADB keyboard handler.
+ * Copyright (c) 1997 Alan Cox
+ *
+ * Derived from code
+ * Copyright (C) 1996 Paul Mackerras.
+ *
+ * MSch (9/97) Partial rewrite of interrupt handler to MacII style
+ * ADB handshake, based on:
+ * - Guide to Mac Hardware
+ * - Guido Koerber's session with a logic analyzer
+ */
+
+#include <stdarg.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include "via6522.h"
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/adb.h>
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <asm/setup.h>
+#include <asm/macintosh.h>
+#include <asm/macints.h>
+
+
+#define MACII /* For now - will be a switch */
+
+/* Bits in B data register: all active low */
+#define TREQ 0x08 /* Transfer request (input) */
+#define TACK 0x10 /* Transfer acknowledge (output) */
+#define TIP 0x20 /* Transfer in progress (output) */
+
+/* Bits in B data register: ADB transaction states MacII */
+#define ST_MASK 0x30 /* mask for selecting ADB state bits */
+/* ADB transaction states according to GMHW */
+#define ST_CMD 0x00 /* ADB state: command byte */
+#define ST_EVEN 0x10 /* ADB state: even data byte */
+#define ST_ODD 0x20 /* ADB state: odd data byte */
+#define ST_IDLE 0x30 /* ADB state: idle, nothing to send */
+
+/* Bits in ACR */
+#define SR_CTRL 0x1c /* Shift register control bits */
+#ifdef USE_ORIG
+#define SR_EXT 0x1c /* Shift on external clock */
+#else
+#define SR_EXT 0x0c /* Shift on external clock */
+#endif
+#define SR_OUT 0x10 /* Shift out if 1 */
+
+/* Bits in IFR and IER */
+#define IER_SET 0x80 /* set bits in IER */
+#define IER_CLR 0 /* clear bits in IER */
+#define SR_INT 0x04 /* Shift register full/empty */
+#define SR_DATA 0x08 /* Shift register data */
+#define SR_CLOCK 0x10 /* Shift register clock */
+
+static struct adb_handler {
+ void (*handler)(unsigned char *, int, struct pt_regs *);
+} adb_handler[16];
+
+static enum adb_state {
+ idle,
+ sent_first_byte,
+ sending,
+ reading,
+ read_done,
+ awaiting_reply
+} adb_state;
+
+static struct adb_request *current_req;
+static struct adb_request *last_req;
+static unsigned char cuda_rbuf[16];
+static unsigned char *reply_ptr;
+static int reply_len;
+static int reading_reply;
+static int data_index;
+static int first_byte;
+static int prefix_len;
+
+static int status = ST_IDLE|TREQ;
+static int last_status;
+/*static int adb_delay;*/
+int in_keybinit = 1;
+
+static void adb_start(void);
+extern void adb_interrupt(int irq, void *arg, struct pt_regs *regs);
+extern void adb_cuda_interrupt(int irq, void *arg, struct pt_regs *regs);
+extern void adb_clock_interrupt(int irq, void *arg, struct pt_regs *regs);
+extern void adb_data_interrupt(int irq, void *arg, struct pt_regs *regs);
+static void adb_input(unsigned char *buf, int nb, struct pt_regs *regs);
+
+/*
+ * Misc. defines for testing
+ */
+
+extern int console_loglevel;
+
+#define ADBDEBUG_STATUS (1)
+#define ADBDEBUG_STATE (2)
+#define ADBDEBUG_READ (4)
+#define ADBDEBUG_WRITE (8)
+#define ADBDEBUG_START (16)
+#define ADBDEBUG_RETRY (32)
+#define ADBDEBUG_POLL (64)
+#define ADBDEBUG_INT (128)
+#define ADBDEBUG_PROT (256)
+#define ADBDEBUG_SRQ (512)
+#define ADBDEBUG_REQUEST (1024)
+#define ADBDEBUG_INPUT (2048)
+#define ADBDEBUG_DEVICE (4096)
+
+
+#define DEBUG_ADB
+
+#ifdef DEBUG_ADB
+#define ADBDEBUG (ADBDEBUG_READ | ADBDEBUG_START | ADBDEBUG_WRITE | ADBDEBUG_SRQ | ADBDEBUG_REQUEST)
+#else
+#define ADBDEBUG (0)
+#endif
+
+#define TRY_CUDA
+
+void adb_bus_init(void)
+{
+ unsigned long flags;
+ unsigned char c;
+
+ save_flags(flags);
+ cli();
+
+ /*
+ * Setup ADB
+ */
+
+ switch(macintosh_config->adb_type)
+ {
+
+ case MAC_ADB_II:
+ printk("adb: MacII style keyboard/mouse driver.\n");
+ /* Set the lines up. We want TREQ as input TACK|TIP as output */
+ via_write(via1, vDirB, ((via_read(via1,vDirB)|TACK|TIP)&~TREQ));
+ /*
+ * Docs suggest TREQ should be output - that seems nuts
+ * BSD agrees here :-)
+ * Setup vPCR ??
+ */
+
+#ifdef USE_ORIG
+ /* Lower the bus signals (MacII is active low it seems ???) */
+ via_write(via1, vBufB, via_read(via1, vBufB)&~TACK);
+#else
+ /* Corresponding state: idle (clear state bits) */
+ via_write(via1, vBufB, (via_read(via1, vBufB)&~ST_MASK)|ST_IDLE);
+ last_status = (via_read(via1, vBufB)&~ST_MASK);
+#endif
+ /* Shift register on input */
+ c=via_read(via1, vACR);
+ c&=~SR_CTRL; /* Clear shift register bits */
+ c|=SR_EXT; /* Shift on external clock; out or in? */
+ via_write(via1, vACR, c);
+ /* Wipe any pending data and int */
+ via_read(via1, vSR);
+
+ /* This is interrupts on enable SR for keyboard */
+ via_write(via1, vIER, IER_SET|SR_INT);
+ /* This clears the interrupt bit */
+ via_write(via1, vIFR, SR_INT);
+#if 0
+ ct=1000;
+ while( ct-- && (via_read(via1, vBufB)&TREQ))
+ udelay(1000);
+ if(ct<0)
+ printk("No sync occured\n");
+ ct=1000;
+ while( ct-- && !(via_read(via1, vIFR)&SR_INT))
+ udelay(1000);
+ if(ct<0)
+ printk("No sync 2 occured\n");
+ via_read(via1, vSR);
+ via_write(via1, vBufB, via_read(via1, vBufB)|TACK);
+ while( ct-- && !(via_read(via1, vBufB)&TREQ))
+ udelay(1000);
+ if(ct<0)
+ printk("No sync 3 occured\n");
+ ct=1000;
+ while( ct-- && !(via_read(via1, vIFR)&SR_INT))
+ udelay(1000);
+ if(ct<0)
+ printk("No sync 4 occured\n");
+ via_read(via1, vSR);
+ via_write(via1, vBufB, via_read(via1, vBufB)|TIP);
+#endif
+ /*
+ * Ok we probably ;) have a ready to use adb bus. Its also
+ * hopefully idle (Im assuming the mac didnt leave a half
+ * complete transaction on booting us).
+ */
+
+ request_irq(IRQ_MAC_ADB, adb_interrupt, IRQ_FLG_LOCK,
+ "adb interrupt", adb_interrupt);
+ adb_state = idle;
+ break;
+ /*
+ * Unsupported; but later code doesn't notice !!
+ */
+ case MAC_ADB_CUDA:
+ printk("adb: CUDA interface.\n");
+#ifdef TRY_CUDA
+ /* don't know what to set up here ... */
+ adb_state = idle;
+ /* Set the lines up. We want TREQ as input TACK|TIP as output */
+ via_write(via1, vDirB, ((via_read(via1,vDirB)|TACK|TIP)&~TREQ));
+ request_irq(IRQ_MAC_ADB, adb_cuda_interrupt, IRQ_FLG_LOCK,
+ "adb CUDA interrupt", adb_cuda_interrupt);
+ break;
+#else
+ goto nosupp;
+#endif
+ case MAC_ADB_IISI:
+ printk("adb: Using IIsi hardware.\n");
+ goto nosupp;
+ default:
+ printk("adb: Unknown hardware interface.\n");
+ nosupp:
+ printk("adb: Interface unsupported.\n");
+ restore_flags(flags);
+ return;
+ }
+
+ /*
+ * XXX: interrupt only registered if supported HW !!
+ * -> unsupported HW will just time out on keyb_init!
+ */
+#if 0
+ request_irq(IRQ_MAC_ADB, adb_interrupt, IRQ_FLG_LOCK,
+ "adb interrupt", adb_interrupt);
+#endif
+#ifdef DEBUG_ADB_INTS
+ request_irq(IRQ_MAC_ADB_CL, adb_clock_interrupt, IRQ_FLG_LOCK,
+ "adb clock interrupt", adb_clock_interrupt);
+ request_irq(IRQ_MAC_ADB_SD, adb_data_interrupt, IRQ_FLG_LOCK,
+ "adb data interrupt", adb_data_interrupt);
+#endif
+
+ printk("adb: init done.\n");
+ restore_flags(flags);
+}
+
+#define WAIT_FOR(cond, what) \
+ do { \
+ for (x = 1000; !(cond); --x) { \
+ if (x == 0) { \
+ printk("Timeout waiting for " what); \
+ return 0; \
+ } \
+ __delay(100*160); \
+ } \
+ } while (0)
+
+/*
+ * Construct and send an adb request
+ * This function is the main entry point into the ADB driver from
+ * kernel code; it takes the request data supplied and populates the
+ * adb_request structure.
+ * In order to keep this interface independent from any assumption about
+ * the underlying ADB hardware, we take requests in CUDA format here,
+ * the ADB packet 'prefixed' with a packet type code.
+ * Non-CUDA hardware is confused by this, so we strip the packet type
+ * here depending on hardware type ...
+ */
+int adb_request(struct adb_request *req, void (*done)(struct adb_request *),
+ int nbytes, ...)
+{
+ va_list list;
+ int i, start;
+
+ va_start(list, nbytes);
+
+ /*
+ * skip first byte if not CUDA
+ */
+ if (macintosh_config->adb_type != MAC_ADB_CUDA) {
+ start = va_arg(list, int);
+ nbytes--;
+ }
+ req->nbytes = nbytes;
+ req->done = done;
+#if (ADBDEBUG & ADBDEBUG_REQUEST)
+ if (console_loglevel == 10)
+ printk("adb_request, data bytes: ");
+#endif
+ for (i = 0; i < nbytes; ++i) {
+ req->data[i] = va_arg(list, int);
+#if (ADBDEBUG & ADBDEBUG_REQUEST)
+ if (console_loglevel == 10)
+ printk("%x ", req->data[i]);
+#endif
+ }
+#if (ADBDEBUG & ADBDEBUG_REQUEST)
+ if (console_loglevel == 10)
+ printk(" !\n");
+#endif
+ va_end(list);
+ /*
+ * XXX: This might be fatal if no reply is generated (i.e. Listen) !
+ * Currently, the interrupt handler 'fakes' a reply on non-TALK
+ * commands for this reason.
+ * Also, we need a CUDA_AUTOPOLL emulation here for non-CUDA
+ * Macs, and some mechanism to remember the last issued TALK
+ * request for resending it repeatedly on timeout!
+ */
+ req->reply_expected = 1;
+ return adb_send_request(req);
+}
+
+/*
+ * Construct an adb request for later sending
+ * This function only populates the adb_request structure, without
+ * actually queueing it.
+ * Reason: Poll requests and Talk requests need to be handled in a way
+ * different from 'user' requests; no reply_expected is set and
+ * Poll requests need to be placed at the head of the request queue.
+ * Using adb_request results in implicit queueing at the tail of the
+ * request queue (duplicating the Poll) with reply_expected set.
+ * No adjustment of packet data is necessary, as this mechanisnm is not
+ * used by CUDA hardware (Autopoll used instead).
+ */
+int adb_build_request(struct adb_request *req, void (*done)(struct adb_request *),
+ int nbytes, ...)
+{
+ va_list list;
+ int i;
+
+ req->nbytes = nbytes;
+ req->done = done;
+ va_start(list, nbytes);
+#if (ADBDEBUG & ADBDEBUG_REQUEST)
+ if (console_loglevel == 10)
+ printk("adb__build_request, data bytes: ");
+#endif
+ /*
+ * skip first byte if not CUDA ?
+ */
+ for (i = 0; i < nbytes; ++i) {
+ req->data[i] = va_arg(list, int);
+#if (ADBDEBUG & ADBDEBUG_REQUEST)
+ if (console_loglevel == 10)
+ printk("%x ", req->data[i]);
+#endif
+ }
+#if (ADBDEBUG & ADBDEBUG_REQUEST)
+ if (console_loglevel == 10)
+ printk(" !\n");
+#endif
+ va_end(list);
+
+ req->reply_expected = 0;
+ return 0;
+}
+
+/*
+ * Send an ADB poll (Talk, tagged on the front of the request queue)
+ */
+void adb_queue_poll(void)
+{
+ static int pod=0;
+ static int in_poll=0;
+ static struct adb_request r;
+ unsigned long flags;
+
+ if(in_poll)
+ printk("Double poll!\n");
+
+ in_poll++;
+ pod++;
+ if(pod>7) /* 15 */
+ pod=0;
+
+#if (ADBDEBUG & ADBDEBUG_POLL)
+ if (console_loglevel == 10)
+ printk("adb: Polling %d\n",pod);
+#endif
+
+ /* XXX: that's a TALK, register 0, MacII version */
+ adb_build_request(&r,NULL, 1, (pod<<4|0xC));
+
+ r.reply_expected=0;
+ r.done=NULL;
+ r.sent=0;
+ r.got_reply=0;
+ r.reply_len=0;
+ save_flags(flags);
+ cli();
+ /* Poll inserted at head of queue ... */
+ r.next=current_req;
+ current_req=&r;
+ restore_flags(flags);
+ adb_start();
+ in_poll--;
+}
+
+/*
+ * Send an ADB retransmit (Talk, appended to the request queue)
+ */
+void adb_retransmit(int device)
+{
+ static int in_retransmit=0;
+ static struct adb_request rt;
+ unsigned long flags;
+
+ if(in_retransmit)
+ printk("Double retransmit!\n");
+
+ in_retransmit++;
+
+#if (ADBDEBUG & ADBDEBUG_POLL)
+ if (console_loglevel == 10)
+ printk("adb: Sending retransmit: %d\n", device);
+#endif
+
+ /* MacII version */
+ adb_build_request(&rt,NULL, 1, (device<<4|0xC));
+
+ rt.reply_expected = 0;
+ rt.done = NULL;
+ rt.sent = 0;
+ rt.got_reply = 0;
+ rt.reply_len = 0;
+ rt.next = NULL;
+
+ save_flags(flags);
+ cli();
+
+ /* Retransmit inserted at tail of queue ... */
+
+ if (current_req != NULL)
+ {
+ last_req->next = &rt;
+ last_req = &rt;
+ }
+ else
+ {
+ current_req = &rt;
+ last_req = &rt;
+ }
+
+ /* always restart driver (send_retransmit used in place of adb_start!)*/
+
+ if (adb_state == idle)
+ adb_start();
+
+ restore_flags(flags);
+ in_retransmit--;
+}
+
+/*
+ * Queue an ADB request; start ADB transfer if necessary
+ */
+int adb_send_request(struct adb_request *req)
+{
+ unsigned long flags;
+
+ req->next = 0;
+ req->sent = 0;
+ req->got_reply = 0;
+ req->reply_len = 0;
+ save_flags(flags);
+ cli();
+
+ if (current_req != NULL)
+ {
+ last_req->next = req;
+ last_req = req;
+ }
+ else
+ {
+ current_req = req;
+ last_req = req;
+ if (adb_state == idle)
+ adb_start();
+ }
+
+ restore_flags(flags);
+ return 0;
+}
+
+static int nclock, ndata;
+
+static int need_poll = 0;
+static int command_byte = 0;
+static int last_reply = 0;
+static int last_active = 0;
+
+static struct adb_request *retry_req;
+
+/*
+ * Start sending ADB packet
+ */
+static void adb_start(void)
+{
+ unsigned long flags;
+ struct adb_request *req;
+
+ /*
+ * We get here on three 'sane' conditions:
+ * 1) called from send_adb_request, if adb_state == idle
+ * 2) called from within adb_interrupt, if adb_state == idle
+ * (after receiving, or after sending a LISTEN)
+ * 3) called from within adb_interrupt, if adb_state == sending
+ * and no reply is expected (immediate next command).
+ * Maybe we get here on SRQ as well ??
+ */
+
+ /* get the packet to send */
+ req = current_req;
+ /* assert adb_state == idle */
+ if (adb_state != idle) {
+ printk("ADB: adb_start called while driver busy (%p %x %x)!\n",
+ req, adb_state, via_read(via1, vBufB)&(ST_MASK|TREQ));
+ return;
+ }
+ if (req == 0)
+ return;
+ save_flags(flags);
+ cli();
+
+#if (ADBDEBUG & ADBDEBUG_START)
+ if (console_loglevel == 10)
+ printk("adb_start: request %p ", req);
+#endif
+
+ nclock = 0;
+ ndata = 0;
+
+ /*
+ * IRQ signaled ?? (means ADB controller wants to send, or might
+ * be end of packet if we were reading)
+ */
+ if ((via_read(via1, vBufB)& TREQ) == 0)
+ {
+ switch(macintosh_config->adb_type)
+ {
+ /*
+ * FIXME - we need to restart this on a timer
+ * or a collision at boot hangs us.
+ * Never set adb_state to idle here, or adb_start
+ * won't be called again from send_request!
+ * (need to re-check other cases ...)
+ */
+ case MAC_ADB_CUDA:
+ /* printk("device busy - fail\n"); */
+ restore_flags(flags);
+ /* a byte is coming in from the CUDA */
+ return;
+ case MAC_ADB_II:
+ /*
+ * if the interrupt handler set the need_poll
+ * flag, it's hopefully a SRQ poll or re-Talk
+ * so we try to send here anyway
+ */
+ if (!need_poll) {
+ printk("device busy - retry %p state %d status %x!\n",
+ req, adb_state, via_read(via1, vBufB)&(ST_MASK|TREQ));
+ retry_req = req;
+ /* set ADB status here ? */
+ restore_flags(flags);
+ return;
+ } else {
+#if (ADBDEBUG & ADBDEBUG_START)
+ if (console_loglevel == 10)
+ printk("device busy - polling; state %d status %x!\n",
+ adb_state, via_read(via1, vBufB)&(ST_MASK|TREQ));
+#endif
+ need_poll = 0;
+ break;
+ }
+ }
+ }
+
+#if 0
+ /*
+ * Bus idle ?? Not sure about this one; SRQ might need ST_CMD here!
+ * OTOH: setting ST_CMD in the interrupt routine would make the
+ * ADB contoller shift in before this routine starts shifting out ...
+ */
+ if ((via_read(via1, vBufB)&ST_MASK) != ST_IDLE)
+ {
+#if (ADBDEBUG & ADBDEBUG_STATE)
+ if (console_loglevel == 10)
+ printk("ADB bus not idle (%x), retry later!\n",
+ via_read(via1, vBufB)&(ST_MASK|TREQ));
+#endif
+ retry_req = req;
+ restore_flags(flags);
+ return;
+ }
+#endif
+
+ /*
+ * Another retry pending? (sanity check)
+ */
+ if (retry_req) {
+#if (ADBDEBUG & ADBDEBUG_RETRY)
+ if (console_loglevel == 10)
+ if (retry_req == req)
+ /* new requests are appended at tail of request queue */
+ printk("adb_start: retry %p pending ! \n", req);
+ else
+ /* poll requests are added to the head of queue */
+ printk("adb_start: retry %p pending, req %p (poll?) current! \n",
+ retry_req, req);
+#endif
+ retry_req = NULL;
+ }
+
+ /*
+ * Seems OK, go for it!
+ */
+ switch(macintosh_config->adb_type)
+ {
+ case MAC_ADB_CUDA:
+ /* store command byte (first byte is 'type' byte) */
+ command_byte = req->data[1];
+ /* set the shift register to shift out and send a byte */
+ via_write(via1, vACR, via_read(via1, vACR)|SR_OUT);
+ via_write(via1, vSR, req->data[0]);
+ via_write(via1, vBufB, via_read(via1, vBufB)&~TIP);
+ break;
+ case MAC_ADB_II:
+ /* store command byte */
+ command_byte = req->data[0];
+ /* Output mode */
+ via_write(via1, vACR, via_read(via1, vACR)|SR_OUT);
+ /* Load data */
+ via_write(via1, vSR, req->data[0]);
+#ifdef USE_ORIG
+ /* Turn off TIP/TACK - this should tell the external logic to
+ start the external shift clock */
+/* via_write(via1, vBufB, via_read(via1, vBufB)&~(TIP|TACK));*/
+ via_write(via1, vBufB, via_read(via1, vBufB)|(TIP|TACK));
+#else
+ /* set ADB state to 'command' */
+ via_write(via1, vBufB, (via_read(via1, vBufB)&~ST_MASK)|ST_CMD);
+#endif
+ break;
+ }
+#if (ADBDEBUG & ADBDEBUG_START)
+ if (console_loglevel == 10)
+ printk("sent first byte of %d: %x, (%x %x) ... ",
+ req->nbytes, req->data[0], adb_state,
+ (via_read(via1, vBufB) & (ST_MASK|TREQ)) );
+#endif
+ adb_state = sent_first_byte;
+ data_index = 1;
+ restore_flags(flags);
+}
+
+/*
+ * Poll the ADB state (maybe obsolete now that interrupt-driven ADB runs)
+ */
+void adb_poll(void)
+{
+ unsigned char c;
+ unsigned long flags;
+ save_flags(flags);
+ cli();
+ c=via_read(via1, vIFR);
+#if (ADBDEBUG & ADBDEBUG_POLL)
+#ifdef DEBUG_ADB_INTS
+ if (console_loglevel == 10) {
+ printk("adb_poll: IFR %x state %x cl %d dat %d ",
+ c, adb_state, nclock, ndata);
+ if (c & (SR_CLOCK|SR_DATA)) {
+ if (c & SR_CLOCK)
+ printk("adb clock event ");
+ if (c & SR_DATA)
+ printk("adb data event ");
+ }
+ }
+#else
+ if (console_loglevel == 10)
+ printk("adb_poll: IFR %x state %x ",
+ c, adb_state);
+#endif
+ if (console_loglevel == 10)
+ printk("\r");
+#endif
+ if (c & SR_INT)
+ {
+#if (ADBDEBUG & ADBDEBUG_POLL)
+ if (console_loglevel == 10)
+ printk("adb_poll: adb interrupt event\n");
+#endif
+ adb_interrupt(0, 0, 0);
+ }
+ restore_flags(flags);
+}
+
+/*
+ * Debugging gimmicks
+ */
+void adb_clock_interrupt(int irq, void *arg, struct pt_regs *regs)
+{
+ nclock++;
+}
+
+void adb_data_interrupt(int irq, void *arg, struct pt_regs *regs)
+{
+ ndata++;
+}
+
+/*
+ * The notorious ADB interrupt handler - does all of the protocol handling,
+ * except for starting new send operations. Relies heavily on the ADB
+ * controller sending and receiving data, thereby generating SR interrupts
+ * for us. This means there has to be always activity on the ADB bus, otherwise
+ * the whole process dies and has to be re-kicked by sending TALK requests ...
+ * CUDA-based Macs seem to solve this with the autopoll option, for MacII-type
+ * ADB the problem isn't solved yet (retransmit of the latest active TALK seems
+ * a good choice; either on timeout or on a timer interrupt).
+ *
+ * The basic ADB state machine was left unchanged from the original MacII code
+ * by Alan Cox, which was based on the CUDA driver for PowerMac.
+ * The syntax of the ADB status lines seems to be totally different on MacII,
+ * though. MacII uses the states Command -> Even -> Odd -> Even ->...-> Idle for
+ * sending, and Idle -> Even -> Odd -> Even ->...-> Idle for receiving. Start
+ * and end of a receive packet are signaled by asserting /IRQ on the interrupt
+ * line. Timeouts are signaled by a sequence of 4 0xFF, with /IRQ asserted on
+ * every other byte. SRQ is probably signaled by 3 or more 0xFF tacked on the
+ * end of a packet. (Thanks to Guido Koerber for eavesdropping on the ADB
+ * protocol with a logic analyzer!!)
+ * CUDA seems to use /TIP -> /TIP | TACK -> /TIP -> /TIP | TACK ... -> TIP|TACK
+ * for sending, and /TIP -> /TIP | TACK -> /TIP -> /TIP | TACK ... -> TIP for
+ * receiving. No clue how timeouts are handled; SRQ seems to be sent as a
+ * separate packet. Quite a few changes have been made outside the handshake
+ * code, so I don't know if the CUDA code still behaves as before.
+ *
+ * Note: As of 21/10/97, the MacII ADB part works including timeout detection
+ * and retransmit (Talk to the last active device). Cleanup of code and
+ * testing of the CUDA functionality is required, though.
+ * Note2: As of 13/12/97, CUDA support is definitely broken ...
+ * Next TODO: implementation of IIsi ADB protocol (maybe the USE_ORIG
+ * conditionals can be a start?)
+ */
+void adb_interrupt(int irq, void *arg, struct pt_regs *regs)
+{
+ int x, adbdir;
+ struct adb_request *req;
+
+ last_status = status;
+
+#ifdef USE_ORIG
+ status = (~via_read(via1, vBufB) & (TIP|TREQ)) | (via_read(via1, vACR) & SR_OUT);
+#else
+ if (macintosh_config->adb_type==MAC_ADB_CUDA)
+ status = (~via_read(via1, vBufB) & (TIP|TREQ)) | (via_read(via1, vACR) & SR_OUT);
+ else
+ /* status bits (0x8->0x20) and direction (0x10 ??) CLASH !! */
+ status = (via_read(via1, vBufB) & (ST_MASK|TREQ));
+#endif
+ adbdir = (via_read(via1, vACR) & SR_OUT);
+#if (ADBDEBUG & ADBDEBUG_INT)
+ if (console_loglevel == 10)
+ printk("adb_interrupt: state=%d status=%x last=%x direction=%x\n",
+ adb_state, status, last_status, adbdir);
+#endif
+
+
+ switch (adb_state)
+ {
+ case idle:
+ if(macintosh_config->adb_type==MAC_ADB_CUDA)
+ {
+ /* CUDA has sent us the first byte of data - unsolicited */
+ if (status != TREQ)
+ printk("cuda: state=idle, status=%x\n", status);
+ x = via_read(via1, vSR);
+ via_write(via1, vBufB, via_read(via1,vBufB)&~TIP);
+ }
+ else if(macintosh_config->adb_type==MAC_ADB_II)
+ {
+#if (ADBDEBUG & ADBDEBUG_STATUS)
+ if (status == TREQ && !adbdir)
+ /* that's: not IRQ, idle, input -> weird */
+ printk("adb_macII: idle, status=%x dir=%x\n",
+ status, adbdir);
+#endif
+ x = via_read(via1, vSR);
+ first_byte = x;
+#if (ADBDEBUG & ADBDEBUG_READ)
+ if (console_loglevel == 10)
+ printk("adb_macII: receiving unsol. packet: %x (%x %x) ",
+ x, adb_state, status);
+#endif
+#ifdef USE_ORIG
+ via_write(via1, vBufB, via_read(via1, vBufB)&~(TIP|TACK));
+#else
+ /* set ADB state = even for first data byte */
+ via_write(via1, vBufB, (via_read(via1, vBufB)&~ST_MASK)|ST_EVEN);
+#endif
+ }
+ adb_state = reading;
+ reply_ptr = cuda_rbuf;
+ reply_len = 0;
+ reading_reply = 0;
+ prefix_len = 0;
+ if (macintosh_config->adb_type==MAC_ADB_II) {
+ *reply_ptr++ = ADB_PACKET;
+ *reply_ptr++ = first_byte;
+ *reply_ptr++ = command_byte; /*first_byte;*/
+ reply_len = 3;
+ prefix_len = 3;
+ }
+ break;
+
+ case awaiting_reply:
+ if(macintosh_config->adb_type==MAC_ADB_CUDA)
+ {
+ /* CUDA has sent us the first byte of data of a reply */
+ if (status != TREQ)
+ printk("cuda: state=awaiting_reply, status=%x\n", status);
+ x = via_read(via1, vSR);
+ via_write(via1,vBufB,
+ via_read(via1, vBufB)&~TIP);
+ } else if(macintosh_config->adb_type==MAC_ADB_II) {
+ /* handshake etc. for II ?? */
+ x = via_read(via1, vSR);
+ first_byte = x;
+#if (ADBDEBUG & ADBDEBUG_READ)
+ if (console_loglevel == 10)
+ printk("adb_macII: reading reply: %x (%x %x) ",
+ x, adb_state, status);
+#endif
+#ifdef USE_ORIG
+ via_write(via1, vBufB, via_read(via1, vBufB)&~(TIP|TACK));
+#else
+ /* set ADB state = even for first data byte */
+ via_write(via1, vBufB, (via_read(via1, vBufB)&~ST_MASK)|ST_EVEN);
+#endif
+ }
+ adb_state = reading;
+ reply_ptr = current_req->reply;
+ reading_reply = 1;
+ reply_len = 0;
+ prefix_len = 0;
+ if (macintosh_config->adb_type==MAC_ADB_II) {
+ *reply_ptr++ = ADB_PACKET;
+ *reply_ptr++ = first_byte;
+ *reply_ptr++ = first_byte; /* should be command byte */
+ reply_len = 3;
+ prefix_len = 3;
+ }
+ break;
+
+ case sent_first_byte:
+ if(macintosh_config->adb_type==MAC_ADB_CUDA)
+ {
+ if (status == TREQ + TIP + SR_OUT)
+ {
+ /* collision */
+ via_write(via1, vACR,
+ via_read(via1, vACR)&~SR_OUT);
+ x = via_read(via1, vSR);
+ via_write(via1, vBufB,
+ via_read(via1,vBufB)|TIP|TACK);
+ adb_state = idle;
+ }
+ else
+ {
+ /* assert status == TIP + SR_OUT */
+ if (status != TIP + SR_OUT)
+ printk("cuda: state=sent_first_byte status=%x\n", status);
+ via_write(via1,vSR,current_req->data[1]);
+ via_write(via1, vBufB,
+ via_read(via1, vBufB)^TACK);
+ data_index = 2;
+ adb_state = sending;
+ }
+ }
+ else if(macintosh_config->adb_type==MAC_ADB_II)
+ {
+ /* how to detect a collision here ?? */
+#if (ADBDEBUG & ADBDEBUG_WRITE)
+ if (console_loglevel == 10)
+ printk(" sending: %x (%x %x) ",
+ current_req->data[1], adb_state, status);
+#endif
+ /* maybe we're already done (Talk, or Poll)? */
+ if (data_index >= current_req->nbytes)
+ {
+ /* assert it's a Talk ?? */
+ if ( (command_byte&0xc) != 0xc
+ && console_loglevel == 10 )
+ printk("ADB: single byte command, no Talk: %x!\n",
+ command_byte);
+#if (ADBDEBUG & ADBDEBUG_WRITE)
+ if (console_loglevel == 10)
+ printk(" -> end (%d of %d) (%x %x)!\n",
+ data_index, current_req->nbytes, adb_state, status);
+#endif
+ current_req->sent = 1;
+ if (current_req->reply_expected)
+ {
+#if (ADBDEBUG & ADBDEBUG_WRITE)
+ if (console_loglevel == 10)
+ printk("ADB: reply expected on poll!\n");
+#endif
+ adb_state = awaiting_reply;
+ reading_reply = 0;
+ } else {
+#if (ADBDEBUG & ADBDEBUG_WRITE)
+ if (console_loglevel == 10)
+ printk("ADB: no reply for poll, not calling done()!\n");
+#endif
+ req = current_req;
+ current_req = req->next;
+#if 0 /* XXX Not sure about that one ... probably better enabled */
+ if (req->done)
+ (*req->done)(req);
+#endif
+ adb_state = idle;
+ reading_reply = 0;
+ }
+ /* set to shift in */
+ via_write(via1, vACR,
+ via_read(via1, vACR) & ~SR_OUT);
+ x=via_read(via1, vSR);
+#ifdef USE_ORIG
+ via_write(via1, vBufB,
+ via_read(via1, vBufB)|TACK|TIP);
+#else
+ /* set ADB state idle - might get SRQ */
+ via_write(via1, vBufB,
+ (via_read(via1, vBufB)&~ST_MASK)|ST_IDLE);
+#endif
+ break;
+ }
+#if (ADBDEBUG & ADBDEBUG_STATUS)
+ if(!(status==(ST_CMD|TREQ) && adbdir == SR_OUT))
+ printk("adb_macII: sent_first_byte, weird status=%x dir=%x\n",
+ status, adbdir);
+#endif
+ /* SR already set to shift out; send byte */
+ via_write(via1, vSR, current_req->data[1]);
+#ifdef USE_ORIG
+ via_write(via1, vBufB,
+ via_read(via1, vBufB)^TACK);
+#else
+ /* set state to ST_EVEN (first byte was: ST_CMD) */
+ via_write(via1, vBufB,
+ (via_read(via1, vBufB)&~ST_MASK)|ST_EVEN);
+#endif
+ data_index=2;
+ adb_state = sending;
+ }
+ break;
+
+ case sending:
+ req = current_req;
+ if (data_index >= req->nbytes)
+ {
+ /* end of packet */
+ if(macintosh_config->adb_type==MAC_ADB_CUDA)
+ {
+ via_write(via1, vACR,
+ via_read(via1, vACR)&~SR_OUT);
+ x = via_read(via1, vSR);
+ via_write(via1, vBufB,
+ via_read(via1,vBufB)|TACK|TIP);
+ }
+ else if(macintosh_config->adb_type==MAC_ADB_II)
+ {
+ /*
+ * XXX Not sure: maybe only switch to
+ * input mode on Talk ??
+ */
+#if (ADBDEBUG & ADBDEBUG_WRITE)
+ if (console_loglevel == 10)
+ printk(" -> end (%d of %d) (%x %x)!\n",
+ data_index-1, req->nbytes, adb_state, status);
+#endif
+ /* set to shift in */
+ via_write(via1, vACR,
+ via_read(via1, vACR) & ~SR_OUT);
+ x=via_read(via1, vSR);
+#ifdef USE_ORIG
+ via_write(via1, vBufB,
+ via_read(via1, vBufB)|TACK|TIP);
+#else
+ /* set ADB state idle - might get SRQ */
+ via_write(via1, vBufB,
+ (via_read(via1, vBufB)&~ST_MASK)|ST_IDLE);
+#endif
+ }
+ req->sent = 1;
+ if (req->reply_expected)
+ {
+ /*
+ * maybe fake a reply here on Listen ??
+ * Otherwise, a Listen hangs on success
+ */
+ if ( ((req->data[0]&0xc) == 0xc) )
+ adb_state = awaiting_reply;
+ else {
+ /*
+ * Reply expected, but none
+ * possible -> fake reply.
+ * Problem: sending next command
+ * should probably be done
+ * without setting bus to 'idle'!
+ * (except if no more commands)
+ */
+#if (ADBDEBUG & ADBDEBUG_PROT)
+ printk("ADB: reply expected on Listen, faking reply\n");
+#endif
+ /* make it look weird */
+ /* XXX: return reply_len -1? */
+ /* XXX: fake ADB header? */
+ req->reply[0] = req->reply[1] = req->reply[2] = 0xFF;
+ req->reply_len = 3;
+ req->got_reply = 1;
+ current_req = req->next;
+ if (req->done)
+ (*req->done)(req);
+ /*
+ * ready with this one, run
+ * next command or repeat last
+ * Talk (=idle on II)
+ */
+ /* set state to idle !! */
+ adb_state = idle;
+ if (current_req || retry_req)
+ adb_start();
+ }
+ }
+ else
+ {
+ current_req = req->next;
+ if (req->done)
+ (*req->done)(req);
+ /* not sure about this */
+ /*
+ * MS: Must set idle, no new request
+ * started else !
+ */
+ adb_state = idle;
+ /*
+ * requires setting ADB state to idle,
+ * maybe read a byte ! (done above)
+ */
+ if (current_req || retry_req)
+ adb_start();
+ }
+ }
+ else
+ {
+ if(macintosh_config->adb_type==MAC_ADB_CUDA)
+ {
+ via_write(via1, vSR, req->data[data_index++]);
+ via_write(via1, vBufB,
+ via_read(via1, vBufB)^TACK);
+ }
+ else if(macintosh_config->adb_type==MAC_ADB_II)
+ {
+#if (ADBDEBUG & ADBDEBUG_WRITE)
+ if (console_loglevel == 10)
+ printk(" %x (%x %x) ",
+ req->data[data_index], adb_state, status);
+#endif
+ via_write(via1, vSR, req->data[data_index++]);
+#ifdef USE_ORIG
+ via_write(via1, vBufB,
+ via_read(via1, vBufB)^TACK);
+#else
+ /* invert state bits, toggle ODD/EVEN */
+ x = via_read(via1, vBufB);
+ via_write(via1, vBufB,
+ (x&~ST_MASK)|~(x&ST_MASK));
+#endif
+ }
+ }
+ break;
+
+ case reading:
+#ifdef POLL_ON_TIMEOUT
+ if((reply_len-prefix_len)==3 && memcmp(reply_ptr-3,"\xFF\xFF\xFF",3)==0)
+#else
+ if( (first_byte == 0xFF && (reply_len-prefix_len)==2
+ && memcmp(reply_ptr-2,"\xFF\xFF",2)==0) ||
+ ((reply_len-prefix_len)==3
+ && memcmp(reply_ptr-3,"\xFF\xFF\xFF",3)==0))
+#endif
+ {
+ /*
+ * possible timeout (in fact, most probably a
+ * timeout, since SRQ can't be signaled without
+ * transfer on the bus).
+ * The last three bytes seen were FF, together
+ * with the starting byte (in case we started
+ * on 'idle' or 'awaiting_reply') this probably
+ * makes four. So this is mostl likely #5!
+ * The timeout signal is a pattern 1 0 1 0 0..
+ * on /INT, meaning we missed it :-(
+ */
+ x = via_read(via1, vSR);
+ if (x != 0xFF)
+ printk("ADB: mistaken timeout/SRQ!\n");
+
+ /*
+ * ADB status bits: either even or odd.
+ * adb_state: need to set 'idle' here.
+ * Maybe saner: set 'need_poll' or
+ * 'need_resend' here, fall through to
+ * read_done ??
+ */
+#if (ADBDEBUG & ADBDEBUG_READ)
+ if (console_loglevel == 10)
+ printk(" -> read aborted: %x (%x %x)!\n",
+ x, adb_state, status);
+#endif
+
+#ifdef USE_ORIG
+ via_write(via1, vBufB,
+ via_read(via1, vBufB)|TACK|TIP);
+#else
+#if 0 /* XXX leave status unchanged!! - need to check this again! */
+ /* set ADB state to idle (required by adb_start()) */
+ via_write(via1, vBufB,
+ (via_read(via1, vBufB)&~ST_MASK)|ST_IDLE);
+#endif
+#endif
+
+ /*
+ * What if the timeout happens on reading a
+ * reply ?? Assemble error reply and call
+ * current_request->done()? Keep request
+ * on queue?
+ */
+
+ /* prevent 'busy' in adb_start() */
+ need_poll = 1;
+
+ /*
+ * Timeout: /IRQ alternates high/low during
+ * 4 'FF' bytes (1 0 1 0 0...)
+ * We're on byte 5, so we need one
+ * more backlog here (TBI) ....
+ */
+ if ((status&TREQ) != (last_status&TREQ)) {
+#if (ADBDEBUG & ADBDEBUG_SRQ)
+ if (console_loglevel == 10)
+ printk("ADB: reply timeout, resending!\n");
+#endif
+ /*
+ * first byte received should be the
+ * command byte timing out !!
+ */
+ if (first_byte != 0xff)
+ command_byte = first_byte;
+
+ /*
+ * compute target for retransmit: if
+ * last_active is set, use that one,
+ * else use command_byte
+ */
+ if (last_active == -1)
+ last_active = (command_byte&0xf0)>>4;
+ adb_state = idle;
+ /* resend if TALK, don't poll! */
+ if (current_req)
+ adb_start();
+ else
+ /*
+ * XXX: need to count the timeouts ??
+ * restart last active TALK ??
+ * If no current_req, reuse old one!
+ */
+ adb_retransmit(last_active);
+
+ } else {
+ /*
+ * SRQ: NetBSD suggests /IRQ is asserted!?
+ */
+ if (status&TREQ)
+ printk("ADB: SRQ signature w/o /INT!\n");
+#if (ADBDEBUG & ADBDEBUG_SRQ)
+ if (console_loglevel == 10)
+ printk("ADB: empty SRQ packet!\n");
+#endif
+ /* Terminate the SRQ packet and poll */
+ adb_state = idle;
+ adb_queue_poll();
+ }
+ /*
+ * Leave ADB status lines unchanged (means /IRQ
+ * will still be low when entering adb_start!)
+ */
+ break;
+ }
+ if((reply_len-prefix_len)>3 && memcmp(reply_ptr-3,"\xFF\xFF\xFF",3)==0)
+ {
+ /* SRQ tacked on data packet */
+ /* Check /IRQ here ?? */
+#if (ADBDEBUG & ADBDEBUG_SRQ)
+ if (console_loglevel == 10)
+ printk("\nADB: Packet with SRQ!\n");
+#endif
+ /* Terminate the packet (SRQ never ends) */
+ x = via_read(via1, vSR);
+ adb_state = read_done;
+ reply_len -= 3;
+ reply_ptr -= 3;
+ need_poll = 1;
+ /* need to continue; next byte not seen else */
+ /*
+ * XXX: not at all sure here; maybe need to
+ * send away the reply and poll immediately?
+ */
+ } else {
+ /* Sanity check */
+ if(reply_len>15)
+ reply_len=0;
+ /* read byte */
+ *reply_ptr = via_read(via1, vSR);
+ x = *reply_ptr;
+#if (ADBDEBUG & ADBDEBUG_READ)
+ if (console_loglevel == 10)
+ printk(" %x (%x %x) ",
+ *reply_ptr, adb_state, status);
+#endif
+ reply_ptr++;
+ reply_len++;
+ }
+ /* The usual handshake ... */
+ if(macintosh_config->adb_type==MAC_ADB_CUDA)
+ {
+ if (status == TIP)
+ {
+ /* that's all folks */
+ via_write(via1, vBufB,
+ via_read(via1, vBufB)|TACK|TIP);
+ adb_state = read_done;
+ }
+ else
+ {
+ /* assert status == TIP | TREQ */
+ if (status != TIP + TREQ)
+ printk("cuda: state=reading status=%x\n", status);
+ via_write(via1, vBufB,
+ via_read(via1, vBufB)^TACK);
+ }
+ }
+ if(macintosh_config->adb_type==MAC_ADB_II)
+ {
+ /*
+ * NetBSD hints that the next to last byte
+ * is sent with IRQ !!
+ * Guido found out it's the last one (0x0),
+ * but IRQ should be asserted already.
+ * Problem with timeout detection: First
+ * transition to /IRQ might be second
+ * byte of timeout packet!
+ * Timeouts are signaled by 4x FF.
+ */
+ if(!(status&TREQ) && x == 0x00) /* != 0xFF */
+ {
+#if (ADBDEBUG & ADBDEBUG_READ)
+ if (console_loglevel == 10)
+ printk(" -> read done!\n");
+#endif
+#ifdef USE_ORIG
+ via_write(via1, vBufB,
+ via_read(via1, vBufB)|TACK|TIP);
+#else
+#if 0 /* XXX: we take one more byte (why?), so handshake! */
+ /* set ADB state to idle */
+ via_write(via1, vBufB,
+ (via_read(via1, vBufB)&~ST_MASK)|ST_IDLE);
+#else
+ /* invert state bits, toggle ODD/EVEN */
+ x = via_read(via1, vBufB);
+ via_write(via1, vBufB,
+ (x&~ST_MASK)|~(x&ST_MASK));
+#endif
+#endif
+ /* adjust packet length */
+ reply_len--;
+ reply_ptr--;
+ adb_state = read_done;
+ }
+ else
+ {
+#if (ADBDEBUG & ADBDEBUG_STATUS)
+ if(status!=TIP+TREQ)
+ printk("macII_adb: state=reading status=%x\n", status);
+#endif
+#ifdef USE_ORIG
+ via_write(via1, vBufB,
+ via_read(via1, vBufB)^TACK);
+#else
+ /* not caught: ST_CMD */
+ /* required for re-entry 'reading'! */
+ if ((status&ST_MASK) == ST_IDLE) {
+ /* (in)sanity check - set even */
+ via_write(via1, vBufB,
+ (via_read(via1, vBufB)&~ST_MASK)|ST_EVEN);
+ } else {
+ /* invert state bits, toggle ODD/EVEN */
+ x = via_read(via1, vBufB);
+ via_write(via1, vBufB,
+ (x&~ST_MASK)|~(x&ST_MASK));
+ }
+#endif
+ }
+ }
+ break;
+
+ case read_done:
+ x = via_read(via1, vSR);
+#if (ADBDEBUG & ADBDEBUG_READ)
+ if (console_loglevel == 10)
+ printk("ADB: read done: %x (%x %x)!\n",
+ x, adb_state, status);
+#endif
+ if (reading_reply)
+ {
+ req = current_req;
+ req->reply_len = reply_ptr - req->reply;
+ req->got_reply = 1;
+ current_req = req->next;
+ if (req->done)
+ (*req->done)(req);
+ }
+ else
+ {
+ adb_input(cuda_rbuf, reply_ptr - cuda_rbuf, regs);
+ }
+
+ /*
+ * remember this device ID; it's the latest we got a
+ * reply from!
+ */
+ last_reply = command_byte;
+ last_active = (command_byte&0xf0)>>4;
+
+
+ /*
+ * Assert status = ST_IDLE ??
+ */
+ /*
+ * SRQ seen before, initiate poll now
+ */
+ if (need_poll) {
+#if (ADBDEBUG & ADBDEBUG_POLL)
+ if (console_loglevel == 10)
+ printk("ADB: initiate poll!\n");
+#endif
+ adb_state = idle;
+ /*
+ * set ADB status bits?? (unchanged above!)
+ */
+ adb_queue_poll();
+ need_poll = 0;
+ /* hope this is ok; queue_poll runs adb_start */
+ break;
+ }
+
+#ifdef USE_ORIG
+ /*
+ * This will fail - TREQ is active low -> 0 is IRQ !!
+ */
+ if (status == TREQ)
+ {
+ via_write(via1, vBufB,
+ via_read(via1, vBufB)|~TIP);
+#else
+ /*
+ * /IRQ seen, so the ADB controller has data for us
+ */
+ if (!(status&TREQ))
+ {
+ /* set ADB state to idle */
+ via_write(via1, vBufB,
+ (via_read(via1, vBufB)&~ST_MASK)|ST_IDLE);
+#endif
+ adb_state = reading;
+ reply_ptr = cuda_rbuf;
+ reply_len = 0;
+ prefix_len = 0;
+ if (macintosh_config->adb_type==MAC_ADB_II) {
+ *reply_ptr++ = ADB_PACKET;
+ *reply_ptr++ = command_byte;
+ reply_len = 2;
+ prefix_len = 2;
+ }
+ reading_reply = 0;
+ }
+ else
+ {
+ /*
+ * no IRQ, send next packet or wait
+ */
+ adb_state = idle;
+ if (current_req)
+ adb_start();
+ else
+ adb_retransmit(last_active);
+ }
+ break;
+
+ default:
+#if (ADBDEBUG & ADBDEBUG_STATE)
+ printk("adb_interrupt: unknown adb_state %d?\n", adb_state);
+#endif
+ }
+}
+
+/*
+ * Restart of CUDA support: please modify this interrupt handler while
+ * working at the Quadra etc. ADB driver. We can try to merge them later, or
+ * remove the CUDA stuff from the MacII handler
+ */
+
+void adb_cuda_interrupt(int irq, void *arg, struct pt_regs *regs)
+{
+ int x, status;
+ struct adb_request *req;
+
+ status = (~via_read(via1, vBufB) & (TIP|TREQ)) | (via_read(via1, vACR) & SR_OUT);
+ if (console_loglevel == 10)
+ printk("adb_interrupt: state=%d status=%x\n", adb_state, status);
+
+ switch (adb_state)
+ {
+ case idle:
+ if(macintosh_config->adb_type==MAC_ADB_CUDA)
+ {
+ /* CUDA has sent us the first byte of data - unsolicited */
+ if (status != TREQ)
+ printk("cuda: state=idle, status=%x want=%x\n",
+ status, TREQ);
+ x = via_read(via1, vSR);
+ via_write(via1, vBufB, via_read(via1,vBufB)&~TIP);
+ }
+ else if(macintosh_config->adb_type==MAC_ADB_II)
+ {
+ if (status != TREQ)
+ printk("adb_macII: state=idle status=%x want=%x\n",
+ status, TREQ);
+ x = via_read(via1, vSR);
+ via_write(via1, vBufB, via_read(via1, vBufB)&~(TIP|TACK));
+ }
+ adb_state = reading;
+ reply_ptr = cuda_rbuf;
+ reply_len = 0;
+ reading_reply = 0;
+ break;
+
+ case awaiting_reply:
+ if(macintosh_config->adb_type==MAC_ADB_CUDA)
+ {
+ /* CUDA has sent us the first byte of data of a reply */
+ if (status != TREQ)
+ printk("cuda: state=awaiting_reply, status=%x want=%x\n",
+ status, TREQ);
+ x = via_read(via1, vSR);
+ via_write(via1,vBufB,
+ via_read(via1, vBufB)&~TIP);
+ }
+ adb_state = reading;
+ reply_ptr = current_req->reply;
+ reading_reply = 1;
+ reply_len = 0;
+ break;
+
+ case sent_first_byte:
+ if(macintosh_config->adb_type==MAC_ADB_CUDA)
+ {
+ if (status == TREQ + TIP + SR_OUT)
+ {
+ /* collision */
+ if (console_loglevel == 10)
+ printk("cuda: send collision!\n");
+ via_write(via1, vACR,
+ via_read(via1, vACR)&~SR_OUT);
+ x = via_read(via1, vSR);
+ via_write(via1, vBufB,
+ via_read(via1,vBufB)|TIP|TACK);
+ adb_state = idle;
+ }
+ else
+ {
+ /* assert status == TIP + SR_OUT */
+ if (status != TIP + SR_OUT)
+ printk("cuda: state=sent_first_byte status=%x want=%x\n",
+ status, TIP + SR_OUT);
+ via_write(via1,vSR,current_req->data[1]);
+ via_write(via1, vBufB,
+ via_read(via1, vBufB)^TACK);
+ data_index = 2;
+ adb_state = sending;
+ }
+ }
+ else if(macintosh_config->adb_type==MAC_ADB_II)
+ {
+ if(status!=TIP+SR_OUT)
+ printk("adb_macII: state=send_first_byte status=%x want=%x\n",
+ status, TIP+SR_OUT);
+ via_write(via1, vSR, current_req->data[1]);
+ via_write(via1, vBufB,
+ via_read(via1, vBufB)^TACK);
+ data_index=2;
+ adb_state = sending;
+ }
+ break;
+
+ case sending:
+ req = current_req;
+ if (data_index >= req->nbytes)
+ {
+ if(macintosh_config->adb_type==MAC_ADB_CUDA)
+ {
+ via_write(via1, vACR,
+ via_read(via1, vACR)&~SR_OUT);
+ x = via_read(via1, vSR);
+ via_write(via1, vBufB,
+ via_read(via1,vBufB)|TACK|TIP);
+ }
+ else if(macintosh_config->adb_type==MAC_ADB_II)
+ {
+ via_write(via1, vACR,
+ via_read(via1, vACR) & ~SR_OUT);
+ x=via_read(via1, vSR);
+ via_write(via1, vBufB,
+ via_read(via1, vBufB)|TACK|TIP);
+ }
+ req->sent = 1;
+ if (req->reply_expected)
+ {
+ adb_state = awaiting_reply;
+ }
+ else
+ {
+ current_req = req->next;
+ if (req->done)
+ (*req->done)(req);
+ /* not sure about this */
+ adb_state = idle;
+ adb_start();
+ }
+ }
+ else
+ {
+ if(macintosh_config->adb_type==MAC_ADB_CUDA)
+ {
+ via_write(via1, vSR, req->data[data_index++]);
+ via_write(via1, vBufB,
+ via_read(via1, vBufB)^TACK);
+ }
+ else if(macintosh_config->adb_type==MAC_ADB_II)
+ {
+ via_write(via1, vSR, req->data[data_index++]);
+ via_write(via1, vBufB,
+ via_read(via1, vBufB)^TACK);
+ }
+ }
+ break;
+
+ case reading:
+ if(reply_len==3 && memcmp(reply_ptr-3,"\xFF\xFF\xFF",3)==0)
+ {
+ /* Terminate the SRQ packet */
+ printk("CUDA: Got an SRQ\n");
+ adb_state = idle;
+ adb_queue_poll();
+ break;
+ }
+ /* Sanity check - botched in orig. code! */
+ if(reply_len>15) {
+ printk("CUDA: reply buffer overrun!\n");
+ /* wrap buffer */
+ reply_len=0;
+ if (reading_reply)
+ reply_ptr = current_req->reply;
+ else
+ reply_ptr = cuda_rbuf;
+ }
+ *reply_ptr = via_read(via1, vSR);
+ if (console_loglevel == 10)
+ printk(" %p-> %x (%x %x) ",
+ reply_ptr, *reply_ptr, adb_state, status);
+ reply_ptr++;
+ reply_len++;
+ if(macintosh_config->adb_type==MAC_ADB_CUDA)
+ {
+ if (status == TIP)
+ {
+ /* that's all folks */
+ via_write(via1, vBufB,
+ via_read(via1, vBufB)|TACK|TIP);
+ adb_state = read_done;
+ }
+ else
+ {
+ /* assert status == TIP | TREQ */
+ if (status != TIP + TREQ)
+ printk("cuda: state=reading status=%x want=%x\n",
+ status, TIP + TREQ);
+ via_write(via1, vBufB,
+ via_read(via1, vBufB)^TACK);
+ }
+ }
+ if(macintosh_config->adb_type==MAC_ADB_II)
+ {
+ if( status == TIP)
+ {
+ via_write(via1, vBufB,
+ via_read(via1, vBufB)|TACK|TIP);
+ adb_state = read_done;
+ }
+ else
+ {
+ if(status!=TIP+TREQ)
+ printk("macII_adb: state=reading status=%x\n", status);
+ via_write(via1, vBufB,
+ via_read(via1, vBufB)^TACK);
+ }
+ }
+ break;
+
+ case read_done:
+ x = via_read(via1, vSR);
+ if (reading_reply)
+ {
+ req = current_req;
+ req->reply_len = reply_ptr - req->reply;
+ req->got_reply = 1;
+ current_req = req->next;
+ if (req->done)
+ (*req->done)(req);
+ }
+ else
+ {
+ adb_input(cuda_rbuf, reply_ptr - cuda_rbuf, regs);
+ }
+
+ if (status == TREQ)
+ {
+ via_write(via1, vBufB,
+ via_read(via1, vBufB)|~TIP);
+ adb_state = reading;
+ reply_ptr = cuda_rbuf;
+ reading_reply = 0;
+ }
+ else
+ {
+ adb_state = idle;
+ adb_start();
+ }
+ break;
+
+ default:
+ printk("adb_interrupt: unknown adb_state %d?\n", adb_state);
+ }
+}
+
+/*
+ * The 'reply delivery' routine; determines which device sent the
+ * request and calls the appropriate handler.
+ * Reply data are expected in CUDA format (again, argh...) so we need
+ * to fake this in the interrupt handler for MacII.
+ * Only one handler per device ID is currently possible.
+ * XXX: is the ID field here representing the default or real ID?
+ */
+static void adb_input(unsigned char *buf, int nb, struct pt_regs *regs)
+{
+ int i, id;
+
+ switch (buf[0])
+ {
+ case ADB_PACKET:
+ /* what's in buf[1] ?? */
+ id = buf[2] >> 4;
+#if 0
+ xmon_printf("adb packet: ");
+ for (i = 0; i < nb; ++i)
+ xmon_printf(" %x", buf[i]);
+ xmon_printf(", id = %d\n", id);
+#endif
+#if (ADBDEBUG & ADBDEBUG_INPUT)
+ if (console_loglevel == 10) {
+ printk("adb_input: adb packet ");
+ for (i = 0; i < nb; ++i)
+ printk(" %x", buf[i]);
+ printk(", id = %d\n", id);
+ }
+#endif
+ if (adb_handler[id].handler != 0)
+ {
+ (*adb_handler[id].handler)(buf, nb, regs);
+ }
+ break;
+
+ default:
+#if (ADBDEBUG & ADBDEBUG_INPUT)
+ if (console_loglevel == 10) {
+ printk("adb_input: data from via (%d bytes):", nb);
+ for (i = 0; i < nb; ++i)
+ printk(" %.2x", buf[i]);
+ printk("\n");
+ }
+#endif
+ }
+}
+
+/* Ultimately this should return the number of devices with
+ the given default id. */
+
+int adb_register(int default_id,
+ void (*handler)(unsigned char *, int, struct pt_regs *))
+{
+ if (adb_handler[default_id].handler != 0)
+ panic("Two handlers for ADB device %d\n", default_id);
+ adb_handler[default_id].handler = handler;
+ return 1;
+}
+
+/*
+ * /dev/adb device driver.
+ */
+
+#define ADB_MAJOR 56 /* major number for /dev/adb */
+
+#define ADB_MAX_MINOR 64 /* range of ADB minors */
+#define ADB_TYPE_SHIFT 4 /* # bits for device ID/type in subdevices */
+
+#define ADB_TYPE_RAW 0 /* raw device; unbuffered */
+#define ADB_TYPE_BUFF 1 /* raw device; buffered */
+#define ADB_TYPE_COOKED 2 /* 'cooked' device */
+
+
+extern void adbdev_init(void);
+
+struct adbdev_state {
+ struct adb_request req;
+};
+
+static struct wait_queue *adb_wait;
+
+static int adb_wait_reply(struct adbdev_state *state, struct file *file)
+{
+ int ret = 0;
+ struct wait_queue wait = { current, NULL };
+
+ add_wait_queue(&adb_wait, &wait);
+ current->state = TASK_INTERRUPTIBLE;
+
+ while (!state->req.got_reply) {
+ if (file->f_flags & O_NONBLOCK) {
+ ret = -EAGAIN;
+ break;
+ }
+ if (signal_pending(current)) {
+ ret = -ERESTARTSYS;
+ break;
+ }
+ schedule();
+ }
+
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&adb_wait, &wait);
+
+ return ret;
+}
+
+static void adb_write_done(struct adb_request *req)
+{
+ if (!req->got_reply) {
+ req->reply_len = 0;
+ req->got_reply = 1;
+ }
+ wake_up_interruptible(&adb_wait);
+}
+
+struct file_operations *adb_raw[16];
+struct file_operations *adb_buffered[16];
+struct file_operations *adb_cooked[16];
+
+static int adb_open(struct inode *inode, struct file *file)
+{
+ int adb_type, adb_subtype;
+ struct adbdev_state *state;
+
+ if (MINOR(inode->i_rdev) > ADB_MAX_MINOR)
+ return -ENXIO;
+
+ switch (MINOR(inode->i_rdev) >> ADB_TYPE_SHIFT) {
+ case ADB_TYPE_RAW:
+ /* see code below */
+ break;
+ case ADB_TYPE_BUFF:
+ /* TBI */
+ return -ENXIO;
+ case ADB_TYPE_COOKED:
+ /* subtypes such as kbd, mouse, ... */
+ adb_subtype = MINOR(inode->i_rdev) & ~ADB_TYPE_SHIFT;
+ if ((file->f_op = adb_cooked[adb_subtype]))
+ return file->f_op->open(inode,file);
+ else
+ return -ENODEV;
+ }
+
+ state = kmalloc(sizeof(struct adbdev_state), GFP_KERNEL);
+ if (state == 0)
+ return -ENOMEM;
+ file->private_data = state;
+ state->req.reply_expected = 0;
+ return 0;
+}
+
+static void adb_release(struct inode *inode, struct file *file)
+{
+ struct adbdev_state *state = file->private_data;
+
+ if (state) {
+ file->private_data = NULL;
+ if (state->req.reply_expected && !state->req.got_reply)
+ if (adb_wait_reply(state, file))
+ return;
+ kfree(state);
+ }
+ return;
+}
+
+static int adb_lseek(struct inode *inode, struct file *file,
+ off_t offset, int origin)
+{
+ return -ESPIPE;
+}
+
+static int adb_read(struct inode *inode, struct file *file,
+ char *buf, int count)
+{
+ int ret;
+ struct adbdev_state *state = file->private_data;
+
+ if (count < 2)
+ return -EINVAL;
+ if (count > sizeof(state->req.reply))
+ count = sizeof(state->req.reply);
+ ret = verify_area(VERIFY_WRITE, buf, count);
+ if (ret)
+ return ret;
+
+ if (!state->req.reply_expected)
+ return 0;
+
+ ret = adb_wait_reply(state, file);
+ if (ret)
+ return ret;
+
+ state->req.reply_expected = 0;
+ ret = state->req.reply_len;
+ copy_to_user(buf, state->req.reply, ret);
+
+ return ret;
+}
+
+static int adb_write(struct inode *inode, struct file *file,
+ const char *buf, int count)
+{
+ int ret, i;
+ struct adbdev_state *state = file->private_data;
+
+ if (count < 2 || count > sizeof(state->req.data))
+ return -EINVAL;
+ ret = verify_area(VERIFY_READ, buf, count);
+ if (ret)
+ return ret;
+
+ if (state->req.reply_expected && !state->req.got_reply) {
+ /* A previous request is still being processed.
+ Wait for it to finish. */
+ ret = adb_wait_reply(state, file);
+ if (ret)
+ return ret;
+ }
+
+ state->req.nbytes = count;
+ state->req.done = adb_write_done;
+ state->req.got_reply = 0;
+ copy_from_user(state->req.data, buf, count);
+#if 0
+ switch (adb_hardware) {
+ case ADB_NONE:
+ return -ENXIO;
+ case ADB_VIACUDA:
+ state->req.reply_expected = 1;
+ cuda_send_request(&state->req);
+ break;
+ default:
+#endif
+ if (state->req.data[0] != ADB_PACKET)
+ return -EINVAL;
+ for (i = 1; i < state->req.nbytes; ++i)
+ state->req.data[i] = state->req.data[i+1];
+ state->req.reply_expected =
+ ((state->req.data[0] & 0xc) == 0xc);
+ adb_send_request(&state->req);
+#if 0
+ break;
+ }
+#endif
+
+ return count;
+}
+
+static struct file_operations adb_fops = {
+ adb_lseek,
+ adb_read,
+ adb_write,
+ NULL, /* no readdir */
+ NULL, /* no poll yet */
+ NULL, /* no ioctl yet */
+ NULL, /* no mmap */
+ adb_open,
+ adb_release
+};
+
+int adbdev_register(int subtype, struct file_operations *fops)
+{
+ if (subtype < 0 || subtype > 15)
+ return -EINVAL;
+ if (adb_cooked[subtype])
+ return -EBUSY;
+ adb_cooked[subtype] = fops;
+ return 0;
+}
+
+int adbdev_unregister(int subtype)
+{
+ if (subtype < 0 || subtype > 15)
+ return -EINVAL;
+ if (!adb_cooked[subtype])
+ return -ENODEV;
+ adb_cooked[subtype] = NULL;
+ return 0;
+}
+
+void adbdev_init()
+{
+ if (register_chrdev(ADB_MAJOR, "adb", &adb_fops))
+ printk(KERN_ERR "adb: unable to get major %d\n", ADB_MAJOR);
+}
+
+
+#if 0 /* old ADB device */
+
+/*
+ * Here are the file operations we export for /dev/adb.
+ */
+
+#define ADB_MINOR 140 /* /dev/adb is c 10 140 */
+
+extern void adbdev_inits(void);
+
+struct adbdev_state {
+ struct adb_request req;
+};
+
+static struct wait_queue *adb_wait;
+
+static int adb_wait_reply(struct adbdev_state *state, struct file *file)
+{
+ int ret = 0;
+ struct wait_queue wait = { current, NULL };
+
+#if (ADBDEBUG & ADBDEBUG_DEVICE)
+ printk("ADB request: wait_reply (blocking ... \n");
+#endif
+
+ add_wait_queue(&adb_wait, &wait);
+ current->state = TASK_INTERRUPTIBLE;
+
+ while (!state->req.got_reply) {
+ if (file->f_flags & O_NONBLOCK) {
+ ret = -EAGAIN;
+ break;
+ }
+ if (signal_pending(current)) {
+ ret = -ERESTARTSYS;
+ break;
+ }
+ schedule();
+ }
+
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&adb_wait, &wait);
+
+ return ret;
+}
+
+static void adb_write_done(struct adb_request *req)
+{
+ if (!req->got_reply) {
+ req->reply_len = 0;
+ req->got_reply = 1;
+ }
+ wake_up_interruptible(&adb_wait);
+}
+
+static int adb_open(struct inode *inode, struct file *file)
+{
+ struct adbdev_state *state;
+
+ state = kmalloc(sizeof(struct adbdev_state), GFP_KERNEL);
+ if (state == 0)
+ return -ENOMEM;
+ file->private_data = state;
+ state->req.reply_expected = 0;
+ return 0;
+}
+
+static void adb_release(struct inode *inode, struct file *file)
+{
+ struct adbdev_state *state = file->private_data;
+
+ if (state) {
+ file->private_data = NULL;
+ if (state->req.reply_expected && !state->req.got_reply)
+ if (adb_wait_reply(state, file))
+ return;
+ kfree(state);
+ }
+ return;
+}
+
+static int adb_lseek(struct inode *inode, struct file *file,
+ off_t offset, int origin)
+{
+ return -ESPIPE;
+}
+
+static int adb_read(struct inode *inode, struct file *file,
+ char *buf, int count)
+{
+ int ret;
+ struct adbdev_state *state = file->private_data;
+
+ if (count < 2)
+ return -EINVAL;
+ if (count > sizeof(state->req.reply))
+ count = sizeof(state->req.reply);
+ ret = verify_area(VERIFY_WRITE, buf, count);
+ if (ret)
+ return ret;
+
+ if (!state->req.reply_expected)
+ return 0;
+
+ ret = adb_wait_reply(state, file);
+ if (ret)
+ return ret;
+
+ ret = state->req.reply_len;
+ memcpy_tofs(buf, state->req.reply, ret);
+ state->req.reply_expected = 0;
+
+ return ret;
+}
+
+static int adb_write(struct inode *inode, struct file *file,
+ const char *buf, int count)
+{
+ int ret;
+ struct adbdev_state *state = file->private_data;
+
+ if (count < 2 || count > sizeof(state->req.data))
+ return -EINVAL;
+ ret = verify_area(VERIFY_READ, buf, count);
+ if (ret)
+ return ret;
+
+ if (state->req.reply_expected && !state->req.got_reply) {
+ /* A previous request is still being processed.
+ Wait for it to finish. */
+ ret = adb_wait_reply(state, file);
+ if (ret)
+ return ret;
+ }
+
+ state->req.nbytes = count;
+ state->req.done = adb_write_done;
+ memcpy_fromfs(state->req.data, buf, count);
+ state->req.reply_expected = 1;
+ state->req.got_reply = 0;
+ adb_send_request(&state->req);
+
+ return count;
+}
+
+static struct file_operations adb_fops = {
+ adb_lseek,
+ adb_read,
+ adb_write,
+ NULL, /* no readdir */
+ NULL, /* no select */
+ NULL, /* no ioctl */
+ NULL, /* no mmap */
+ adb_open,
+ adb_release
+};
+
+static struct miscdevice adb_dev = {
+ ADB_MINOR,
+ "adb",
+ &adb_fops
+};
+
+void adbdev_init(void)
+{
+ misc_register(&adb_dev);
+}
+
+#endif /* old ADB device */
diff --git a/arch/m68k/mac/bootparse.c b/arch/m68k/mac/bootparse.c
new file mode 100644
index 000000000..ae5046c3e
--- /dev/null
+++ b/arch/m68k/mac/bootparse.c
@@ -0,0 +1,121 @@
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <asm/setup.h>
+#include <asm/bootinfo.h>
+#include <asm/macintosh.h>
+
+/*
+ * Booter vars
+ */
+
+int boothowto;
+int _boothowto;
+
+/*
+ * Called early to parse the environment (passed to us from the booter)
+ * into a bootinfo struct. Will die as soon as we have our own booter
+ */
+
+#define atol(x) simple_strtoul(x,NULL,0)
+
+void parse_booter(char *env)
+{
+ char *name;
+ char *value;
+#if 0
+ while(0 && *env)
+#else
+ while(*env)
+#endif
+ {
+ name=env;
+ value=name;
+ while(*value!='='&&*value)
+ value++;
+ if(*value=='=')
+ *value++=0;
+ env=value;
+ while(*env)
+ env++;
+ env++;
+#if 0
+ if(strcmp(name,"VIDEO_ADDR")==0)
+ mac_mch.videoaddr=atol(value);
+ if(strcmp(name,"ROW_BYTES")==0)
+ mac_mch.videorow=atol(value);
+ if(strcmp(name,"SCREEN_DEPTH")==0)
+ mac_mch.videodepth=atol(value);
+ if(strcmp(name,"DIMENSIONS")==0)
+ mac_mch.dimensions=atol(value);
+#endif
+ if(strcmp(name,"BOOTTIME")==0)
+ mac_bi_data.boottime=atol(value);
+ if(strcmp(name,"GMTBIAS")==0)
+ mac_bi_data.gmtbias=atol(value);
+ if(strcmp(name,"BOOTERVER")==0)
+ mac_bi_data.bootver=atol(value);
+ if(strcmp(name,"MACOS_VIDEO")==0)
+ mac_bi_data.videological=atol(value);
+ if(strcmp(name,"MACOS_SCC")==0)
+ mac_bi_data.sccbase=atol(value);
+ if(strcmp(name,"MACHINEID")==0)
+ mac_bi_data.id=atol(value);
+ if(strcmp(name,"MEMSIZE")==0)
+ mac_bi_data.memsize=atol(value);
+ if(strcmp(name,"SERIAL_MODEM_FLAGS")==0)
+ mac_bi_data.serialmf=atol(value);
+ if(strcmp(name,"SERIAL_MODEM_HSKICLK")==0)
+ mac_bi_data.serialhsk=atol(value);
+ if(strcmp(name,"SERIAL_MODEM_GPICLK")==0)
+ mac_bi_data.serialgpi=atol(value);
+ if(strcmp(name,"SERIAL_PRINT_FLAGS")==0)
+ mac_bi_data.printmf=atol(value);
+ if(strcmp(name,"SERIAL_PRINT_HSKICLK")==0)
+ mac_bi_data.printhsk=atol(value);
+ if(strcmp(name,"SERIAL_PRINT_GPICLK")==0)
+ mac_bi_data.printgpi=atol(value);
+ if(strcmp(name,"PROCESSOR")==0)
+ mac_bi_data.cpuid=atol(value);
+ if(strcmp(name,"ROMBASE")==0)
+ mac_bi_data.rombase=atol(value);
+ if(strcmp(name,"TIMEDBRA")==0)
+ mac_bi_data.timedbra=atol(value);
+ if(strcmp(name,"ADBDELAY")==0)
+ mac_bi_data.adbdelay=atol(value);
+ }
+#if 0 /* XXX: TODO with m68k_mach_* */
+ /* Fill in the base stuff */
+ boot_info.machtype=MACH_MAC;
+ /* Read this from the macinfo we got ! */
+/* boot_info.cputype=CPU_68020|FPUB_68881;*/
+/* boot_info.memory[0].addr=0;*/
+/* boot_info.memory[0].size=((mac_bi_data.id>>7)&31)<<20;*/
+ boot_info.num_memory=1; /* On a MacII */
+ boot_info.ramdisk_size=0; /* For now */
+ *boot_info.command_line=0;
+#endif
+ }
+
+
+void print_booter(char *env)
+{
+ char *name;
+ char *value;
+ while(*env)
+ {
+ name=env;
+ value=name;
+ while(*value!='='&&*value)
+ value++;
+ if(*value=='=')
+ *value++=0;
+ env=value;
+ while(*env)
+ env++;
+ env++;
+ printk("%s=%s\n", name,value);
+ }
+ }
+
+
diff --git a/arch/m68k/mac/config.c b/arch/m68k/mac/config.c
new file mode 100644
index 000000000..d711dd7b3
--- /dev/null
+++ b/arch/m68k/mac/config.c
@@ -0,0 +1,575 @@
+/*
+ * linux/arch/m68k/mac/config.c
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+/*
+ * Miscellaneous linux stuff
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/kd.h>
+#include <linux/tty.h>
+#include <linux/console.h>
+#include <linux/interrupt.h>
+/* keyb */
+#include <linux/random.h>
+#include <linux/delay.h>
+/* keyb */
+#include <linux/init.h>
+
+#define BOOTINFO_COMPAT_1_0
+#include <asm/setup.h>
+#include <asm/bootinfo.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/pgtable.h>
+#include <asm/machdep.h>
+
+#include <asm/macintosh.h>
+#include <asm/macints.h>
+
+#include "via6522.h"
+
+/* old bootinfo stuff */
+
+struct mac_booter_data mac_bi_data = {0,};
+int mac_bisize = sizeof mac_bi_data;
+
+struct compat_bootinfo compat_boot_info ={0,};
+int compat_bisize = sizeof compat_boot_info;
+
+int compat_bi = 0;
+
+/* New bootinfo stuff */
+
+extern int m68k_num_memory;
+extern struct mem_info m68k_memory[NUM_MEMINFO];
+
+extern struct mem_info m68k_ramdisk;
+
+extern char m68k_command_line[CL_SIZE];
+
+void *mac_env; /* Loaded by the boot asm */
+
+extern int mac_keyb_init(void);
+extern int mac_kbdrate(struct kbd_repeat *k);
+extern void mac_kbd_leds(unsigned int leds);
+
+extern void (*kd_mksound)(unsigned int, unsigned int);
+extern void mac_mksound(unsigned int, unsigned int);
+extern int mac_floppy_init(void);
+extern void mac_floppy_setup(char *,int *);
+
+extern void mac_gettod (int *, int *, int *, int *, int *, int *);
+
+extern void nubus_sweep_video(void);
+extern void via_init_clock(void (*func)(int, void *, struct pt_regs *));
+extern void mac_debugging_long(int, long);
+
+/* Mac specific debug functions (in debug.c) */
+extern void mac_debug_init(void);
+
+#ifdef CONFIG_MAGIC_SYSRQ
+static char mac_sysrq_xlate[128] =
+ "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */
+ "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */
+ "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */
+ "bnm,./\000\000\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */
+ "\206\207\210\211\212\000\000\000\000\000-\000\000\000+\000"/* 0x40 - 0x4f */
+ "\000\000\000\177\000\000\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */
+ "\000\000\000()/*789456123" /* 0x60 - 0x6f */
+ "0.\r\000\000\000\000\000\000\000\000\000\000\000\000\000"; /* 0x70 - 0x7f */
+#endif
+
+extern void (*kd_mksound)(unsigned int, unsigned int);
+
+void mac_get_model(char *str)
+{
+ strcpy(str,"Macintosh");
+}
+
+void mac_bang(int irq, void *vector, struct pt_regs *p)
+{
+ printk("Resetting ...\n");
+ mac_reset();
+}
+
+void mac_sched_init(void (*vector)(int, void *, struct pt_regs *))
+{
+ via_init_clock(vector);
+}
+
+unsigned long mac_gettimeoffset (void)
+{
+ return 0L;
+}
+
+extern int console_loglevel;
+
+void mac_gettod (int *yearp, int *monp, int *dayp,
+ int *hourp, int *minp, int *secp)
+{
+ unsigned long time;
+ int leap, oldleap, isleap;
+ int mon_days[14] = { -1, 31, 27, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, -1 };
+
+ time = mac_bi_data.boottime - 60*mac_bi_data.gmtbias; /* seconds */
+
+#if 0
+ printk("mac_gettod: boottime 0x%lx gmtbias %ld \n",
+ mac_bi_data.boottime, mac_bi_data.gmtbias);
+#endif
+
+ *minp = time / 60;
+ *secp = time - (*minp * 60);
+ time = *minp; /* minutes now */
+
+ *hourp = time / 60;
+ *minp = time - (*hourp * 60);
+ time = *hourp; /* hours now */
+
+ *dayp = time / 24;
+ *hourp = time - (*dayp * 24);
+ time = *dayp; /* days now ... */
+
+ /* for leap day calculation */
+ *yearp = (time / 365) + 1970; /* approx. year */
+
+ /* leap year calculation - there's an easier way, I bet */
+ /* calculate leap days up to previous year */
+ oldleap = (*yearp-1)/4 - (*yearp-1)/100 + (*yearp-1)/400;
+ /* calculate leap days incl. this year */
+ leap = *yearp/4 - *yearp/100 + *yearp/400;
+ /* this year a leap year ?? */
+ isleap = (leap != oldleap);
+
+ /* adjust days: days, excluding past leap days since epoch */
+ time -= oldleap - (1970/4 - 1970/100 + 1970/400);
+
+ /* precise year, and day in year */
+ *yearp = (time / 365); /* #years since epoch */
+ *dayp = time - (*yearp * 365) + 1; /* #days this year (0: Jan 1) */
+ *yearp += 70; /* add epoch :-) */
+ time = *dayp;
+
+ if (isleap) /* add leap day ?? */
+ mon_days[2] = 28;
+
+ /* count the months */
+ for (*monp = 1; time > mon_days[*monp]; (*monp)++)
+ time -= mon_days[*monp];
+
+ *dayp = time;
+
+#if 1
+ printk("mac_gettod: %d-%d-%d %d:%d.%d GMT (GMT offset %d)\n",
+ *yearp, *monp, *dayp, *hourp, *minp, *secp,
+ (signed long) mac_bi_data.gmtbias);
+#endif
+
+ return;
+}
+
+void mac_waitbut (void)
+{
+ ;
+}
+
+extern struct consw fb_con;
+extern struct fb_info *mac_fb_init(long *);
+extern void mac_video_setup(char *, int *);
+
+void mac_debug_init (void)
+{
+ ;
+}
+
+void (*mac_handlers[8])(int, void *, struct pt_regs *)=
+{
+ mac_default_handler,
+ mac_default_handler,
+ mac_default_handler,
+ mac_default_handler,
+ mac_default_handler,
+ mac_default_handler,
+ mac_default_handler,
+ mac_default_handler
+};
+
+ /*
+ * Parse a Macintosh-specific record in the bootinfo
+ */
+
+__initfunc(int mac_parse_bootinfo(const struct bi_record *record))
+{
+ int unknown = 0;
+ const u_long *data = record->data;
+
+ if (compat_bi)
+ return(unknown);
+
+ switch (record->tag) {
+ case BI_MAC_MODEL:
+ mac_bi_data.id = *data;
+ break;
+ case BI_MAC_VADDR:
+ mac_bi_data.videoaddr = *data;
+ break;
+ case BI_MAC_VDEPTH:
+ mac_bi_data.videodepth = *data;
+ break;
+ case BI_MAC_VROW:
+ mac_bi_data.videorow = *data;
+ break;
+ case BI_MAC_VDIM:
+ mac_bi_data.dimensions = *data;
+ break;
+ case BI_MAC_VLOGICAL:
+ mac_bi_data.videological = *data;
+ break;
+ case BI_MAC_SCCBASE:
+ mac_bi_data.sccbase = *data;
+ break;
+ case BI_MAC_BTIME:
+ mac_bi_data.boottime = *data;
+ break;
+ case BI_MAC_GMTBIAS:
+ mac_bi_data.gmtbias = *data;
+ break;
+ case BI_MAC_MEMSIZE:
+ mac_bi_data.memsize = *data;
+ break;
+ case BI_MAC_CPUID:
+ mac_bi_data.cpuid = *data;
+ break;
+ default:
+ unknown = 1;
+ }
+ return(unknown);
+}
+
+__initfunc(void mac_copy_compat(void))
+{
+ int i;
+
+ compat_bi = 1;
+
+ for (i=0; i<compat_boot_info.num_memory; i++) {
+ m68k_memory[m68k_num_memory].addr = compat_boot_info.memory[i].addr;
+ m68k_memory[m68k_num_memory].size = compat_boot_info.memory[i].size;
+ m68k_num_memory++;
+ }
+
+ m68k_ramdisk.addr = compat_boot_info.ramdisk_addr;
+ m68k_ramdisk.size = compat_boot_info.ramdisk_size;
+
+ strncpy(m68k_command_line, (const char *)compat_boot_info.command_line,
+ CL_SIZE);
+ m68k_command_line[CL_SIZE-1] = '\0';
+
+ mac_bi_data.id = compat_boot_info.bi_mac.id;
+ mac_bi_data.videoaddr = compat_boot_info.bi_mac.videoaddr;
+ mac_bi_data.videodepth = compat_boot_info.bi_mac.videodepth;
+ mac_bi_data.videorow = compat_boot_info.bi_mac.videorow;
+ mac_bi_data.dimensions = compat_boot_info.bi_mac.dimensions;
+ mac_bi_data.videological = compat_boot_info.bi_mac.videological;
+ mac_bi_data.sccbase = compat_boot_info.bi_mac.sccbase;
+ mac_bi_data.boottime = compat_boot_info.bi_mac.boottime;
+ mac_bi_data.gmtbias = compat_boot_info.bi_mac.gmtbias;
+ mac_bi_data.memsize = compat_boot_info.bi_mac.memsize;
+ mac_bi_data.cpuid = compat_boot_info.bi_mac.cpuid;
+
+}
+
+__initfunc(void config_mac(void))
+{
+
+ if (MACH_IS_ATARI || MACH_IS_AMIGA) {
+ printk("ERROR: no Mac, but config_mac() called!! \n");
+ }
+
+ mac_debugging_penguin(5);
+
+ mac_debug_init();
+
+ mach_sched_init = mac_sched_init;
+ mach_keyb_init = mac_keyb_init;
+ mach_kbdrate = mac_kbdrate;
+ mach_kbd_leds = mac_kbd_leds;
+ mach_init_IRQ = mac_init_IRQ;
+ mach_request_irq = mac_request_irq;
+ mach_free_irq = mac_free_irq;
+ enable_irq = mac_enable_irq;
+ disable_irq = mac_disable_irq;
+#if 1
+ mach_default_handler = &mac_handlers;
+#endif
+ mach_get_model = mac_get_model;
+ mach_get_irq_list = mac_get_irq_list;
+ mach_gettimeoffset = mac_gettimeoffset;
+ mach_gettod = mac_gettod;
+#if 0
+ mach_mksound = mac_mksound;
+#endif
+ mach_reset = mac_reset;
+#ifdef CONFIG_BLK_DEV_FD
+ mach_floppy_init = mac_floppy_init;
+ mach_floppy_setup = mac_floppy_setup;
+#endif
+ conswitchp = &fb_con;
+ mach_max_dma_address = 0xffffffff;
+#if 0
+ mach_debug_init = mac_debug_init;
+ mach_video_setup = mac_video_setup;
+#endif
+ kd_mksound = mac_mksound;
+#ifdef CONFIG_MAGIC_SYSRQ
+ mach_sysrq_key = 98; /* HELP */
+ mach_sysrq_shift_state = 8; /* Alt */
+ mach_sysrq_shift_mask = 0xff; /* all modifiers except CapsLock */
+ mach_sysrq_xlate = mac_sysrq_xlate;
+#endif
+#ifdef CONFIG_HEARTBEAT
+#if 0
+ mach_heartbeat = mac_heartbeat;
+ mach_heartbeat_irq = IRQ_MAC_TIMER;
+#endif
+#endif
+
+ /*
+ * Determine hardware present
+ */
+
+ mac_identify();
+ mac_report_hardware();
+
+ /* goes on forever if timers broken */
+#ifdef MAC_DEBUG_SOUND
+ mac_mksound(1000,10);
+#endif
+
+ /*
+ * Check for machine specific fixups.
+ */
+
+ nubus_sweep_video();
+}
+
+
+/*
+ * Macintosh Table
+ */
+
+struct mac_model *macintosh_config;
+
+static struct mac_model mac_data_table[]=
+{
+ /*
+ * Original MacII hardware
+ *
+ */
+
+ { MAC_MODEL_II, "II", MAC_ADB_II, MAC_VIA_II, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_NUBUS},
+ { MAC_MODEL_IIX, "IIx", MAC_ADB_II, MAC_VIA_II, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_NUBUS},
+ { MAC_MODEL_IICX, "IIcx", MAC_ADB_II, MAC_VIA_II, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_NUBUS},
+ { MAC_MODEL_SE30, "SE/30", MAC_ADB_II, MAC_VIA_II, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_NUBUS},
+
+ /*
+ * Weirdified MacII hardware - all subtley different. Gee thanks
+ * Apple. All these boxes seem to have VIA2 in a different place to
+ * the MacII (+1A000 rather than +4000)
+ *
+ * The IIfx apparently has different ADB hardware, and stuff
+ * so zany nobody knows how to drive it.
+ */
+
+ { MAC_MODEL_IICI, "IIci", MAC_ADB_II, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_IIFX, "IIfx", MAC_ADB_NONE, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_IISI, "IIsi", MAC_ADB_IISI, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_IIVI, "IIvi", MAC_ADB_IISI, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_IIVX, "IIvx", MAC_ADB_IISI, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
+
+ /*
+ * Classic models (guessing: similar to SE/30 ?? Nope, similar to LC ...)
+ */
+
+ { MAC_MODEL_CLII, "Classic II", MAC_ADB_IISI, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_CCL, "Color Classic", MAC_ADB_IISI, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
+
+ /*
+ * Some Mac LC machines. Basically the same as the IIci
+ */
+
+ { MAC_MODEL_LCII, "LC II", MAC_ADB_IISI, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_LCIII,"LC III", MAC_ADB_IISI, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
+
+ /*
+ * Quadra (only 68030 ones will actually work!). Not much odd. Video is at
+ * 0xF9000000, via is like a MacII. We label it differently as some of the
+ * stuff connected to VIA2 seems different. Better SCSI chip and ???? onboard ethernet
+ * in all cases using a NatSemi SONIC. The 700, 900 and 950 have some I/O chips in the wrong
+ * place to confuse us. The 840 seems to have a scsi location of its own
+ */
+
+ { MAC_MODEL_Q605, "Quadra 605", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS},
+ { MAC_MODEL_Q610, "Quadra 610", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS},
+ { MAC_MODEL_Q630, "Quadra 630", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS},
+ { MAC_MODEL_Q650, "Quadra 650", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS},
+ /* The Q700 does have a NS Sonic */
+#if 0
+ { MAC_MODEL_Q700, "Quadra 700", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE, MAC_SCC_QUADRA2, MAC_ETHER_SONIC, MAC_NUBUS},
+ { MAC_MODEL_Q800, "Quadra 800", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS},
+#else
+ { MAC_MODEL_Q700, "Quadra 700", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE, MAC_SCC_QUADRA2, MAC_ETHER_SONIC, MAC_NUBUS},
+ { MAC_MODEL_Q800, "Quadra 800", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS},
+#endif
+ /* Does the 840 have ethernet ??? documents seem to indicate its not quite a
+ Quadra in this respect ? */
+ { MAC_MODEL_Q840, "Quadra 840", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA3, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_Q900, "Quadra 900", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE, MAC_SCC_QUADRA2, MAC_ETHER_SONIC, MAC_NUBUS},
+ { MAC_MODEL_Q950, "Quadra 950", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE, MAC_SCC_QUADRA2, MAC_ETHER_SONIC, MAC_NUBUS},
+
+ /*
+ * Performa - more LC type machines
+ */
+
+ { MAC_MODEL_P460, "Performa 460", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_P475, "Performa 475", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_P520, "Performa 520", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_P550, "Performa 550", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_P575, "Performa 575", MAC_ADB_CUDA, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_TV, "TV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
+#if 0 /* other sources seem to suggest the P630/Q630/LC630 is more like LCIII */
+ { MAC_MODEL_P630, "Performa 630", MAC_ADB_IISI, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
+#endif
+ /*
+ * Centris - just guessing again; maybe like Quadra
+ */
+
+ { MAC_MODEL_C610, "Centris 610", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_C650, "Centris 650", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_C660, "Centris 660AV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
+
+ /*
+ * Power books - seem similar to early Quadras ? (most have 030 though)
+ */
+
+ { MAC_MODEL_PB140, "PowerBook 140", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_PB145, "PowerBook 145", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
+ /* The PB150 has IDE, and IIci style VIA */
+ { MAC_MODEL_PB150, "PowerBook 150", MAC_ADB_CUDA, MAC_VIA_IIci, MAC_SCSI_QUADRA, MAC_IDE_PB, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_PB160, "PowerBook 160", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_PB165, "PowerBook 165", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_PB165C, "PowerBook 165c", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_PB170, "PowerBook 170", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_PB180, "PowerBook 180", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_PB180C, "PowerBook 180c", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_PB190, "PowerBook 190cs", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_PB520, "PowerBook 520", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
+
+ /*
+ * Power book Duos - similar to Power books, I hope
+ */
+
+ { MAC_MODEL_PB210, "PowerBook Duo 210", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_PB230, "PowerBook Duo 230", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_PB250, "PowerBook Duo 250", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_PB270C, "PowerBook Duo 270c", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_PB280, "PowerBook Duo 280", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_PB280C, "PowerBook Duo 280c", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
+
+ /*
+ * Other stuff ??
+ */
+ { -1, NULL, 0,0,0,}
+};
+
+void mac_identify(void)
+{
+ struct mac_model *m=&mac_data_table[0];
+
+ /* Penguin data useful? */
+ int model = mac_bi_data.id;
+ if (!model) {
+ /* no bootinfo model id -> NetBSD booter was used! */
+ /* XXX FIXME: breaks for model > 31 */
+ model=(mac_bi_data.cpuid>>2)&63;
+ printk ("No bootinfo model ID, using cpuid instead (hey, use Penguin!)\n");
+ }
+
+ printk ("Detected Macintosh model: %d \n", model);
+
+ while(m->ident != -1)
+ {
+ if(m->ident == model)
+ break;
+ m++;
+ }
+ if(m->ident==-1)
+ {
+ printk("\nUnknown macintosh model %d, probably unsupported.\n",
+ model);
+ mac_debugging_long(1, (long) 0x55555555);
+ mac_debugging_long(1, (long) model);
+ model = MAC_MODEL_Q800;
+ printk("Defaulting to: Quadra800, model id %d\n", model);
+ printk("Please report this case to linux-mac68k@wave.lm.com\n");
+ m=&mac_data_table[0];
+ while(m->ident != -1)
+ {
+ if(m->ident == model)
+ break;
+ m++;
+ }
+ if(m->ident==-1)
+ mac_boom(5);
+ }
+
+ /*
+ * Report booter data:
+ */
+ printk (" Penguin (bootinfo version %d) data:\n", 2-compat_bi);
+ printk (" Video: addr 0x%lx row 0x%lx depth %lx dimensions %d x %d\n",
+ mac_bi_data.videoaddr, mac_bi_data.videorow,
+ mac_bi_data.videodepth, mac_bi_data.dimensions & 0xFFFF,
+ mac_bi_data.dimensions >> 16);
+ printk (" Boottime: 0x%lx GMTBias: 0x%lx \n",
+ mac_bi_data.boottime, mac_bi_data.gmtbias);
+ printk (" Videological 0x%lx, SCC at 0x%lx \n",
+ mac_bi_data.videological, mac_bi_data.sccbase);
+ printk (" Machine ID: %ld CPUid: 0x%lx memory size: 0x%lx \n",
+ mac_bi_data.id, mac_bi_data.cpuid, mac_bi_data.memsize);
+ printk ("Ramdisk: addr 0x%lx size 0x%lx\n",
+ m68k_ramdisk.addr, m68k_ramdisk.size);
+
+ /*
+ * Save the pointer
+ */
+
+ macintosh_config=m;
+
+ /*
+ * TODO: set the various fields in macintosh_config->hw_present here!
+ */
+
+}
+
+void mac_report_hardware(void)
+{
+ printk("Apple Macintosh %s\n", macintosh_config->name);
+}
+
+/*
+ * Local variables:
+ * c-indent-level: 4
+ * tab-width: 8
+ * End:
+ */
diff --git a/arch/m68k/mac/debug.c b/arch/m68k/mac/debug.c
new file mode 100644
index 000000000..cc6f491fb
--- /dev/null
+++ b/arch/m68k/mac/debug.c
@@ -0,0 +1,366 @@
+/*
+ * linux/arch/m68k/mac/debug.c
+ *
+ * Shamelessly stolen (SCC code and general framework) from:
+ *
+ * linux/arch/m68k/atari/debug.c
+ *
+ * Atari debugging and serial console stuff
+ *
+ * Assembled of parts of former atari/config.c 97-12-18 by Roman Hodek
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/tty.h>
+#include <linux/console.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#define BOOTINFO_COMPAT_1_0
+#include <asm/setup.h>
+#include <asm/bootinfo.h>
+#include <asm/machw.h>
+#include <asm/macints.h>
+
+extern char m68k_debug_device[];
+
+extern struct compat_bootinfo compat_boot_info;
+
+extern unsigned long mac_videobase;
+extern unsigned long mac_videodepth;
+extern unsigned long mac_rowbytes;
+
+/*
+ * These two auxiliary debug functions should go away ASAP. Only usage:
+ * before the console output is up (after head.S come some other crucial
+ * setup routines :-) it permits writing 'data' to the screen as bit patterns
+ * (good luck reading those). Helped to figure that the bootinfo contained
+ * garbage data on the amount and size of memory chunks ...
+ *
+ * The 'pos' argument now simply means 'linefeed after print' ...
+ */
+
+static int peng=0, line=0;
+
+void mac_debugging_short(int pos, short num)
+{
+ unsigned char *pengoffset;
+ unsigned char *pptr;
+ int i;
+
+ if (!MACH_IS_MAC) {
+ /* printk("debug: %d !\n", num); */
+ return;
+ }
+
+ /* calculate current offset */
+ pengoffset=(unsigned char *)(mac_videobase+(20+line*2)*mac_rowbytes)
+ +80*peng;
+
+ pptr=pengoffset;
+
+ for(i=0;i<8*sizeof(short);i++) /* # of bits */
+ {
+ /* value mask for bit i, reverse order */
+ *pptr++ = (num & ( 1 << (8*sizeof(short)-i-1) ) ? 0xFF : 0x00);
+ }
+
+ peng++;
+
+ if (pos) {
+ line++;
+ peng = 0;
+ }
+}
+
+void mac_debugging_long(int pos, long addr)
+{
+ unsigned char *pengoffset;
+ unsigned char *pptr;
+ int i;
+
+ if (!MACH_IS_MAC) {
+ /* printk("debug: #%ld !\n", addr); */
+ return;
+ }
+
+ pengoffset=(unsigned char *)(mac_videobase+(20+line*2)*mac_rowbytes)
+ +80*peng;
+
+ pptr=pengoffset;
+
+ for(i=0;i<8*sizeof(long);i++) /* # of bits */
+ {
+ *pptr++ = (addr & ( 1 << (8*sizeof(long)-i-1) ) ? 0xFF : 0x00);
+ }
+
+ peng++;
+
+ if (pos) {
+ line++;
+ peng = 0;
+ }
+}
+
+/*
+ * Penguin - used by head.S console; obsolete
+ */
+char that_penguin[]={
+#include "that_penguin.h"
+};
+
+/*
+ * B/W version of penguin, unfinished - any takers??
+ */
+static char bw_penguin[]={
+#include "bw_penguin.h"
+};
+
+void mac_debugging_penguin(int peng)
+{
+ unsigned char *pengoffset;
+ unsigned char *pptr;
+ unsigned char *bwpdptr=bw_penguin;
+ int i;
+
+ if (!MACH_IS_MAC)
+ return;
+
+ if (compat_boot_info.bi_mac.videodepth ==1)
+ pengoffset=(unsigned char *)(mac_videobase+80*mac_rowbytes)
+ +5*peng;
+ else
+ pengoffset=(unsigned char *)(mac_videobase+80*mac_rowbytes)
+ +20*peng;
+
+ pptr=pengoffset;
+
+ for(i=0;i<36;i++)
+ {
+ memcpy(pptr,bwpdptr,4);
+ bwpdptr+=4;
+ pptr+=mac_rowbytes;
+ }
+}
+
+/*
+ * B/W version of flaming Mac, unfinished (see above).
+ */
+static char bw_kaboom_map[]={
+#include "bw_mac.h"
+};
+
+static void mac_boom_boom(void)
+{
+ static unsigned char *boomoffset=NULL;
+ unsigned char *pptr;
+ unsigned char *bwpdptr=bw_kaboom_map;
+ int i;
+
+ if(!boomoffset)
+ if (compat_boot_info.bi_mac.videodepth == 1) {
+ boomoffset=(unsigned char *)(mac_videobase+160*mac_rowbytes);
+ } else {
+ boomoffset=(unsigned char *)(mac_videobase+256*mac_rowbytes);
+ }
+ else
+ if (compat_boot_info.bi_mac.videodepth == 1)
+ boomoffset+=5;
+ else
+ boomoffset+=32;
+
+ pptr=boomoffset;
+
+ for(i=0;i<36;i++)
+ {
+ memcpy(pptr,bwpdptr,4);
+ bwpdptr+=4;
+ pptr+=mac_rowbytes;
+ }
+}
+
+void mac_boom(int booms)
+{
+ int i;
+
+ if (!MACH_IS_MAC)
+ return;
+
+ for(i=0;i<booms;i++)
+ mac_boom_boom();
+ while(1);
+}
+
+
+#if 0
+/*
+ * TODO: serial debug code
+ */
+
+/* Flag that serial port is already initialized and used */
+int mac_SCC_init_done = 0;
+/* Can be set somewhere, if a SCC master reset has already be done and should
+ * not be repeated; used by kgdb */
+int mac_SCC_reset_done = 0;
+
+static struct console mac_console_driver = {
+ "debug",
+ NULL, /* write */
+ NULL, /* read */
+ NULL, /* device */
+ NULL, /* wait_key */
+ NULL, /* unblank */
+ NULL, /* setup */
+ CON_PRINTBUFFER,
+ -1,
+ 0,
+ NULL
+};
+
+static int scc_port;
+
+static inline void mac_scc_out (char c)
+{
+ do {
+ MFPDELAY();
+ } while (!(scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */
+ MFPDELAY();
+ scc.cha_b_data = c;
+}
+
+void mac_scc_console_write (struct console *co, const char *str,
+ unsigned int count)
+{
+ while (count--) {
+ if (*str == '\n')
+ mac_scc_out( '\r' );
+ mac_scc_out( *str++ );
+ }
+}
+
+#ifdef CONFIG_SERIAL_CONSOLE
+int mac_scc_console_wait_key(struct console *co)
+{
+ do {
+ MFPDELAY();
+ } while( !(scc.cha_b_ctrl & 0x01) ); /* wait for rx buf filled */
+ MFPDELAY();
+ return( scc.cha_b_data );
+}
+#endif
+
+/* The following two functions do a quick'n'dirty initialization of the MFP or
+ * SCC serial ports. They're used by the debugging interface, kgdb, and the
+ * serial console code. */
+#define SCC_WRITE(reg,val) \
+ do { \
+ scc.cha_b_ctrl = (reg); \
+ MFPDELAY(); \
+ scc.cha_b_ctrl = (val); \
+ MFPDELAY(); \
+ } while(0)
+
+/* loops_per_sec isn't initialized yet, so we can't use udelay(). This does a
+ * delay of ~ 60us. */
+#define LONG_DELAY() \
+ do { \
+ int i; \
+ for( i = 100; i > 0; --i ) \
+ MFPDELAY(); \
+ } while(0)
+
+#ifndef CONFIG_SERIAL_CONSOLE
+__initfunc(static void mac_init_scc_port( int cflag, int port ))
+#else
+void mac_init_scc_port( int cflag, int port )
+#endif
+{
+ extern int mac_SCC_reset_done;
+ static int clksrc_table[9] =
+ /* reg 11: 0x50 = BRG, 0x00 = RTxC, 0x28 = TRxC */
+ { 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x00, 0x00 };
+ static int brgsrc_table[9] =
+ /* reg 14: 0 = RTxC, 2 = PCLK */
+ { 2, 2, 2, 2, 2, 2, 0, 2, 2 };
+ static int clkmode_table[9] =
+ /* reg 4: 0x40 = x16, 0x80 = x32, 0xc0 = x64 */
+ { 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0xc0, 0x80 };
+ static int div_table[9] =
+ /* reg12 (BRG low) */
+ { 208, 138, 103, 50, 24, 11, 1, 0, 0 };
+
+ int baud = cflag & CBAUD;
+ int clksrc, clkmode, div, reg3, reg5;
+
+ if (cflag & CBAUDEX)
+ baud += B38400;
+ if (baud < B1200 || baud > B38400+2)
+ baud = B9600; /* use default 9600bps for non-implemented rates */
+ baud -= B1200; /* tables starts at 1200bps */
+
+ clksrc = clksrc_table[baud];
+ clkmode = clkmode_table[baud];
+ div = div_table[baud];
+
+ reg3 = (cflag & CSIZE) == CS8 ? 0xc0 : 0x40;
+ reg5 = (cflag & CSIZE) == CS8 ? 0x60 : 0x20 | 0x82 /* assert DTR/RTS */;
+
+ (void)scc.cha_b_ctrl; /* reset reg pointer */
+ SCC_WRITE( 9, 0xc0 ); /* reset */
+ LONG_DELAY(); /* extra delay after WR9 access */
+ SCC_WRITE( 4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 |
+ 0x04 /* 1 stopbit */ |
+ clkmode );
+ SCC_WRITE( 3, reg3 );
+ SCC_WRITE( 5, reg5 );
+ SCC_WRITE( 9, 0 ); /* no interrupts */
+ LONG_DELAY(); /* extra delay after WR9 access */
+ SCC_WRITE( 10, 0 ); /* NRZ mode */
+ SCC_WRITE( 11, clksrc ); /* main clock source */
+ SCC_WRITE( 12, div ); /* BRG value */
+ SCC_WRITE( 13, 0 ); /* BRG high byte */
+ SCC_WRITE( 14, brgsrc_table[baud] );
+ SCC_WRITE( 14, brgsrc_table[baud] | (div ? 1 : 0) );
+ SCC_WRITE( 3, reg3 | 1 );
+ SCC_WRITE( 5, reg5 | 8 );
+
+ mac_SCC_reset_done = 1;
+ mac_SCC_init_done = 1;
+}
+
+
+__initfunc(void mac_debug_init(void))
+{
+#ifdef CONFIG_KGDB
+ /* the m68k_debug_device is used by the GDB stub, do nothing here */
+ return;
+#endif
+ if (!strcmp( m68k_debug_device, "ser" )) {
+ strcpy( m68k_debug_device, "ser1" );
+ }
+ if (!strcmp( m68k_debug_device, "ser1" )) {
+ /* ST-MFP Modem1 serial port */
+ mac_init_scc_port( B9600|CS8, 0 );
+ mac_console_driver.write = mac_scc_console_write;
+ }
+ else if (!strcmp( m68k_debug_device, "ser2" )) {
+ /* SCC Modem2 serial port */
+ mac_init_scc_port( B9600|CS8, 1 );
+ mac_console_driver.write = mac_scc_console_write;
+ }
+ if (mac_console_driver.write)
+ register_console(&mac_console_driver);
+}
+#endif
+
+/*
+ * Local variables:
+ * c-indent-level: 4
+ * tab-width: 8
+ * End:
+ */
diff --git a/arch/m68k/mac/ksyms.c b/arch/m68k/mac/ksyms.c
new file mode 100644
index 000000000..05373b04e
--- /dev/null
+++ b/arch/m68k/mac/ksyms.c
@@ -0,0 +1,7 @@
+#include <linux/module.h>
+#include <asm/ptrace.h>
+#include <asm/traps.h>
+/* Hook for mouse driver */
+extern void (*mac_mouse_interrupt_hook) (char *);
+
+EXPORT_SYMBOL(mac_mouse_interrupt_hook);
diff --git a/arch/m68k/mac/macboing.c b/arch/m68k/mac/macboing.c
new file mode 100644
index 000000000..d24c5ae16
--- /dev/null
+++ b/arch/m68k/mac/macboing.c
@@ -0,0 +1,92 @@
+/*
+ * Mac bong noise generator. Note - we ought to put a boingy noise
+ * here 8)
+ */
+
+#include <linux/sched.h>
+#include <linux/timer.h>
+
+#include <asm/macintosh.h>
+#include <asm/mac_asc.h>
+
+static const signed char sine_data[] = {
+ 0, 39, 75, 103, 121, 127, 121, 103, 75, 39,
+ 0, -39, -75, -103, -121, -127, -121, -103, -75, -39
+};
+#define DATA_SIZE (sizeof(sine_data)/sizeof(sine_data[0]))
+
+static void nosound( unsigned long ignored );
+static struct timer_list sound_timer = { NULL, NULL, 0, 0, nosound };
+
+static volatile unsigned char *asc_base=(void *)0x50F14000;
+
+
+void mac_mksound( unsigned int hz, unsigned int ticks )
+{
+ static int inited = 0;
+ unsigned long flags;
+ int samples=512;
+
+ if(!inited)
+ {
+ int i=0;
+ int j=0;
+ int k=0;
+ int l=0;
+ for(i=0;i<samples;i++)
+ {
+ asc_base[i]=sine_data[j];
+ asc_base[i+512]=sine_data[j];
+ asc_base[i+1024]=sine_data[j];
+ asc_base[i+1536]=sine_data[j];
+ j++;
+ if(j==DATA_SIZE)
+ j=0;
+ if(i&1)
+ k++;
+ if(k==DATA_SIZE)
+ k=0;
+ if((i&3)==3)
+ l++;
+ if(l==DATA_SIZE)
+ l=0;
+ }
+ inited=1;
+ }
+ save_flags(flags);
+ cli();
+ del_timer( &sound_timer );
+
+ if (hz > 20 && hz < 32767) {
+ int i;
+ u_long asc_pulses=((hz<<5)*samples)/468;
+ for(i=0;i<4;i++)
+ {
+ asc_base[ASC_FREQ(i,0)]=0x00;
+ asc_base[ASC_FREQ(i,1)]=20;
+ asc_base[ASC_FREQ(i,2)]=0x00;
+ asc_base[ASC_FREQ(i,3)]=20;
+ asc_base[ASC_FREQ(i,4)]=(asc_pulses>>24)&0xFF;
+ asc_base[ASC_FREQ(i,5)]=(asc_pulses>>16)&0xFF;
+ asc_base[ASC_FREQ(i,6)]=(asc_pulses>>8)&0xFF;
+ asc_base[ASC_FREQ(i,7)]=(asc_pulses>>0)&0xFF;
+ }
+ asc_base[ASC_CHAN]=0x03;
+ asc_base[ASC_VOLUME]=128;
+ asc_base[ASC_MODE]=ASC_MODE_SAMPLE;
+ asc_base[ASC_ENABLE]=ASC_ENABLE_SAMPLE;
+ if (ticks) {
+ sound_timer.expires = jiffies + ticks;
+ add_timer( &sound_timer );
+ }
+ } else {
+ nosound( 0 );
+ }
+ restore_flags(flags);
+}
+
+
+static void nosound( unsigned long ignored )
+{
+ asc_base[ASC_ENABLE]=0;
+}
diff --git a/arch/m68k/mac/macints.c b/arch/m68k/mac/macints.c
new file mode 100644
index 000000000..b9c3331e9
--- /dev/null
+++ b/arch/m68k/mac/macints.c
@@ -0,0 +1,979 @@
+/*
+ * Macintosh interrupts
+ *
+ * General design:
+ * In contrary to the Amiga and Atari platforms, the Mac hardware seems to
+ * exclusively use the autovector interrupts (the 'generic level0-level7'
+ * interrupts with exception vectors 0x19-0x1f). The following interrupt levels
+ * are used:
+ * 1 - VIA1
+ * - slot 0: one second interrupt
+ * - slot 1: VBlank
+ * - slot 2: ADB data ready (SR full)
+ * - slot 3: ADB data (CB2)
+ * - slot 4: ADB clock (CB1)
+ * - slot 5: timer 2
+ * - slot 6: timer 1
+ * - slot 7: status of IRQ; signals 'any enabled int.'
+ *
+ * 2 - VIA2, RBV or OSS
+ * - slot 0: SCSI DRQ
+ * - slot 1: NUBUS IRQ
+ * - slot 3: SCSI IRQ
+ *
+ * 4 - SCC
+ * - subdivided into Channel B and Channel A interrupts
+ *
+ * 6 - Off switch (??)
+ *
+ * 7 - Debug output
+ *
+ * Using the autovector irq numbers for Linux/m68k hardware interrupts without
+ * the IRQ_MACHSPEC bit set would interfere with the general m68k interrupt
+ * handling in kernel versions 2.0.x, so the following strategy is used:
+ *
+ * - mac_init_IRQ installs the low-level entry points for the via1 and via2
+ * exception vectors and the corresponding handlers (C functions); these
+ * entry points just add the machspec bit and call the handlers proper.
+ * (in principle, the C functions can be installed as the exception vectors
+ * directly, as they are hardcoded anyway; that's the current method).
+ *
+ * - via[12]_irq determine what interrupt sources have triggered the interrupt,
+ * and call the corresponding device interrupt handlers.
+ * (currently, via1_irq and via2_irq just call via_irq, passing the via base
+ * address. RBV interrupts are handled by (you guessed it) rbv_irq).
+ * Some interrupt functions want to have the interrupt number passed, so
+ * via_irq and rbv_irq need to generate the 'fake' numbers from scratch.
+ *
+ * - for the request/free/enable/disable business, interrupt sources are
+ * numbered internally (suggestion: keep irq 0-7 unused :-). One bit in the
+ * irq number specifies the via# to use, i.e. via1 interrupts are 8-16,
+ * via2 interrupts 17-32, rbv interrupts ...
+ * The device interrupt table and the irq_enable bitmap is maintained by
+ * the machspec interrupt code; all device drivers should only use these
+ * functions !
+ *
+ * - For future porting to version 2.1 (and removing of the machspec bit) it
+ * should be sufficient to use the same numbers (everything > 7 is assumed
+ * to be machspec, according to Jes!).
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/kernel_stat.h>
+#include <linux/interrupt.h> /* for intr_count */
+
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/traps.h>
+#include <asm/machw.h>
+#include <asm/macintosh.h>
+#include "via6522.h"
+
+#include <asm/macints.h>
+
+/*
+ * Interrupt handler and parameter types
+ */
+struct irqhandler {
+ void (*handler)(int, void *, struct pt_regs *);
+ void *dev_id;
+};
+
+struct irqparam {
+ unsigned long flags;
+ const char *devname;
+};
+
+struct irqflags {
+ unsigned int disabled;
+ unsigned int pending;
+};
+
+/*
+ * Array with irq's and their parameter data.
+ */
+static struct irqhandler via1_handler[8];
+static struct irqhandler via2_handler[8];
+static struct irqhandler rbv_handler[8];
+static struct irqhandler scc_handler[8];
+static struct irqhandler nubus_handler[8];
+
+static struct irqhandler *handler_table[8];
+
+/*
+ * This array hold the rest of parameters of int handlers: type
+ * (slow,fast,prio) and the name of the handler. These values are only
+ * accessed from C
+ */
+static struct irqparam via1_param[8];
+static struct irqparam via2_param[8];
+static struct irqparam rbv_param[8];
+static struct irqparam scc_param[8];
+static struct irqparam nubus_param[8];
+
+static struct irqparam *param_table[8];
+
+/*
+ * This array holds the 'disabled' and 'pending' software flags maintained
+ * by mac_{enable,disable}_irq and the generic via_irq function.
+ */
+
+static struct irqflags irq_flags[8];
+
+/*
+ * This array holds the pointers to the various VIA or other interrupt
+ * controllers
+ */
+
+static volatile unsigned char *via_table[8];
+
+#ifdef VIABASE_WEIRDNESS
+/*
+ * VIA2 / RBV default base address
+ */
+
+volatile unsigned char *via2_regp = ((volatile unsigned char *)VIA2_BAS);
+volatile unsigned char *rbv_regp = ((volatile unsigned char *)VIA2_BAS_IIci);
+#endif
+
+/*
+ * Flags to control via2 / rbv behaviour
+ */
+
+static int via2_is_rbv = 0;
+static int rbv_clear = 0;
+
+/*
+ * console_loglevel determines NMI handler function
+ */
+
+extern int console_loglevel;
+
+/*
+ * ADB test hooks
+ */
+extern int in_keybinit;
+void adb_queue_poll(void);
+
+/* Defined in entry.S; only increments 'num_spurious' */
+asmlinkage void bad_interrupt(void);
+
+void nubus_wtf(int slot, void *via, struct pt_regs *regs);
+
+void mac_nmi_handler(int irq, void *dev_id, struct pt_regs *regs);
+void mac_debug_handler(int irq, void *dev_id, struct pt_regs *regs);
+
+static void via_do_nubus(int slot, void *via, struct pt_regs *regs);
+
+/*#define DEBUG_VIA*/
+
+void mac_init_IRQ(void)
+{
+ int i;
+
+ mac_debugging_penguin(6);
+
+#ifdef DEBUG_MACINTS
+ printk("Mac interrupt stuff initializing ...\n");
+#endif
+ /* initialize the hardwired (primary, autovector) IRQs */
+
+ /* level 1 IRQ: VIA1, always present */
+ sys_request_irq(1, via1_irq, IRQ_FLG_LOCK, "via1", via1_irq);
+
+ /* via2 or rbv?? */
+ if (macintosh_config->via_type == MAC_VIA_IIci) {
+ /* VIA2 is part of the RBV: different base, other offsets */
+ via2_is_rbv = 1;
+ /* LC III weirdness: IFR seems to behave like VIA2 */
+ /* FIXME: maybe also for LC II ?? */
+ if (macintosh_config->ident == MAC_MODEL_LCIII) {
+ rbv_clear = 0x0;
+ } else {
+ rbv_clear = 0x80;
+ }
+ /* level 2 IRQ: RBV/OSS; we only care about RBV for now */
+ sys_request_irq(2, rbv_irq, IRQ_FLG_LOCK, "rbv", rbv_irq);
+ } else
+ /* level 2 IRQ: VIA2 */
+ sys_request_irq(2, via2_irq, IRQ_FLG_LOCK, "via2", via2_irq);
+
+ /*
+ * level 4 IRQ: SCC - use 'master' interrupt routine that calls the
+ * registered channel-specific interrupts in turn.
+ * Currently, one interrupt per channel is used, solely
+ * to pass the correct async_info as parameter!
+ */
+#if 0 /* doesn't seem to work yet */
+ sys_request_irq(4, mac_SCC_handler, IRQ_FLG_STD, "INT4", mac_SCC_handler);
+#else
+ sys_request_irq(4, mac_debug_handler, IRQ_FLG_STD, "INT4", mac_debug_handler);
+#endif
+ /* Alan uses IRQ 5 for SCC ?? */
+ sys_request_irq(5, mac_debug_handler, IRQ_FLG_STD, "INT5", mac_debug_handler);
+
+ /* level 6 */
+ sys_request_irq(6, mac_bang, IRQ_FLG_LOCK, "offswitch", mac_bang);
+
+ /* level 7 (or NMI) : debug stuff */
+ sys_request_irq(7, mac_nmi_handler, IRQ_FLG_STD, "NMI", mac_nmi_handler);
+
+ /* initialize the handler tables for VIAs */
+ for (i = 0; i < 8; i++) {
+ via1_handler[i].handler = mac_default_handler;
+ via1_handler[i].dev_id = NULL;
+ via1_param[i].flags = IRQ_FLG_STD;
+ via1_param[i].devname = NULL;
+
+ via2_handler[i].handler = mac_default_handler;
+ via2_handler[i].dev_id = NULL;
+ via2_param[i].flags = IRQ_FLG_STD;
+ via2_param[i].devname = NULL;
+
+ rbv_handler[i].handler = mac_default_handler;
+ rbv_handler[i].dev_id = NULL;
+ rbv_param[i].flags = IRQ_FLG_STD;
+ rbv_param[i].devname = NULL;
+
+ scc_handler[i].handler = mac_default_handler;
+ scc_handler[i].dev_id = NULL;
+ scc_param[i].flags = IRQ_FLG_STD;
+ scc_param[i].devname = NULL;
+
+ /* NUBUS interrupts routed through VIA2 slot 2 - special */
+ nubus_handler[i].handler = nubus_wtf;
+ nubus_handler[i].dev_id = NULL;
+ nubus_param[i].flags = IRQ_FLG_STD;
+ nubus_param[i].devname = NULL;
+
+ }
+
+ /* initialize the handler tables (level 1 -> via_handler[0] !!!) */
+ via_table[0] = via1_regp;
+ handler_table[0] = &via1_handler[0];
+ param_table[0] = &via1_param[0];
+
+ if (via2_is_rbv) {
+ via_table[1] = rbv_regp;
+ handler_table[1] = &rbv_handler[0];
+ param_table[1] = &rbv_param[0];
+ } else {
+ via_table[1] = via2_regp;
+ handler_table[1] = &via2_handler[0];
+ param_table[1] = &via2_param[0];
+ }
+ via_table[2] = NULL;
+ via_table[3] = NULL;
+
+ handler_table[2] = &rbv_handler[0];
+ handler_table[3] = &nubus_handler[0];
+
+ param_table[2] = &rbv_param[0];
+ param_table[3] = &nubus_param[0];
+
+ mac_debugging_penguin(7);
+#ifdef DEBUG_MACINTS
+ printk("Mac interrupt init done!\n");
+#endif
+}
+
+/*
+ * We have no machine specific interrupts on a macintoy
+ * Yet, we need to register/unregister interrupts ... :-)
+ * Currently unimplemented: Test for valid irq number, chained irqs,
+ * Nubus interrupts.
+ */
+
+int mac_request_irq (unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
+ unsigned long flags, const char *devname, void *dev_id)
+{
+ int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
+ int irqidx = (irq & IRQ_IDX_MASK);
+ struct irqhandler *via_handler;
+ struct irqparam *via_param;
+ volatile unsigned char *via;
+
+#ifdef DEBUG_MACINTS
+ printk ("%s: IRQ %d on VIA%d[%d] requested from %s\n",
+ __FUNCTION__, irq, srcidx+1, irqidx, devname);
+#endif
+
+ if (flags < IRQ_TYPE_SLOW || flags > IRQ_TYPE_PRIO) {
+ printk ("%s: Bad irq type %ld requested from %s\n",
+ __FUNCTION__, flags, devname);
+ return -EINVAL;
+ }
+
+ /* figure out what VIA is handling this irq */
+ if (irq < IRQ_IDX(IRQ_VIA1_1) || irq >= IRQ_IDX(IRQ_NUBUS_1)) {
+ /* non-via irqs unimplemented */
+ printk ("%s: Bad irq source %d on VIA %d requested from %s\n",
+ __FUNCTION__, irq, srcidx, devname);
+ return -EINVAL;
+ }
+
+ /* figure out if SCC pseudo-irq */
+ if (irq >= IRQ_IDX(IRQ_SCC) && irq < IRQ_IDX(IRQ_NUBUS_1)) {
+ /* set specific SCC handler */
+ scc_handler[irqidx].handler = handler;
+ scc_handler[irqidx].dev_id = dev_id;
+ scc_param[irqidx].flags = flags;
+ scc_param[irqidx].devname = devname;
+ /* and done! */
+ return 0;
+ }
+
+ via = (volatile unsigned char *) via_table[srcidx];
+ if (!via)
+ return -EINVAL;
+
+ via_handler = handler_table[srcidx];
+ via_param = param_table[srcidx];
+
+ /* check for conflicts or possible replacement */
+
+ /* set the handler - no chained irqs yet !! */
+ via_handler[irqidx].handler = handler;
+ via_handler[irqidx].dev_id = dev_id;
+ via_param[irqidx].flags = flags;
+ via_param[irqidx].devname = devname;
+
+ /* and turn it on ... */
+ if (srcidx == SRC_VIA2 && via2_is_rbv)
+ via_write(via, rIER, via_read(via, rIER)|0x80|(1<<(irqidx)));
+ else
+ via_write(via, vIER, via_read(via, vIER)|0x80|(1<<(irqidx)));
+
+
+ if (irq == IRQ_IDX(IRQ_MAC_SCSI)) {
+ /*
+ * Set vPCR for SCSI interrupts. (what about RBV here?)
+ */
+ via_write(via, vPCR, 0x66);
+ }
+
+ return 0;
+}
+
+void mac_free_irq (unsigned int irq, void *dev_id)
+{
+ unsigned long flags;
+ int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
+ int irqidx = (irq & IRQ_IDX_MASK);
+ struct irqhandler *via_handler;
+ struct irqparam *via_param;
+ volatile unsigned char *via;
+
+#ifdef DEBUG_MACINTS
+ printk ("%s: IRQ %d on VIA%d[%d] freed\n",
+ __FUNCTION__, irq, srcidx+1, irqidx);
+#endif
+
+ /* figure out what VIA is handling this irq */
+ if (irq < IRQ_IDX(IRQ_VIA1_1) || irq >= IRQ_IDX(IRQ_NUBUS_1)) {
+ /* non-via irqs unimplemented */
+ return;
+ }
+
+ save_flags(flags);
+ cli();
+
+ /* figure out if SCC pseudo-irq */
+ if (irq >= IRQ_IDX(IRQ_SCC) && irq < IRQ_IDX(IRQ_NUBUS_1)) {
+ /* clear specific SCC handler */
+ scc_handler[irqidx].handler = mac_default_handler;
+ scc_handler[irqidx].dev_id = NULL;
+ scc_param[irqidx].flags = IRQ_FLG_STD;
+ scc_param[irqidx].devname = NULL;
+ /* and done! */
+ restore_flags(flags);
+ return;
+ }
+
+ via = (volatile unsigned char *) via_table[srcidx];
+ via_handler = handler_table[srcidx];
+ via_param = param_table[srcidx];
+
+ if ( !via || (via_handler[irqidx].dev_id != dev_id) ) {
+ restore_flags(flags);
+ goto not_found;
+ }
+
+ /* clear the handler - no chained irqs yet !! */
+ via_handler[irqidx].handler = mac_default_handler;
+ via_handler[irqidx].dev_id = NULL;
+ via_param[irqidx].flags = IRQ_FLG_STD;
+ via_param[irqidx].devname = NULL;
+
+ /* and turn it off */
+ if (srcidx == SRC_VIA2 && via2_is_rbv)
+ via_write(via, rIER, (via_read(via, rIER)&(1<<irqidx)));
+ else
+ via_write(via, vIER, (via_read(via, vIER)&(1<<irqidx)));
+
+ restore_flags(flags);
+ return;
+
+not_found:
+ printk("%s: tried to remove invalid irq\n", __FUNCTION__);
+ return;
+
+}
+
+/*
+ * {en,dis}able_irq have the usual semantics of temporary blocking the
+ * interrupt, but not loosing requests that happen between disabling and
+ * enabling. On Atari, this is done with the MFP mask registers.
+ *
+ * On the Mac, this isn't possible: there is no VIA mask register.
+ * Needs to be implemented in software, setting 'mask' bits in a separate
+ * struct for each interrupt controller. These mask bits need to be checked
+ * by the VIA interrupt routine which should ignore requests for masked IRQs
+ * (after possibly ack'ing them).
+ *
+ * On second thought: some of the IRQ sources _can_ be turned off via bits
+ * in the VIA output registers. Need to check this ...
+ *
+ * TBI: According to the VIA docs, clearing a bit in the IER has the effect of
+ * blocking generation of the interrupt, but the internal interrupt condition
+ * is preserved. So the IER might be used as mask register here, and turnon_irq
+ * would need to clear the interrupt bit in the IFR to prevent getting an
+ * interrupt at all.
+ *
+ * Implementation note: the irq no's here are the _machspec_ irqs, hence the
+ * hack with srcidx to figure out which VIA/RBV handles the interrupt.
+ * That's fundamentally different when it comes to the interrupt handlers
+ * proper: these get the interrupt level no. as argument, all information about
+ * which source triggered the int. is buried in the VIA IFR ... The int. level
+ * points us to the proper handler, so we could do a sanity check there ...
+ */
+
+void mac_enable_irq (unsigned int irq)
+{
+ int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
+ int irqidx = (irq & IRQ_IDX_MASK);
+
+ irq_flags[srcidx].disabled &= ~(1<<irqidx);
+ /*
+ * Call handler here if irq_flags[srcidx].pending & 1<<irqidx ??
+ * The structure of via_irq prevents this, sort of: it warns if
+ * no true events are pending. Maybe that's being changed ...
+ * Other problem: is it always possible to call an interrupt handler,
+ * or should that depend on the current interrupt level?
+ */
+}
+
+void mac_disable_irq (unsigned int irq)
+{
+ int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
+ int irqidx = (irq & IRQ_IDX_MASK);
+
+ irq_flags[srcidx].disabled |= (1<<irqidx);
+}
+
+/*
+ * In opposite to {en,dis}able_irq, requests between turn{off,on}_irq are not
+ * "stored". This is done with the VIA interrupt enable register
+ */
+
+void mac_turnon_irq( unsigned int irq )
+{
+ int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
+ int irqidx = (irq & IRQ_IDX_MASK);
+ volatile unsigned char *via;
+
+ via = (volatile unsigned char *) via_table[srcidx];
+ if (!via)
+ return;
+
+ if (srcidx == SRC_VIA2 && via2_is_rbv)
+ via_write(via, rIER, via_read(via, rIER)|0x80|(1<<(irqidx)));
+ else
+ via_write(via, vIER, via_read(via, vIER)|0x80|(1<<(irqidx)));
+
+}
+
+void mac_turnoff_irq( unsigned int irq )
+{
+ int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
+ int irqidx = (irq & IRQ_IDX_MASK);
+ volatile unsigned char *via;
+
+ via = (volatile unsigned char *) via_table[srcidx];
+ if (!via)
+ return;
+
+ if (srcidx == SRC_VIA2 && via2_is_rbv)
+ via_write(via, rIER, (via_read(via, rIER)&(1<<irqidx)));
+ else
+ via_write(via, vIER, (via_read(via, vIER)&(1<<irqidx)));
+}
+
+/*
+ * These functions currently only handle the software-maintained irq pending
+ * list for disabled irqs - manipulating the actual irq flags in the via would
+ * require clearing single bits in the via, such as (probably)
+ * via_write(via, vIFR, (via_read(via, vIFR)&(1<<irqidx))); - don't know if
+ * this has side-effects ...
+ */
+
+void mac_clear_pending_irq( unsigned int irq )
+{
+ int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
+ int irqidx = (irq & IRQ_IDX_MASK);
+
+ irq_flags[srcidx].pending &= ~(1<<irqidx);
+}
+
+int mac_irq_pending( unsigned int irq )
+{
+ int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
+ int irqidx = (irq & IRQ_IDX_MASK);
+
+ return (irq_flags[srcidx].pending & (1<<irqidx));
+}
+
+int mac_get_irq_list (char *buf)
+{
+ return 0;
+}
+
+void via_scsi_clear(void)
+{
+ volatile unsigned char deep_magic;
+ if (via2_is_rbv) {
+ via_write(rbv_regp, rIFR, (1<<3)|(1<<0)|0x80);
+ deep_magic = via_read(rbv_regp, rBufB);
+ } else
+ deep_magic = via_read(via2_regp, vBufB);
+ mac_enable_irq( IRQ_IDX(IRQ_MAC_SCSI) );
+}
+
+
+void mac_default_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+#ifdef DEBUG_VIA
+ printk("Unexpected IRQ %d\n", irq);
+#endif
+}
+
+static int num_debug[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+
+void mac_debug_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+ if (num_debug[irq] < 10) {
+ printk("DEBUG: Unexpected IRQ %d\n", irq);
+ num_debug[irq]++;
+ }
+}
+
+void mac_nmi_handler(int irq, void *dev_id, struct pt_regs *fp)
+{
+ /*
+ * generate debug output on NMI switch if 'debug' kernel option given
+ * (only works with Penguin!)
+ */
+ if ( console_loglevel >= 8 ) {
+#if 0
+ show_state();
+ printk("PC: %08lx\nSR: %04x SP: %p\n", fp->pc, fp->sr, fp);
+ printk("d0: %08lx d1: %08lx d2: %08lx d3: %08lx\n",
+ fp->d0, fp->d1, fp->d2, fp->d3);
+ printk("d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n",
+ fp->d4, fp->d5, fp->a0, fp->a1);
+
+ if (STACK_MAGIC != *(unsigned long *)current->kernel_stack_page)
+ printk("Corrupted stack page\n");
+ printk("Process %s (pid: %d, stackpage=%08lx)\n",
+ current->comm, current->pid, current->kernel_stack_page);
+ if (intr_count == 1)
+ dump_stack((struct frame *)fp);
+#else
+ /* printk("NMI "); */
+#endif
+ }
+}
+
+/*
+ * The generic VIA interrupt routines (shamelessly stolen from Alan Cox's
+ * via6522.c :-), disable/pending masks added.
+ * The int *viaidx etc. is just to keep the prototype happy ...
+ */
+
+static void via_irq(unsigned char *via, int *viaidx, struct pt_regs *regs)
+{
+ unsigned char events=(via_read(via, vIFR)&via_read(via,vIER))&0x7F;
+ int i;
+ int ct = 0;
+ struct irqhandler *via_handler = handler_table[*viaidx];
+ struct irqparam *via_param = param_table[*viaidx];
+
+ /* to be changed, possibly: for each non'masked', enabled IRQ, read
+ * flag bit, ack and call handler ...
+ * Currently: all pending irqs ack'ed en bloc.
+ * If ack for masked IRQ required: keep 'pending' info separate.
+ */
+
+ /* shouldn't we disable interrupts here ?? */
+
+
+ /*
+ * Shouldnt happen
+ */
+
+ if(events==0)
+ {
+ printk("via_irq: nothing pending!\n");
+ return;
+ }
+
+#ifdef DEBUG_VIA
+ /*
+ * limited verbosity for VIA interrupts
+ */
+#if 0
+ if ( (*viaidx == 0 && events != 1<<6) /* timer int */
+ || (*viaidx == 1 && events != 1<<3) ) /* SCSI IRQ */
+#else
+ if ( *viaidx == 0 && (events & 1<<2) )
+#endif
+ printk("via_irq: irq %d events %x !\n", (*viaidx)+1, events);
+#endif
+
+ do {
+ /*
+ * Clear the pending flag
+ */
+
+ via_write(via, vIFR, events);
+
+ /*
+ * Now see what bits are raised
+ */
+
+ for(i=0;i<7;i++)
+ {
+ /* determine machspec. irq no. */
+ int irq = ((*viaidx)+1)* 8 + i;
+ /* call corresponding handlers */
+ if (events&(1<<i)) {
+ if (irq_flags[*viaidx].disabled & (1<<i)) {
+ /* irq disabled -> mark pending */
+ irq_flags[*viaidx].pending |= (1<<i);
+ } else {
+ /* irq enabled -> call handler */
+ (via_handler[i].handler)(irq, via, regs);
+ }
+ }
+ /* and call handlers for pending irqs - first ?? */
+ if ( (irq_flags[*viaidx].pending & (1<<i))
+ && !(irq_flags[*viaidx].disabled & (1<<i)) ) {
+ /* call handler for re-enabled irq */
+ (via_handler[i].handler)(irq, via, regs);
+ /* and clear pending flag :-) */
+ irq_flags[*viaidx].pending &= ~(1<<i);
+ }
+ }
+
+ /*
+ * And done ... check for more punishment!
+ */
+
+ events=(via_read(via, vIFR)&via_read(via,vIER))&0x7F;
+ ct++;
+ if(events && ct>8)
+ {
+ printk("via%d: stuck events %x\n", (*viaidx)+1, events);
+ break;
+ }
+ }
+ while(events);
+#if 0
+ scsi_mac_polled();
+#endif
+}
+
+/*
+ * Caution: the following stuff is called from process_int as _autovector_
+ * system interrupts. So irq is always in the range 0-7 :-( and the selection
+ * of the appropriate VIA is up to the irq handler here based on the autovec
+ * irq number. There's no information whatsoever about which source on the VIA
+ * triggered the int - and that's what the machspec irq no's are about.
+ * Broken design :-((((
+ */
+
+/*
+ * System interrupts
+ */
+
+void via1_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+ int srcidx = IRQ_IDX(irq) - 1;
+ via_irq((unsigned char *)via1_regp, &srcidx, regs);
+}
+
+
+/*
+ * Nubus / SCSI interrupts, VIA style (could be wrapped into via1_irq or
+ * via_irq directly by selecting the regp based on the irq!)
+ */
+
+void via2_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+ int srcidx = IRQ_IDX(irq) - 1;
+ via_irq((unsigned char *)via2_regp, &srcidx, regs);
+}
+
+/*
+ * Nubus / SCSI interrupts; RBV style
+ * The RBV is different. RBV appears to stand for randomly broken
+ * VIA (or even real broken VIA).
+ */
+
+void rbv_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+ int srcidx = IRQ_IDX(irq) - 1; /* MUST be 1 !! */
+ volatile unsigned char *via = rbv_regp;
+ unsigned char events=(via_read(via, rIFR)&via_read(via,rIER))&0x7F;
+ int i;
+ int ct = 0;
+ struct irqhandler *via_handler = handler_table[srcidx];
+ struct irqparam *via_param = param_table[srcidx];
+
+#ifdef DEBUG_VIA
+ /*
+ * limited verbosity for RBV interrupts (add more if needed)
+ */
+ if ( srcidx == 1 && events != 1<<3 ) /* SCSI IRQ */
+ printk("rbv_irq: irq %d (%d) events %x !\n", irq, srcidx+1, events);
+#endif
+
+ /* to be changed, possibly: for each non'masked', enabled IRQ, read
+ * flag bit, ack and call handler ...
+ * Currently: all pending irqs ack'ed en bloc.
+ * If ack for masked IRQ required: keep 'pending' info separate.
+ */
+
+ /* shouldn't we disable interrupts here ?? */
+
+
+ /*
+ * Shouldnt happen
+ */
+
+ if(events==0)
+ {
+ printk("rbv_irq: nothing pending!\n");
+ return;
+ }
+
+ do {
+ /*
+ * Clear the pending flag
+ */
+
+ via_write(via, rIFR, events | rbv_clear);
+
+ /*
+ * Now see what bits are raised
+ */
+
+ for(i=0;i<7;i++)
+ {
+ /* determine machspec. irq no. */
+ int irq = (srcidx+1)* 8 + i;
+ /* call corresponding handlers */
+ if (events&(1<<i)) {
+ if (irq_flags[srcidx].disabled & (1<<i))
+ /* irq disabled -> mark pending */
+ irq_flags[srcidx].pending |= (1<<i);
+ else
+ /* irq enabled -> call handler */
+ (via_handler[i].handler)(irq, via, regs);
+ }
+ /* and call handlers for pending irqs - first ?? */
+ if ( (irq_flags[srcidx].pending & (1<<i))
+ && !(irq_flags[srcidx].disabled & (1<<i)) ) {
+ /* call handler for re-enabled irq */
+ (via_handler[i].handler)(irq, via, regs);
+ /* and clear pending flag :-) */
+ irq_flags[srcidx].pending &= ~(1<<i);
+ }
+ }
+
+ /*
+ * And done ... check for more punishment!
+ */
+
+ events=(via_read(via, rIFR)&via_read(via,rIER))&0x7F;
+ ct++;
+ if(events && ct>8)
+ {
+ printk("rbv: stuck events %x\n",events);
+ for(i=0;i<7;i++)
+ {
+ if(events&(1<<i))
+ {
+ printk("rbv - bashing source %d\n",
+ i);
+ via_write(via, rIER, 1<<i);
+ via_write(via, rIFR, (1<<i) | rbv_clear);
+ }
+ }
+ break;
+ }
+ }
+ while(events);
+#if 0
+ scsi_mac_polled();
+#endif
+}
+
+/*
+ * Unexpected via interrupt
+ */
+
+void via_wtf(int slot, void *via, struct pt_regs *regs)
+{
+#ifdef DEBUG_VIA
+ printk("Unexpected event %d on via %p\n",slot,via);
+#endif
+}
+
+void nubus_wtf(int slot, void *via, struct pt_regs *regs)
+{
+#ifdef DEBUG_VIA
+ printk("Unexpected interrupt on nubus slot %d\n",slot);
+#endif
+}
+
+void mac_SCC_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+ int i;
+
+ for (i = 0; i < 8; i++)
+ if (scc_handler[i].handler != mac_default_handler)
+ (scc_handler[i].handler)(i, scc_handler[i].dev_id, regs);
+
+}
+
+/*
+ * Nubus handling
+ * Caution: slot numbers are currently 'hardcoded' to the range 9-15!
+ * In general, the same request_irq() functions as above can be used if
+ * the interrupt numbers specifed in macints.h are used.
+ */
+
+static int nubus_active=0;
+
+int nubus_request_irq(int slot, void (*handler)(int,void *,struct pt_regs *))
+{
+ slot-=9;
+/* printk("Nubus request irq for slot %d\n",slot);*/
+ if(nubus_handler[slot].handler!=nubus_wtf)
+ return -EBUSY;
+ nubus_handler[slot].handler=handler;
+ nubus_handler[slot].dev_id =handler;
+ nubus_param[slot].flags = IRQ_FLG_LOCK;
+ nubus_param[slot].devname = "nubus";
+
+ /*
+ * if no nubus int. was active previously: register the main nubus irq
+ * handler now!
+ */
+
+ if (!nubus_active)
+ request_irq(IRQ_MAC_NUBUS, via_do_nubus, IRQ_FLG_LOCK,
+ "nubus dispatch", via_do_nubus);
+
+ nubus_active|=1<<slot;
+/* printk("program slot %d\n",slot);*/
+/* printk("via2=%p\n",via2);*/
+#if 0
+ via_write(via2, vDirA,
+ via_read(via2, vDirA)|(1<<slot));
+ via_write(via2, vBufA, 0);
+#endif
+ if (!via2_is_rbv) {
+ /* Make sure the bit is an input */
+ via_write(via2_regp, vDirA,
+ via_read(via2_regp, vDirA)&~(1<<slot));
+ }
+/* printk("nubus irq on\n");*/
+ return 0;
+}
+
+int nubus_free_irq(int slot)
+{
+ slot-=9;
+ nubus_active&=~(1<<slot);
+ nubus_handler[slot].handler=nubus_wtf;
+ nubus_handler[slot].dev_id = NULL;
+ nubus_param[slot].flags = IRQ_FLG_STD;
+ nubus_param[slot].devname = NULL;
+
+ if (via2_is_rbv)
+ via_write(rbv_regp, rBufA, 1<<slot);
+ else {
+ via_write(via2_regp, vDirA,
+ via_read(via2_regp, vDirA)|(1<<slot));
+ via_write(via2_regp, vBufA, 1<<slot);
+ via_write(via2_regp, vDirA,
+ via_read(via2_regp, vDirA)&~(1<<slot));
+ }
+ return 0;
+}
+
+static void via_do_nubus(int slot, void *via, struct pt_regs *regs)
+{
+ unsigned char map;
+ int i;
+ int ct=0;
+
+/* printk("nubus interrupt\n");*/
+
+ /* lock the nubus interrupt */
+ if (via2_is_rbv)
+ via_write(rbv_regp, rIFR, 0x82);
+ else
+ via_write(via2_regp, vIFR, 0x82);
+
+ while(1)
+ {
+ if (via2_is_rbv)
+ map = ~via_read(rbv_regp, rBufA);
+ else
+ map = ~via_read(via2_regp, vBufA);
+
+#ifdef DEBUG_VIA
+ printk("nubus_irq: map %x mask %x\n", map, nubus_active);
+#endif
+ if( (map = (map&nubus_active)) ==0 )
+ break;
+
+ if(ct++>2)
+ {
+ printk("nubus stuck events - %d/%d\n", map, nubus_active);
+ return;
+ }
+
+ for(i=0;i<7;i++)
+ {
+ if(map&(1<<i))
+ {
+ (nubus_handler[i].handler)(i+9, via, regs);
+ }
+ }
+ /* clear it */
+ if (via2_is_rbv)
+ via_write(rbv_regp, rIFR, 0x02);
+ else
+ via_write(via2_regp, vIFR, 0x02);
+
+ }
+
+ /* And done */
+}
diff --git a/arch/m68k/mac/mackeyb.c b/arch/m68k/mac/mackeyb.c
new file mode 100644
index 000000000..fe3a860c8
--- /dev/null
+++ b/arch/m68k/mac/mackeyb.c
@@ -0,0 +1,765 @@
+/*
+ * linux/arch/m68k/mac/mackeyb.c
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+/*
+ * misc. keyboard stuff (everything not in adb-bus.c or keyb_m68k.c)
+ */
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/kd.h>
+#include <linux/tty.h>
+#include <linux/console.h>
+#include <linux/interrupt.h>
+/* keyb */
+#include <linux/keyboard.h>
+#include <linux/random.h>
+#include <linux/delay.h>
+/* keyb */
+
+#include <asm/setup.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/pgtable.h>
+#include <asm/machdep.h>
+
+#include <asm/macintosh.h>
+#include <asm/macints.h>
+/* for keyboard_input stuff */
+#include <asm/adb.h>
+#define KEYB_KEYREG 0 /* register # for key up/down data */
+#define KEYB_LEDREG 2 /* register # for leds on ADB keyboard */
+#define MOUSE_DATAREG 0 /* reg# for movement/button codes from mouse */
+/* end keyboard_input stuff */
+
+#include <asm/keyboard.h>
+#include <linux/kbd_kern.h>
+#include <linux/kbd_ll.h>
+
+static void kbd_repeat(unsigned long);
+static struct timer_list repeat_timer = { NULL, NULL, 0, 0, kbd_repeat };
+static int last_keycode;
+
+static void input_keycode(int, int);
+
+extern struct kbd_struct kbd_table[];
+
+extern void handle_scancode(unsigned char);
+extern void put_queue(int);
+
+/* keyb */
+static void mac_leds_done(struct adb_request *);
+static void keyboard_input(unsigned char *, int, struct pt_regs *);
+static void mouse_input(unsigned char *, int, struct pt_regs *);
+/* Hook for mouse driver */
+void (*mac_mouse_interrupt_hook) (char *);
+int mac_emulate_button2;
+int mac_emulate_button3;
+/* The mouse driver - for debugging */
+extern void mac_mouse_interrupt(char *);
+/* end keyb */
+
+/* this map indicates which keys shouldn't autorepeat. */
+static unsigned char dont_repeat[128] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* esc...option */
+ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, /* num lock */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, /* scroll lock */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+/*
+ * Mac private key maps
+ */
+u_short mac_plain_map[NR_KEYS] = {
+ 0xfb61, 0xfb73, 0xfb64, 0xfb66, 0xfb68, 0xfb67, 0xfb7a, 0xfb78,
+ 0xfb63, 0xfb76, 0xf200, 0xfb62, 0xfb71, 0xfb77, 0xfb65, 0xfb72,
+ 0xfb79, 0xfb74, 0xf031, 0xf032, 0xf033, 0xf034, 0xf036, 0xf035,
+ 0xf03d, 0xf039, 0xf037, 0xf02d, 0xf038, 0xf030, 0xf05d, 0xfb6f,
+ 0xfb75, 0xf05b, 0xfb69, 0xfb70, 0xf201, 0xfb6c, 0xfb6a, 0xf027,
+ 0xfb6b, 0xf03b, 0xf05c, 0xf02c, 0xf02f, 0xfb6e, 0xfb6d, 0xf02e,
+ 0xf009, 0xf020, 0xf060, 0xf07f, 0xf200, 0xf01b, 0xf702, 0xf703,
+ 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200,
+ 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
+ 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
+ 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305,
+ 0xf306, 0xf307, 0xfb61, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200,
+ 0xf104, 0xf105, 0xf106, 0xf102, 0xf107, 0xf108, 0xf200, 0xf10a,
+ 0xf200, 0xf10c, 0xf200, 0xf209, 0xf200, 0xf109, 0xf200, 0xf10b,
+ 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf103, 0xf117,
+ 0xf101, 0xf119, 0xf100, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+u_short mac_shift_map[NR_KEYS] = {
+ 0xfb41, 0xfb53, 0xfb44, 0xfb46, 0xfb48, 0xfb47, 0xfb5a, 0xfb58,
+ 0xfb43, 0xfb56, 0xf200, 0xfb42, 0xfb51, 0xfb57, 0xfb45, 0xfb52,
+ 0xfb59, 0xfb54, 0xf021, 0xf040, 0xf023, 0xf024, 0xf05e, 0xf025,
+ 0xf02b, 0xf028, 0xf026, 0xf05f, 0xf02a, 0xf029, 0xf07d, 0xfb4f,
+ 0xfb55, 0xf07b, 0xfb49, 0xfb50, 0xf201, 0xfb4c, 0xfb4a, 0xf022,
+ 0xfb4b, 0xf03a, 0xf07c, 0xf03c, 0xf03f, 0xfb4e, 0xfb4d, 0xf03e,
+ 0xf009, 0xf020, 0xf07e, 0xf07f, 0xf200, 0xf01b, 0xf702, 0xf703,
+ 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200,
+ 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
+ 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
+ 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305,
+ 0xf306, 0xf307, 0xfb41, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200,
+ 0xf10e, 0xf10f, 0xf110, 0xf10c, 0xf111, 0xf112, 0xf200, 0xf10a,
+ 0xf200, 0xf10c, 0xf200, 0xf203, 0xf200, 0xf113, 0xf200, 0xf10b,
+ 0xf200, 0xf11d, 0xf115, 0xf114, 0xf20b, 0xf116, 0xf10d, 0xf117,
+ 0xf10b, 0xf20a, 0xf10a, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+u_short mac_altgr_map[NR_KEYS] = {
+ 0xf914, 0xfb73, 0xf917, 0xf919, 0xfb68, 0xfb67, 0xfb7a, 0xfb78,
+ 0xf916, 0xfb76, 0xf200, 0xf915, 0xfb71, 0xfb77, 0xf918, 0xfb72,
+ 0xfb79, 0xfb74, 0xf200, 0xf040, 0xf200, 0xf024, 0xf200, 0xf200,
+ 0xf200, 0xf05d, 0xf07b, 0xf05c, 0xf05b, 0xf07d, 0xf07e, 0xfb6f,
+ 0xfb75, 0xf200, 0xfb69, 0xfb70, 0xf201, 0xfb6c, 0xfb6a, 0xf200,
+ 0xfb6b, 0xf200, 0xf200, 0xf200, 0xf200, 0xfb6e, 0xfb6d, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf702, 0xf703,
+ 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200,
+ 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
+ 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
+ 0xf200, 0xf200, 0xf90a, 0xf90b, 0xf90c, 0xf90d, 0xf90e, 0xf90f,
+ 0xf910, 0xf911, 0xf914, 0xf912, 0xf913, 0xf200, 0xf200, 0xf200,
+ 0xf510, 0xf511, 0xf512, 0xf50e, 0xf513, 0xf514, 0xf200, 0xf516,
+ 0xf200, 0xf10c, 0xf200, 0xf202, 0xf200, 0xf515, 0xf200, 0xf517,
+ 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf50f, 0xf117,
+ 0xf50d, 0xf119, 0xf50c, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+u_short mac_ctrl_map[NR_KEYS] = {
+ 0xf001, 0xf013, 0xf004, 0xf006, 0xf008, 0xf007, 0xf01a, 0xf018,
+ 0xf003, 0xf016, 0xf200, 0xf002, 0xf011, 0xf017, 0xf005, 0xf012,
+ 0xf019, 0xf014, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01e, 0xf01d,
+ 0xf200, 0xf200, 0xf01f, 0xf01f, 0xf07f, 0xf200, 0xf01d, 0xf00f,
+ 0xf015, 0xf01b, 0xf009, 0xf010, 0xf201, 0xf00c, 0xf00a, 0xf007,
+ 0xf00b, 0xf200, 0xf01c, 0xf200, 0xf07f, 0xf00e, 0xf00d, 0xf20e,
+ 0xf200, 0xf000, 0xf000, 0xf008, 0xf200, 0xf200, 0xf702, 0xf703,
+ 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200,
+ 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
+ 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
+ 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305,
+ 0xf306, 0xf307, 0xf001, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200,
+ 0xf104, 0xf105, 0xf106, 0xf102, 0xf107, 0xf108, 0xf200, 0xf10a,
+ 0xf200, 0xf10c, 0xf200, 0xf204, 0xf200, 0xf109, 0xf200, 0xf10b,
+ 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf103, 0xf117,
+ 0xf101, 0xf119, 0xf100, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+u_short mac_shift_ctrl_map[NR_KEYS] = {
+ 0xf001, 0xf013, 0xf004, 0xf006, 0xf008, 0xf007, 0xf01a, 0xf018,
+ 0xf003, 0xf016, 0xf200, 0xf002, 0xf011, 0xf017, 0xf005, 0xf012,
+ 0xf019, 0xf014, 0xf200, 0xf000, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf200, 0xf200, 0xf00f,
+ 0xf015, 0xf200, 0xf009, 0xf010, 0xf201, 0xf00c, 0xf00a, 0xf200,
+ 0xf00b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf00e, 0xf00d, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf702, 0xf703,
+ 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200,
+ 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
+ 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
+ 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305,
+ 0xf306, 0xf307, 0xf001, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf10c, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf200, 0xf117,
+ 0xf200, 0xf119, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf20c,
+};
+
+u_short mac_alt_map[NR_KEYS] = {
+ 0xf861, 0xf873, 0xf864, 0xf866, 0xf868, 0xf867, 0xf87a, 0xf878,
+ 0xf863, 0xf876, 0xf200, 0xf862, 0xf871, 0xf877, 0xf865, 0xf872,
+ 0xf879, 0xf874, 0xf831, 0xf832, 0xf833, 0xf834, 0xf836, 0xf835,
+ 0xf83d, 0xf839, 0xf837, 0xf82d, 0xf838, 0xf830, 0xf85d, 0xf86f,
+ 0xf875, 0xf85b, 0xf869, 0xf870, 0xf80d, 0xf86c, 0xf86a, 0xf827,
+ 0xf86b, 0xf83b, 0xf85c, 0xf82c, 0xf82f, 0xf86e, 0xf86d, 0xf82e,
+ 0xf809, 0xf820, 0xf860, 0xf87f, 0xf200, 0xf81b, 0xf702, 0xf703,
+ 0xf700, 0xf207, 0xf701, 0xf210, 0xf211, 0xf600, 0xf603, 0xf200,
+ 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
+ 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
+ 0xf200, 0xf200, 0xf900, 0xf901, 0xf902, 0xf903, 0xf904, 0xf905,
+ 0xf906, 0xf907, 0xf861, 0xf908, 0xf909, 0xf200, 0xf200, 0xf200,
+ 0xf504, 0xf505, 0xf506, 0xf502, 0xf507, 0xf508, 0xf200, 0xf50a,
+ 0xf200, 0xf10c, 0xf200, 0xf209, 0xf200, 0xf509, 0xf200, 0xf50b,
+ 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf503, 0xf117,
+ 0xf501, 0xf119, 0xf500, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+u_short mac_ctrl_alt_map[NR_KEYS] = {
+ 0xf801, 0xf813, 0xf804, 0xf806, 0xf808, 0xf807, 0xf81a, 0xf818,
+ 0xf803, 0xf816, 0xf200, 0xf802, 0xf811, 0xf817, 0xf805, 0xf812,
+ 0xf819, 0xf814, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf80f,
+ 0xf815, 0xf200, 0xf809, 0xf810, 0xf201, 0xf80c, 0xf80a, 0xf200,
+ 0xf80b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf80e, 0xf80d, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf702, 0xf703,
+ 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200,
+ 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
+ 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
+ 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305,
+ 0xf306, 0xf307, 0xf801, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200,
+ 0xf504, 0xf505, 0xf506, 0xf502, 0xf507, 0xf508, 0xf200, 0xf50a,
+ 0xf200, 0xf10c, 0xf200, 0xf200, 0xf200, 0xf509, 0xf200, 0xf50b,
+ 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf503, 0xf117,
+ 0xf501, 0xf119, 0xf500, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+extern unsigned int keymap_count;
+
+#if 0
+ushort *mac_key_maps[MAX_NR_KEYMAPS] = {
+ mac_plain_map, mac_shift_map, mac_altgr_map, 0,
+ mac_ctrl_map, mac_shift_ctrl_map, 0, 0,
+ mac_alt_map, 0, 0, 0,
+ mac_ctrl_alt_map, 0
+};
+#endif
+
+/*
+ * Misc. defines for testing
+ */
+
+extern int console_loglevel;
+
+static struct adb_request led_request;
+extern int in_keybinit;
+
+/*
+ * machdep keyboard routines, interface and key repeat method modeled after
+ * drivers/macintosh/keyb_mac.c
+ */
+
+int mac_kbd_translate(unsigned char keycode, unsigned char *keycodep,
+ char raw_mode)
+{
+ if (!raw_mode) {
+ /*
+ * Convert R-shift/control/option to L version.
+ * Remap keycode 0 (A) to the unused keycode 0x5a.
+ * Other parts of the system assume 0 is not a valid keycode.
+ */
+ switch (keycode) {
+ case 0x7b: keycode = 0x38; break; /* R-shift */
+ case 0x7c: keycode = 0x3a; break; /* R-option */
+ case 0x7d: keycode = 0x36; break; /* R-control */
+ case 0: keycode = 0x5a; break; /* A */
+ }
+ }
+ *keycodep = keycode;
+ return 1;
+}
+
+int mac_kbd_unexpected_up(unsigned char keycode)
+{
+ return 0x80;
+}
+
+static void
+keyboard_input(unsigned char *data, int nb, struct pt_regs *regs)
+{
+ /* first check this is from register 0 */
+ if (nb != 5 || (data[2] & 3) != KEYB_KEYREG)
+ return; /* ignore it */
+ kbd_pt_regs = regs;
+ input_keycode(data[3], 0);
+ if (!(data[4] == 0xff || (data[4] == 0x7f && data[3] == 0x7f)))
+ input_keycode(data[4], 0);
+}
+
+static void
+input_keycode(int keycode, int repeat)
+{
+ struct kbd_struct *kbd;
+ int up_flag;
+
+ kbd = kbd_table + fg_console;
+ up_flag = (keycode & 0x80);
+ keycode &= 0x7f;
+ if (!repeat)
+ del_timer(&repeat_timer);
+
+ /*
+ * XXX: Add mouse button 2+3 fake codes here if mouse open.
+ * As we only report up/down events, keep track of faked buttons.
+ * Really messy; might need to check if keyboard is in
+ * VC_RAW mode for X?.
+ * Might also want to know how many buttons need to be emulated.
+ * -> hide this as function in arch/m68k/mac ?
+ * Current emulation buttons: right alt/option and control
+ * (wanted: command and alt/option, or KP= and KP( ...)
+ * Debug version; might be rewritten to be faster on normal keys.
+ */
+ if (mac_mouse_interrupt_hook || console_loglevel >= 8) {
+ unsigned char button, button2, button3, fake_event;
+ static unsigned char button2state=0, button3state=0; /* up */
+ /* faked ADB packet: device type ff, handler 4 ! */
+ static char data[6] = { 0xff, 0x40, 0x3c, 0x80, 0x80, 0x80 };
+
+ button = 0;
+ fake_event = 0;
+ switch (keycode) { /* which 'button' ? */
+ case 0x7c: /* R-option */
+ button2 = (!up_flag); /* new state */
+ if (button2 != button2state) /* change ? */
+ button = 2;
+ button2state = button2; /* save state */
+ fake_event = 2;
+ break;
+ case 0x7d: /* R-control */
+ button3 = (!up_flag); /* new state */
+ if (button3 != button3state) /* change ? */
+ button = 3;
+ button3state = button3; /* save state */
+ fake_event = 3;
+ break;
+ }
+#ifdef DEBUG_ADBMOUSE
+ if (fake_event && console_loglevel >= 8)
+ printk("fake event: button2 %d button3 %d button %d\n",
+ button2state, button3state, button);
+#endif
+ if (button) { /* there's been a button state change */
+ /* fake a mouse packet : send all bytes, change one! */
+ data[button+2] = (up_flag ? 0x80 : 0);
+ if (mac_mouse_interrupt_hook)
+ mac_mouse_interrupt_hook(data);
+#ifdef DEBUG_ADBMOUSE
+ else
+ printk("mouse_fake: data %2x %2x %2x buttons %2x \n",
+ data[3], data[4], data[5],
+ ~( (data[3] & 0x80 ? 0 : 4)
+ | (data[4] & 0x80 ? 0 : 1)
+ | (data[5] & 0x80 ? 0 : 2) )&7 );
+#endif
+ }
+ /*
+ * for mouse 3-button emulation: don't process 'fake' keys!
+ * Keys might autorepeat, and console state gets generally messed
+ * up enough so that selection stops working.
+ */
+ if (fake_event)
+ return;
+ }
+
+ /*
+ * Convert R-shift/control/option to L version.
+ */
+ switch (keycode) {
+ case 0x7b: keycode = 0x38; break; /* R-shift */
+ case 0x7c: keycode = 0x3a; break; /* R-option */
+ case 0x7d: keycode = 0x36; break; /* R-control */
+ case 0x0: if (kbd->kbdmode != VC_RAW)
+ keycode = 0x5a; /* A; keycode 0 deprecated */
+ break;
+ }
+
+ if (kbd->kbdmode != VC_RAW) {
+ if (!up_flag && !dont_repeat[keycode]) {
+ last_keycode = keycode;
+ repeat_timer.expires = jiffies + (repeat? HZ/15: HZ/2);
+ add_timer(&repeat_timer);
+ }
+
+ /*
+ * XXX fix caps-lock behaviour by turning the key-up
+ * transition into a key-down transition.
+ * MSch: need to turn each caps-lock event into a down-up
+ * double event (keyboard code assumes caps-lock is a toggle)
+ */
+#if 0
+ if (keycode == 0x39 && up_flag && vc_kbd_led(kbd, VC_CAPSLOCK))
+ up_flag = 0;
+#else
+ if (keycode == 0x39) {
+ handle_scancode(keycode); /* down */
+ up_flag = 0x80; /* see below ... */
+ }
+#endif
+ }
+
+ handle_scancode(keycode + up_flag);
+}
+
+static void
+kbd_repeat(unsigned long xxx)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ input_keycode(last_keycode, 1);
+ restore_flags(flags);
+}
+
+ /* [ACA:23-Mar-97] Three button mouse support. This is designed to
+ function with MkLinux DR-2.1 style X servers. It only works with
+ three-button mice that conform to Apple's multi-button mouse
+ protocol. */
+
+ /*
+ The X server for MkLinux DR2.1 uses the following unused keycodes to
+ read the mouse:
+
+ 0x7e This indicates that the next two keycodes should be interpreted
+ as mouse information. The first following byte's high bit
+ represents the state of the left button. The lower seven bits
+ represent the x-axis acceleration. The lower seven bits of the
+ second byte represent y-axis acceleration.
+
+ 0x3f The x server interprets this keycode as a middle button
+ release.
+
+ 0xbf The x server interprets this keycode as a middle button
+ depress.
+
+ 0x40 The x server interprets this keycode as a right button
+ release.
+
+ 0xc0 The x server interprets this keycode as a right button
+ depress.
+
+ NOTES: There should be a better way of handling mice in the X server.
+ The MOUSE_ESCAPE code (0x7e) should be followed by three bytes instead
+ of two. The three mouse buttons should then, in the X server, be read
+ as the high-bits of all three bytes. The x and y motions can still be
+ in the first two bytes. Maybe I'll do this...
+ */
+
+ /*
+ Handler 4 -- Apple Extended mouse protocol.
+
+ For Apple's 3-button mouse protocol the data array will contain the
+ following values:
+
+ BITS COMMENTS
+ data[0] = 0000 0000 ADB packet identifer.
+ data[1] = 0100 0000 Extended protocol register.
+ Bits 6-7 are the device id, which should be 1.
+ Bits 4-5 are resolution which is in "units/inch".
+ The Logitech MouseMan returns these bits clear but it has
+ 200/300cpi resolution.
+ Bits 0-3 are unique vendor id.
+ data[2] = 0011 1100 Bits 0-1 should be zero for a mouse device.
+ Bits 2-3 should be 8 + 4.
+ Bits 4-7 should be 3 for a mouse device.
+ data[3] = bxxx xxxx Left button and x-axis motion.
+ data[4] = byyy yyyy Second button and y-axis motion.
+ data[5] = byyy bxxx Third button and fourth button. Y is additional
+ high bits of y-axis motion. XY is additional
+ high bits of x-axis motion.
+
+ NOTE: data[0] and data[2] are confirmed by the parent function and
+ need not be checked here.
+ */
+
+ /*
+ Handler 1 -- 100cpi original Apple mouse protocol.
+ Handler 2 -- 200cpi original Apple mouse protocol.
+
+ For Apple's standard one-button mouse protocol the data array will
+ contain the following values:
+
+ BITS COMMENTS
+ data[0] = 0000 0000 ADB packet identifer.
+ data[1] = ???? ???? (?)
+ data[2] = ???? ??00 Bits 0-1 should be zero for a mouse device.
+ data[3] = bxxx xxxx First button and x-axis motion.
+ data[4] = byyy yyyy Second button and y-axis motion.
+
+ NOTE: data[0] is confirmed by the parent function and need not be
+ checked here.
+ */
+
+static void
+mouse_input(unsigned char *data, int nb, struct pt_regs *regs)
+{
+ struct kbd_struct *kbd;
+ int i;
+
+ if (nb < 5 || nb > 6 || (data[2] & 3) != MOUSE_DATAREG) {
+ printk("data from mouse:");
+ for (i = 0; i < nb; ++i)
+ printk(" %x", data[i]);
+ printk("\n");
+ return;
+ }
+
+ if (mac_mouse_interrupt_hook) {
+ mac_mouse_interrupt_hook(data);
+ /*
+ * passing the mouse data to i.e. the X server as done for
+ * Xpmac will confuse applications on a sane X server :-)
+ */
+ return;
+ }
+#ifdef DEBUG_ADBMOUSE
+ else
+ if (console_loglevel >= 8)
+ printk("mouse_input: data %x %x %x buttons %x dx %d dy %d \n",
+ data[3], data[4], data[5],
+ ~((data[3] & 0x80 ? 0 : 4)
+ | (data[4] & 0x80 ? 0 : 1)
+ | (data[5] & 0x80 ? 0 : 2))&7,
+ ((data[4]&0x7f) < 64 ? (data[4]&0x7f) : (data[4]&0x7f)-128 ),
+ ((data[3]&0x7f) < 64 ? -(data[3]&0x7f) : 128-(data[3]&0x7f) ) );
+#endif
+
+
+ kbd = kbd_table + fg_console;
+
+#if 0 /* The entirely insane way of MkLinux handling mouse input */
+ /* Requires put_queue which is static in keyboard.c :-( */
+ /* Only send mouse codes when keyboard is in raw mode. */
+ if (kbd->kbdmode == VC_RAW) {
+ static unsigned char uch_ButtonStateSecond = 0;
+ unsigned char uchButtonSecond;
+
+ /* Send first button, second button and movement. */
+ put_queue( 0x7e );
+ put_queue( data[3] );
+ put_queue( data[4] );
+
+ /* [ACA: Are there any two-button ADB mice that use handler 1 or 2?] */
+
+ /* Store the button state. */
+ uchButtonSecond = (data[4] & 0x80);
+
+ /* Send second button. */
+ if (uchButtonSecond != uch_ButtonStateSecond) {
+ put_queue( 0x3f | uchButtonSecond );
+ uch_ButtonStateSecond = uchButtonSecond;
+ }
+
+ /* Macintosh 3-button mouse (handler 4). */
+ if ((nb == 6) && (data[1] & 0x40)) {
+ static unsigned char uch_ButtonStateThird = 0;
+ unsigned char uchButtonThird;
+
+ /* Store the button state for speed. */
+ uchButtonThird = (data[5] & 0x80);
+
+ /* Send third button. */
+ if (uchButtonThird != uch_ButtonStateThird) {
+ put_queue( 0x40 | uchButtonThird );
+ uch_ButtonStateThird = uchButtonThird;
+ }
+ }
+ }
+#endif /* insane MkLinux mouse hack */
+}
+
+/* Map led flags as defined in kbd_kern.h to bits for Apple keyboard. */
+static unsigned char mac_ledmap[8] = {
+ 0, /* none */
+ 4, /* scroll lock */
+ 1, /* num lock */
+ 5, /* scroll + num lock */
+ 2, /* caps lock */
+ 6, /* caps + scroll lock */
+ 3, /* caps + num lock */
+ 7, /* caps + num + scroll lock */
+};
+
+static int leds_pending;
+
+void mac_kbd_leds(unsigned int leds)
+{
+ if (led_request.got_reply) {
+#ifdef DEBUG_ADB
+ if (console_loglevel == 10)
+ printk("mac_kbd_leds: got reply, sending request!\n");
+#endif
+ adb_request(&led_request, mac_leds_done, 4, ADB_PACKET,
+ ADB_WRITEREG(ADB_KEYBOARD, KEYB_LEDREG),
+ 0xff, ~mac_ledmap[leds]);
+ } else
+ leds_pending = leds | 0x100;
+}
+
+static void mac_leds_done(struct adb_request *req)
+{
+ int leds;
+
+ if (leds_pending) {
+ leds = leds_pending & 0xff;
+ leds_pending = 0;
+ mac_kbd_leds(leds);
+ }
+ mark_bh(KEYBOARD_BH);
+}
+
+int mac_kbdrate(struct kbd_repeat *k)
+{
+ return 0;
+}
+
+int mac_keyb_init(void)
+{
+ static struct adb_request autopoll_req, confcod_req, mouse_req, readkey_req;
+ volatile int ct;
+
+ /* setup key map */
+ key_maps[0] = mac_plain_map;
+ key_maps[1] = mac_shift_map;
+ key_maps[2] = mac_altgr_map;
+ key_maps[4] = mac_ctrl_map;
+ key_maps[5] = mac_shift_ctrl_map;
+ key_maps[8] = mac_alt_map;
+ /* key_maps[9] = atashift_alt_map; */
+ key_maps[12] = mac_ctrl_alt_map;
+ /* key_maps[13] = atashift_ctrl_alt_map; */
+ memcpy (plain_map, mac_plain_map, sizeof(plain_map));
+ keymap_count = 7;
+
+ /* initialize mouse interrupt hook */
+ mac_mouse_interrupt_hook = NULL;
+ /* assume broken mouse :-) */
+ mac_emulate_button2 = 1;
+ mac_emulate_button3 = 1;
+
+ /*
+ * Might put that someplace else, possibly ....
+ */
+ adb_bus_init();
+
+ /* the input functions ... */
+ adb_register(ADB_KEYBOARD, keyboard_input);
+ adb_register(ADB_MOUSE, mouse_input);
+
+ /* turn on ADB auto-polling in the CUDA */
+
+ /*
+ * Older boxes don't support CUDA_* targets and CUDA commands
+ * instead we emulate them in the adb_request hook to make
+ * the code interfaces saner.
+ *
+ * Note XXX: the Linux PMac and this code both assume the
+ * devices are at their primary ids and do not do device
+ * assignment. This isn't ideal. We should fix it to follow
+ * the reassignment specs.
+ */
+
+ if (macintosh_config->adb_type == MAC_ADB_CUDA) {
+ printk("CUDA autopoll on ...\n");
+ adb_request(&autopoll_req, NULL, 3, CUDA_PACKET, CUDA_AUTOPOLL, 1);
+ ct=0;
+ while (!autopoll_req.got_reply && ++ct<1000)
+ {
+ adb_poll();
+ udelay(10);
+ }
+ if(ct==1000)
+ printk("Keyboard timed out.\n");
+ }
+
+ /*
+ * XXX: all ADB requests now in CUDA format; adb_request takes
+ * care of that for other Macs.
+ */
+
+ printk("Configuring keyboard\n");
+
+ /*
+ * turn on all leds - the keyboard driver will turn them back off
+ * via mac_kbd_leds if everything works ok!
+ */
+ printk("leds on ...\n");
+ adb_request(&led_request, NULL, 4, ADB_PACKET,
+ ADB_WRITEREG(ADB_KEYBOARD, KEYB_LEDREG), 0xff, ~7);
+
+ /*
+ * The polling stuff should go away as soon as the ADB driver is stable
+ */
+ ct = 0;
+ adb_poll();
+ while (!led_request.got_reply && ++ct<1000)
+ {
+ adb_poll();
+ udelay(10);
+ }
+ if(ct==1000)
+ printk("Keyboard timed out.\n");
+
+#if 1
+ printk("Configuring coding mode ...\n");
+
+ /*
+ * get the keyboard to send separate codes for
+ * left and right shift, control, option keys.
+ */
+ adb_request(&confcod_req, NULL, 4, ADB_PACKET,
+ ADB_WRITEREG(ADB_KEYBOARD, 3), 0, 3);
+
+ ct=0;
+ adb_poll();
+ while (!confcod_req.got_reply && ++ct<1000)
+ {
+ adb_poll();
+ udelay(10);
+ }
+ if(ct==1000)
+ printk("Keyboard timed out.\n");
+#endif
+
+#if 0 /* seems to hurt, at least Geert's Mac */
+ printk("Configuring mouse (3-button mode) ...\n");
+
+ /*
+ * XXX: taken from the PPC driver again ...
+ * Try to switch the mouse (id 3) to handler 4, for three-button
+ * mode. (0x20 is Service Request Enable, 0x03 is Device ID).
+ */
+ adb_request(&mouse_req, NULL, 4, ADB_PACKET,
+ ADB_WRITEREG(ADB_MOUSE, 3), 0x23, 4 );
+
+ ct=0;
+ adb_poll();
+ while (!mouse_req.got_reply && ++ct<1000)
+ {
+ adb_poll();
+ udelay(10);
+ }
+ if(ct==1000)
+ printk("Mouse timed out.\n");
+#endif
+
+#if 0
+ printk("Start polling keyboard ...\n");
+
+ /*
+ * get the keyboard to send data back, via the adb_input hook
+ * XXX: was never used properly, and the driver takes care
+ * of polling and timeout retransmits now.
+ * Might be of use if we want to start talking to a specific
+ * device here...
+ */
+ adb_request(&readkey_req, NULL, 2, ADB_PACKET,
+ ADB_READREG(ADB_KEYBOARD, KEYB_KEYREG));
+#endif
+
+ /*
+ * fake 'request done' for the driver if requests timed out
+ */
+
+ autopoll_req.got_reply = 1;
+#if 0
+ /* XXX: results in race and hang with mac_kbd_leds and serial (why ?) */
+ led_request.got_reply = 1;
+#endif
+ confcod_req.got_reply = 1;
+
+ in_keybinit = 0;
+ printk("Keyboard init done\n");
+
+ return 0;
+}
diff --git a/arch/m68k/mac/via6522.c b/arch/m68k/mac/via6522.c
new file mode 100644
index 000000000..d2a25ab13
--- /dev/null
+++ b/arch/m68k/mac/via6522.c
@@ -0,0 +1,590 @@
+
+/*
+ * 6522 Versatile Interface Adapter (VIA)
+ *
+ * There are two of these on the Mac II. Some IRQ's are vectored
+ * via them as are assorted bits and bobs - eg rtc, adb.
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+
+#include <asm/macintosh.h>
+#include <asm/macints.h>
+#include "via6522.h"
+
+volatile unsigned char *via1=(unsigned char *)VIABASE;
+volatile unsigned char *via2=(unsigned char *)VIABASE2;
+
+unsigned char via1_clock, via1_datab;
+
+static int rbv=0;
+
+/*
+ * Debugging the VBL ints
+ */
+
+extern int console_loglevel;
+
+/*
+ * VIA1 - hardwired vectors
+ */
+
+#if 0 /* gone to macints.[ch] */
+extern void via_wtf(int slot, void *via, struct pt_regs *regs);
+static void via_do_nubus(int slot, volatile void *via, struct pt_regs *regs);
+
+extern void adb_interrupt(int slot, void *via, struct pt_regs *regs);
+
+static struct via_irq_tab via1_func_tab=
+{
+ {
+ via_wtf, /* One second interrupt */
+ via_wtf, /* Vblank */
+ via_wtf, /* ADB data ready */
+ via_wtf, /* ADB data */
+ via_wtf, /* ADB clock */
+ via_wtf,
+ via_wtf, /* Slot 6 is replaced by the timer */
+ via_wtf
+ }
+};
+
+static struct via_irq_tab via2_func_tab=
+{
+ {
+ via_wtf,
+ via_do_nubus,
+ via_wtf,
+ via_wtf,
+ via_wtf,
+ via_wtf,
+ via_wtf,
+ via_wtf
+ }
+};
+
+static struct via_irq_tab nubus_func_tab=
+{
+ {
+ via_wtf,
+ via_wtf,
+ via_wtf,
+ via_wtf,
+ via_wtf,
+ via_wtf,
+ via_wtf,
+ via_wtf
+ }
+};
+#endif
+
+extern void adb_interrupt(int slot, void *via, struct pt_regs *regs);
+
+#define MAC_CLOCK_TICK (783300/HZ) /* ticks per HZ */
+#define MAC_CLOCK_LOW (MAC_CLOCK_TICK&0xFF)
+#define MAC_CLOCK_HIGH (MAC_CLOCK_TICK>>8)
+
+
+void via_init_clock(void (*func)(int, void *, struct pt_regs *))
+{
+ unsigned char c;
+
+/* mac_debugging_penguin(6);*/
+
+ switch(macintosh_config->via_type)
+ {
+ /*
+ * CI, SI, VX, LC
+ */
+ case MAC_VIA_IIci:
+ via1=(void *)0x50F00000;
+ via2=(void *)0x50F26000;
+ rbv=1;
+ break;
+ /*
+ * Quadra and early MacIIs agree on the VIA locations
+ */
+ case MAC_VIA_QUADRA:
+ case MAC_VIA_II:
+ via1=(void *)0x50F00000;
+ via2=(void *)0x50F02000;
+ break;
+ default:
+ }
+ via1_clock=via_read(via1, vACR);
+ via1_datab=via_read(via1, vBufB);
+
+ /*
+ * Tell what MacOS left us with
+ */
+
+ printk("via_init: boot via1 acr=%X pcr=%X buf_a=%X dir_a=%X buf_b=%X dir_b=%X \n",
+ (int)via1_clock, (int)via_read(via1, vPCR),
+ (int)via_read(via1, vBufA), (int)via_read(via1, vDirA),
+ (int)via_read(via1, vBufB), (int)via_read(via1, vDirB));
+
+ if (rbv == 0)
+ printk("via_init: boot via2 acr=%X pcr=%X buf_a=%X dir_a=%X buf_b=%X dir_b=%X \n",
+ (int)via_read(via2, vACR), (int)via_read(via2, vPCR),
+ (int)via_read(via2, vBufA), (int)via_read(via2, vDirA),
+ (int)via_read(via2, vBufB), (int)via_read(via2, vDirB));
+
+ /*
+ * Shut it down
+ */
+
+ via_write(via1,vIER, 0x7F);
+
+ /*
+ * Kill the timers
+ */
+
+ via_write(via1,vT1LL,0);
+ via_write(via1,vT1LH,0);
+ via_write(via1,vT1CL,0);
+ via_write(via1,vT1CH,0);
+ via_write(via1,vT2CL,0);
+ via_write(via1,vT2CH,0);
+
+ /*
+ * Now do via2
+ */
+
+ if(rbv==0)
+ {
+ via_write(via2,vT1LL,0);
+ via_write(via2,vT1LH,0);
+ via_write(via2,vT1CL,0);
+ via_write(via2,vT1CH,0);
+ via_write(via2,vT2CL,0);
+ via_write(via2,vT2CH,0);
+ via_write(via2,vIER, 0x7F);
+ }
+ else
+ {
+ /*
+ * Init the RBV chip a bit
+ */
+
+ via_write(via2, rIER,0x7F);
+ }
+
+ /*
+ * Disable the timer latches
+ */
+
+ c=via_read(via1,vACR);
+ via_write(via1,vACR,c&0x3F);
+
+ if(rbv==0)
+ {
+ c=via_read(via2,vACR);
+ via_write(via2,vACR,c&0x3F);
+ }
+
+ /*
+ * Now start the clock - we want 100Hz
+ */
+
+ via_write(via1,vACR,via_read(via1,vACR)|0x40);
+
+ via_write(via1,vT1LL, MAC_CLOCK_LOW);
+ via_write(via1,vT1LH, MAC_CLOCK_HIGH);
+ via_write(via1,vT1CL, MAC_CLOCK_LOW);
+ via_write(via1,vT1CH, MAC_CLOCK_HIGH);
+
+ /*
+ * And enable its interrupt
+ */
+
+ request_irq(IRQ_MAC_TIMER_1, func, IRQ_FLG_LOCK, "timer", func);
+
+/* mac_debugging_penguin(7);*/
+
+ /*
+ * SE/30: disable video int.
+ * XXX: testing for SE/30 VBL
+ */
+
+ if (macintosh_config->ident == MAC_MODEL_SE30
+ && console_loglevel != 10) {
+ c = via_read(via1, vBufB);
+ via_write(via1, vBufB, c|(0x40));
+ c = via_read(via1, vDirB);
+ via_write(via1, vDirB, c|(0x40));
+ }
+
+ /*
+ * XXX: use positive edge
+ */
+
+ if (console_loglevel == 10) {
+ c = via_read(via1, vPCR);
+ via_write(via1, vPCR, c|(0x1));
+ }
+
+#if 0 /* gone to mac_init_IRQ */
+ /*
+ * Set vPCR for SCSI interrupts.
+ *
+ * That is: CA1 negative edge int., CA2 indep., positive edge int.;
+ * CB1 negative edge int., CB2 indep., positive edge int..
+ */
+ via_write(via2,vPCR, 0x66);
+#endif
+
+}
+
+#if 0 /* moved to macints.c */
+
+static void via_irq(volatile unsigned char *via, struct via_irq_tab *irqtab,
+ struct pt_regs *regs)
+{
+ unsigned char events=(via_read(via, vIFR)&via_read(via,vIER))&0x7F;
+ int i;
+ int ct=0;
+
+ /*
+ * Shouldnt happen
+ */
+
+ if(events==0)
+ {
+ printk("via_irq: nothing pending!\n");
+ return;
+ }
+
+ do {
+ /*
+ * Clear the pending flag
+ */
+
+ /* HACK HACK - FIXME !!! - just testing some keyboard ideas */
+
+ /* events&=~(1<<4); */
+ via_write(via, vIFR, events);
+
+ /*
+ * Now see what bits are raised
+ */
+
+ for(i=0;i<7;i++)
+ {
+ if(events&(1<<i))
+ (irqtab->vector[i])(i, via, regs);
+ }
+
+ /*
+ * And done..
+ */
+ events=(via_read(via, vIFR)&via_read(via,vIER))&0x7F;
+ ct++;
+ if(events && ct>8)
+ {
+ printk("via: stuck events %x\n",events);
+ break;
+ }
+ }
+ while(events);
+
+ scsi_mac_polled();
+}
+
+/*
+ *
+ * The RBV is different. RBV appears to stand for randomly broken
+ * VIA.
+ */
+
+static void rbv_irq(volatile unsigned char *via, struct via_irq_tab *irqtab,
+ struct pt_regs *regs)
+{
+ unsigned char events=(via_read(via, rIFR)&via_read(via,rIER))&0x7F;
+ int i;
+ int ct=0;
+
+ /*
+ * Shouldnt happen
+ */
+
+ if(events==0)
+ {
+ printk("rbv_irq: nothing pending!\n");
+ return;
+ }
+
+ do {
+ /*
+ * Clear the pending flag
+ */
+
+ /* HACK HACK - FIXME !!! - just testing some keyboard ideas */
+
+ /* events&=~(1<<4); */
+ via_write(via, rIFR, events);
+
+ /*
+ * Now see what bits are raised
+ */
+
+ for(i=0;i<7;i++)
+ {
+ if(events&(1<<i))
+ (irqtab->vector[i])(i, via, regs);
+ }
+
+ /*
+ * And done..
+ */
+ events=(via_read(via, rIFR)&via_read(via,rIER))&0x7F;
+ ct++;
+ if(events && ct>8)
+ {
+ printk("rbv: stuck events %x\n",events);
+ for(i=0;i<7;i++)
+ {
+ if(events&(1<<i))
+ {
+ printk("rbv - bashing source %d\n",
+ i);
+ via_write(via, rIER, i);
+ via_write(via, rIFR, i);
+ }
+ }
+ break;
+ }
+ }
+ while(events);
+}
+
+/*
+ * System interrupts
+ */
+
+void via1_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+ via_irq(via1, &via1_func_tab, regs);
+}
+
+/*
+ * Nubus interrupts
+ */
+
+void via2_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+/* printk("via2 interrupt\n");*/
+ if(rbv)
+ rbv_irq(via2, &via2_func_tab, regs);
+ else
+ via_irq(via2, &via2_func_tab, regs);
+}
+
+/*
+ * Unexpected via interrupt
+ */
+
+void via_wtf(int slot, volatile void *via, struct pt_regs *regs)
+{
+ printk("Unexpected event %d on via %p\n",slot,via);
+}
+
+void nubus_wtf(int slot, volatile void *via, struct pt_regs *regs)
+{
+ printk("Unexpected interrupt on nubus slot %d\n",slot);
+}
+
+#endif
+
+/*
+ * The power switch - yes its software!
+ */
+
+void mac_reset(void)
+{
+ if(rbv) {
+ via_write(via2, rBufB, via_read(via2, rBufB)&~0x04);
+ } else {
+ /* Direction of vDirB is output */
+ via_write(via2,vDirB,via_read(via2,vDirB)|0x04);
+ /* Send a value of 0 on that line */
+ via_write(via2,vBufB,via_read(via2,vBufB)&~0x04);
+ }
+ /* We never make it this far... */
+ /* XXX - delay do we need to spin here ? */
+ while(1); /* Just in case .. */
+}
+
+/*
+ * Set up the keyboard
+ */
+
+void via_setup_keyboard(void)
+{
+#if 0 /* moved to adb */
+ via1_func_tab.vector[2]=adb_interrupt;
+#else
+ request_irq(IRQ_MAC_ADB, adb_interrupt, IRQ_FLG_LOCK, "adb interrupt",
+ adb_interrupt);
+#endif
+}
+
+/*
+ * Floppy hook
+ */
+
+void via1_set_head(int head)
+{
+ if(head==0)
+ via_write(via1, vBufA, via_read(via1, vBufA)&~0x20);
+ else
+ via_write(via1, vBufA, via_read(via1, vBufA)|0x20);
+}
+
+#if 0 /* moved to macints.c */
+
+
+/*
+ * Set up the SCSI
+ */
+
+void via_scsi_disable(void)
+{
+ if (rbv)
+ via_write(via2, rIER, (1<<3)|(1<<0));
+ else
+ via_write(via2, vIER, (1<<3)|(1<<0));
+}
+
+void via_scsi_enable(void)
+{
+ if (rbv)
+ via_write(via2, rIER, (1<<3)|(1<<0)|0x80);
+ else
+ via_write(via2, vIER, (1<<3)|(1<<0)|0x80);
+}
+
+void via_scsi_clear(void)
+{
+ if (rbv)
+ via_write(via2, rIFR, (1<<3)|(1<<0)|0x80);
+ volatile unsigned char deep_magic=via_read(via2, vBufB);
+ via_scsi_enable();
+}
+
+void via_setup_scsi(void (*handler)(int,volatile void *,struct pt_regs *))
+{
+ via2_func_tab.vector[0]=handler; /* SCSI DRQ */
+ via2_func_tab.vector[3]=handler; /* SCSI IRQ */
+ via_write(via2, vPCR, 0x66); /* Edge direction! */
+ via_scsi_enable();
+}
+
+/*
+ * Nubus handling
+ */
+
+static int nubus_active=0;
+
+int nubus_request_irq(int slot, void (*handler)(int,void *,struct pt_regs *))
+{
+ slot-=9;
+/* printk("Nubus request irq for slot %d\n",slot);*/
+ if(nubus_func_tab.vector[slot]==nubus_wtf)
+ return -EBUSY;
+ nubus_func_tab.vector[slot]=handler;
+ nubus_active|=1<<slot;
+/* printk("program slot %d\n",slot);*/
+/* printk("via2=%p\n",via2);*/
+#if 0
+ via_write(via2, vDirA,
+ via_read(via2, vDirA)|(1<<slot));
+ via_write(via2, vBufA, 0);
+#endif
+ if (!rbv) {
+ /* Make sure the bit is an input */
+ via_write(via2, vDirA,
+ via_read(via2, vDirA)&~(1<<slot));
+ }
+/* printk("nubus irq on\n");*/
+ return 0;
+}
+
+int nubus_free_irq(int slot)
+{
+ slot-=9;
+ nubus_active&=~(1<<slot);
+ nubus_func_tab.vector[slot]=nubus_wtf;
+ if (rbv) {
+ via_write(via2, rBufA, 1<<slot);
+ } else {
+ via_write(via2, vDirA,
+ via_read(via2, vDirA)|(1<<slot));
+ via_write(via2, vBufA, 1<<slot);
+ via_write(via2, vDirA,
+ via_read(via2, vDirA)&~(1<<slot));
+ }
+ return 0;
+}
+
+static void via_do_nubus(int slot, volatile void *via, struct pt_regs *regs)
+{
+ unsigned char map;
+ int i;
+ int ct=0;
+
+/* printk("nubus interrupt\n");*/
+
+ if (rbv) {
+ via_write(via2, rIFR, 0x82); /* lock the nubus interrupt */
+ } else {
+ via_write(via2, vIFR, 0x82); /* lock the nubus interrupt */
+
+ while(1)
+ {
+ if(rbv)
+ map=~via_read(via2, rBufA);
+ else
+ map=~via_read(via2, vBufA);
+ if((map=(map&nubus_active))==0)
+ break;
+ if(ct++>2)
+ {
+ printk("nubus stuck events - %d/%d\n", map, nubus_active);
+ return;
+ }
+ for(i=0;i<7;i++)
+ {
+ if(map&(1<<i))
+ {
+ (nubus_func_tab.vector[i])(i+9, via, regs);
+ }
+ }
+ if (rbv)
+ via_write(via2, rIFR, 0x02); /* clear it */
+ else
+ via_write(via2, vIFR, 0x02); /* clear it */
+ }
+
+ /* And done */
+}
+#endif
+
+void nubus_init_via(void)
+{
+ if (rbv) {
+ via_write(via2, rBufB, via_read(via2, rBufB)|0x02);
+ via_write(via2, rIER, 0x82); /* Interrupts on */
+ } else {
+ /* Assert the nubus active */
+ via_write(via2, vDirB, via_read(via2, vDirB)|0x02);
+ via_write(via2, vBufB, via_read(via2, vBufB)|0x02);
+ /* Make the nubus interrupt source register all output (disable) */
+ /* via_write(via2, vDirA, 0xFF); */
+ via_write(via2, vIER, 0x82); /* Interrupts on */
+ }
+ printk("BTW boot via1 acr=%X datab=%X pcr=%X\n",
+ (int)via1_clock, (int)via1_datab, (int)via_read(via1, vPCR));
+}
+
diff --git a/arch/m68k/mac/via6522.h b/arch/m68k/mac/via6522.h
new file mode 100644
index 000000000..fa8a3ff76
--- /dev/null
+++ b/arch/m68k/mac/via6522.h
@@ -0,0 +1,111 @@
+/*
+ * 6522 Versatile Interface Adapter (VIA)
+ *
+ * There are two of these on the Mac II. Some IRQ's are vectored
+ * via them as are assorted bits and bobs - eg rtc, adb. The picture
+ * is a bit incomplete as the Mac documentation doesnt cover this well
+ */
+
+#define VIABASE 0x50F00000
+#define VIABASE2 0x50F02000
+
+/*
+ * Not all of these are true post MacII I think
+ */
+
+#define VIA1A_vSccWrReq 0x80 /* SCC write */
+#define VIA1A_vRev8 0x40 /* Revision 8 board ??? */
+#define VIA1A_vHeadSel 0x20 /* Head select for IWM */
+#define VIA1A_vOverlay 0x10
+#define VIA1A_vSync 0x08
+#define VIA1A_vVolume 0x07 /* Audio volume mask */
+
+#define VIA1B_vSound 0x80 /* Audio on/off */
+#define VIA1B_vMystery 0x40
+#define VIA1B_vADBS2 0x20 /* ADB state 2 */
+#define VIA1B_vADBS1 0x10 /* ADB state 1 */
+#define VIA1B_vADBInt 0x08 /* ADB interrupt */
+#define VIA1B_vRTCEnb 0x04 /* Real time clock */
+#define VIA1B_vRTCClk 0x02
+#define VIA1B_vRTCData 0x01
+
+/*
+ * VIA2 A register is the interrupt lines raised off the nubus
+ * slots.
+ */
+
+#define VIA2A_vIRQE 0x20
+#define VIA2A_vIRQD 0x10
+#define VIA2A_vIRQC 0x08
+#define VIA2A_vIRQB 0x04
+#define VIA2A_vIRQA 0x02
+#define VIA2A_vIRQ9 0x01
+
+/*
+ * Register B has the fun stuff in it
+ */
+
+#define VIA2B_vPower 0x04 /* Off switch */
+#define VIA2B_vBusLk 0x02
+#define VIA2B_vCDis 0x01
+
+extern __inline__ void via_write(volatile unsigned char *via,int reg, int v)
+{
+ via[reg]=v;
+}
+
+extern __inline__ int via_read(volatile unsigned char *via,int reg)
+{
+ return (int)via[reg];
+}
+
+extern volatile unsigned char *via1,*via2;
+
+/*
+ * 6522 registers - see databook
+ */
+
+#define vBufB 0x0000
+#define vBufA 0x0200
+#define vDirB 0x0400
+#define vDirA 0x0600
+#define vT1CL 0x0800
+#define vT1CH 0x0a00
+#define vT1LL 0x0c00
+#define vT1LH 0x0e00
+#define vT2CL 0x1000
+#define vT2CH 0x1200
+#define vSR 0x1400
+#define vACR 0x1600
+#define vPCR 0x1800
+#define vIFR 0x1a00
+#define vIER 0x1c00
+#define vANH 0x1e00 /* register A (no shake) */
+
+#define rBufB 0x00
+#define rBufA 0x02
+/*#define rIFR 0x03*/
+#define rIFR 0x1A03
+#define rVideo 0x10
+#define rSlot 0x12
+/*#define rIER 0x13*/
+#define rIER 0x1C13
+/*
+#define R_rIFR 0x03
+#define R_rIER 0x13
+#define W_rIFR 0x1A03
+#define W_rIER 0x1C13
+*/
+/*
+ * VIA interrupt
+ */
+
+struct via_irq_tab
+{
+ void (*vector[8])(int, void *, struct pt_regs *);
+};
+
+extern void via1_irq(int, void *, struct pt_regs *);
+extern void via2_irq(int, void *, struct pt_regs *);
+
+extern void via_setup_keyboard(void);