diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1998-03-17 22:05:47 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1998-03-17 22:05:47 +0000 |
commit | 27cfca1ec98e91261b1a5355d10a8996464b63af (patch) | |
tree | 8e895a53e372fa682b4c0a585b9377d67ed70d0e /arch/m68k/mac | |
parent | 6a76fb7214c477ccf6582bd79c5b4ccc4f9c41b1 (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/Makefile | 16 | ||||
-rw-r--r-- | arch/m68k/mac/adb-bus.c | 2134 | ||||
-rw-r--r-- | arch/m68k/mac/bootparse.c | 121 | ||||
-rw-r--r-- | arch/m68k/mac/config.c | 575 | ||||
-rw-r--r-- | arch/m68k/mac/debug.c | 366 | ||||
-rw-r--r-- | arch/m68k/mac/ksyms.c | 7 | ||||
-rw-r--r-- | arch/m68k/mac/macboing.c | 92 | ||||
-rw-r--r-- | arch/m68k/mac/macints.c | 979 | ||||
-rw-r--r-- | arch/m68k/mac/mackeyb.c | 765 | ||||
-rw-r--r-- | arch/m68k/mac/via6522.c | 590 | ||||
-rw-r--r-- | arch/m68k/mac/via6522.h | 111 |
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); |