summaryrefslogtreecommitdiffstats
path: root/arch/m68k/mac
diff options
context:
space:
mode:
Diffstat (limited to 'arch/m68k/mac')
-rw-r--r--arch/m68k/mac/Makefile6
-rw-r--r--arch/m68k/mac/adb-bus.c9
-rw-r--r--arch/m68k/mac/bootparse.c1
-rw-r--r--arch/m68k/mac/config.c596
-rw-r--r--arch/m68k/mac/debug.c16
-rw-r--r--arch/m68k/mac/iop.c725
-rw-r--r--arch/m68k/mac/mac_ksyms.c7
-rw-r--r--arch/m68k/mac/mac_penguin.S75
-rw-r--r--arch/m68k/mac/macboing.c32
-rw-r--r--arch/m68k/mac/macints.c1851
-rw-r--r--arch/m68k/mac/mackeyb.c2
-rw-r--r--arch/m68k/mac/oss.c314
-rw-r--r--arch/m68k/mac/psc.c203
-rw-r--r--arch/m68k/mac/via.c774
-rw-r--r--arch/m68k/mac/via6522.c419
-rw-r--r--arch/m68k/mac/via6522.h131
16 files changed, 2897 insertions, 2264 deletions
diff --git a/arch/m68k/mac/Makefile b/arch/m68k/mac/Makefile
index cfd63295a..10613c0a4 100644
--- a/arch/m68k/mac/Makefile
+++ b/arch/m68k/mac/Makefile
@@ -7,11 +7,9 @@
#
# Note 2! The CFLAGS definitions are now in the main makefile...
-EXTRA_CFLAGS := -Wa,-m68020
-
O_TARGET := mac.o
-O_OBJS := config.o bootparse.o macints.o via6522.o \
- mackeyb.o adb-bus.o macboing.o debug.o
OX_OBJS := mac_ksyms.o
+O_OBJS := config.o bootparse.o macints.o iop.o via.o oss.o psc.o \
+ macboing.o debug.o misc.o
include $(TOPDIR)/Rules.make
diff --git a/arch/m68k/mac/adb-bus.c b/arch/m68k/mac/adb-bus.c
index 5f0f792aa..850e9cb6f 100644
--- a/arch/m68k/mac/adb-bus.c
+++ b/arch/m68k/mac/adb-bus.c
@@ -13,7 +13,6 @@
* MSch (1/98) Integrated start of IIsi driver by Robert Thompson
*/
-#include <stdarg.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
@@ -2335,8 +2334,8 @@ static int adb_wait_reply(struct adbdev_state *state, struct file *file)
int ret = 0;
DECLARE_WAITQUEUE(wait,current);
+ __set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&adb_wait, &wait);
- current->state = TASK_INTERRUPTIBLE;
while (!state->req.got_reply) {
if (file->f_flags & O_NONBLOCK) {
@@ -2350,7 +2349,7 @@ static int adb_wait_reply(struct adbdev_state *state, struct file *file)
schedule();
}
- current->state = TASK_RUNNING;
+ __set_current_state(TASK_RUNNING);
remove_wait_queue(&adb_wait, &wait);
return ret;
@@ -2563,8 +2562,8 @@ static int adb_wait_reply(struct adbdev_state *state, struct file *file)
printk("ADB request: wait_reply (blocking ... \n");
#endif
+ __set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&adb_wait, &wait);
- current->state = TASK_INTERRUPTIBLE;
while (!state->req.got_reply) {
if (file->f_flags & O_NONBLOCK) {
@@ -2578,7 +2577,7 @@ static int adb_wait_reply(struct adbdev_state *state, struct file *file)
schedule();
}
- current->state = TASK_RUNNING;
+ __set_current_state(TASK_RUNNING);
remove_wait_queue(&adb_wait, &wait);
return ret;
diff --git a/arch/m68k/mac/bootparse.c b/arch/m68k/mac/bootparse.c
index ae5046c3e..f7600999b 100644
--- a/arch/m68k/mac/bootparse.c
+++ b/arch/m68k/mac/bootparse.c
@@ -1,6 +1,7 @@
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/sched.h>
+#include <asm/irq.h>
#include <asm/setup.h>
#include <asm/bootinfo.h>
#include <asm/macintosh.h>
diff --git a/arch/m68k/mac/config.c b/arch/m68k/mac/config.c
index 8e902d0bd..b5057f6e8 100644
--- a/arch/m68k/mac/config.c
+++ b/arch/m68k/mac/config.c
@@ -37,7 +37,20 @@
#include <asm/macints.h>
#include <asm/machw.h>
-#include "via6522.h"
+#include <asm/mac_iop.h>
+#include <asm/mac_via.h>
+#include <asm/mac_oss.h>
+#include <asm/mac_psc.h>
+
+/* Offset between Unix time (1970-based) and Mac time (1904-based) */
+
+#define MAC_TIME_OFFSET 2082844800
+
+/*
+ * hardware reset vector
+ */
+
+static void (*rom_reset)(void);
/* Mac bootinfo struct */
@@ -59,30 +72,21 @@ void *mac_env; /* Loaded by the boot asm */
unsigned long mac_orig_videoaddr;
/* Mac specific keyboard functions */
-extern int mac_keyb_init(void);
-extern int mac_kbdrate(struct kbd_repeat *k);
-extern void mac_kbd_leds(unsigned int leds);
-
-/* Mac specific irq functions */
-extern void mac_init_IRQ (void);
-extern void (*mac_handlers[]) (int, void *, struct pt_regs *);
-extern int mac_request_irq (unsigned int irq,
- void (*handler)(int, void *, struct pt_regs *),
- unsigned long flags, const char *devname,
- void *dev_id);
-extern void mac_free_irq (unsigned int irq, void *dev_id);
-extern void mac_enable_irq (unsigned int);
-extern void mac_disable_irq (unsigned int);
-static void mac_get_model(char *model);
-/*static int mac_get_hardware_list(char *buffer);*/
-extern int mac_get_irq_list (char *);
+extern int mackbd_init_hw(void);
+extern void mackbd_leds(unsigned int leds);
/* Mac specific timer functions */
extern unsigned long mac_gettimeoffset (void);
static void mac_gettod (int *, int *, int *, int *, int *, int *);
static int mac_hwclk (int, struct hwclk_time *);
static int mac_set_clock_mmss (unsigned long);
+extern void iop_preinit(void);
+extern void iop_init(void);
+extern void via_init(void);
extern void via_init_clock(void (*func)(int, void *, struct pt_regs *));
+extern void via_flush_cache(void);
+extern void oss_init(void);
+extern void psc_init(void);
extern void (*kd_mksound)(unsigned int, unsigned int);
extern void mac_mksound(unsigned int, unsigned int);
@@ -95,6 +99,18 @@ extern void nubus_sweep_video(void);
extern void mac_debug_init(void);
extern void mac_debugging_long(int, long);
+/* poweroff functions */
+extern void via_poweroff(void);
+extern void oss_poweroff(void);
+extern void adb_poweroff(void);
+extern void adb_hwreset(void);
+
+/* pram functions */
+extern __u32 via_read_time(void);
+extern void via_write_time(__u32);
+extern __u32 adb_read_time(void);
+extern void adb_write_time(__u32);
+
#ifdef CONFIG_MAGIC_SYSRQ
static char mac_sysrq_xlate[128] =
"\000sdfghzxcv\000bqwer" /* 0x00 - 0x0f */
@@ -124,110 +140,201 @@ static void mac_sched_init(void (*vector)(int, void *, struct pt_regs *))
extern int console_loglevel;
+/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
+ * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
+ * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
+ *
+ * [For the Julian calendar (which was used in Russia before 1917,
+ * Britain & colonies before 1752, anywhere else before 1582,
+ * and is still in use by some communities) leave out the
+ * -year/100+year/400 terms, and add 10.]
+ *
+ * This algorithm was first published by Gauss (I think).
+ *
+ * WARNING: this function will overflow on 2106-02-07 06:28:16 on
+ * machines were long is 32-bit! (However, as time_t is signed, we
+ * will already get problems at other places on 2038-01-19 03:14:08)
+ */
+static unsigned long mktime(unsigned int year, unsigned int mon,
+ unsigned int day, unsigned int hour,
+ unsigned int min, unsigned int sec)
+{
+ if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */
+ mon += 12; /* Puts Feb last since it has leap day */
+ year -= 1;
+ }
+ return (((
+ (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) +
+ year*365 - 719499
+ )*24 + hour /* now have hours */
+ )*60 + min /* now have minutes */
+ )*60 + sec; /* finally seconds */
+}
+
/*
- * This function translates the boot timeval into a proper date, to initialize
- * the system time.
+ * This function translates seconds since 1970 into a proper date.
+ *
+ * Algorithm cribbed from glibc2.1, __offtime().
*/
+#define SECS_PER_MINUTE (60)
+#define SECS_PER_HOUR (SECS_PER_MINUTE * 60)
+#define SECS_PER_DAY (SECS_PER_HOUR * 24)
-static void mac_gettod (int *yearp, int *monp, int *dayp,
- int *hourp, int *minp, int *secp)
+static void unmktime(unsigned long time, long offset,
+ 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, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, -1 };
-
- time = mac_bi_data.boottime - 60*mac_bi_data.gmtbias; /* seconds */
-
- *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. And it's broken :-( */
- /* 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] += 1;
-
- /* count the months */
- for (*monp = 1; time > mon_days[*monp]; (*monp)++)
- time -= mon_days[*monp];
+ /* How many days come before each month (0-12). */
+ static const unsigned short int __mon_yday[2][13] =
+ {
+ /* Normal years. */
+ { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
+ /* Leap years. */
+ { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
+ };
+ long int days, rem, y, wday, yday;
+ const unsigned short int *ip;
+
+ days = time / SECS_PER_DAY;
+ rem = time % SECS_PER_DAY;
+ rem += offset;
+ while (rem < 0) {
+ rem += SECS_PER_DAY;
+ --days;
+ }
+ while (rem >= SECS_PER_DAY) {
+ rem -= SECS_PER_DAY;
+ ++days;
+ }
+ *hourp = rem / SECS_PER_HOUR;
+ rem %= SECS_PER_HOUR;
+ *minp = rem / SECS_PER_MINUTE;
+ *secp = rem % SECS_PER_MINUTE;
+ /* January 1, 1970 was a Thursday. */
+ wday = (4 + days) % 7; /* Day in the week. Not currently used */
+ if (wday < 0) wday += 7;
+ y = 1970;
+
+#define DIV(a, b) ((a) / (b) - ((a) % (b) < 0))
+#define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400))
+#define __isleap(year) \
+ ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
+
+ while (days < 0 || days >= (__isleap (y) ? 366 : 365))
+ {
+ /* Guess a corrected year, assuming 365 days per year. */
+ long int yg = y + days / 365 - (days % 365 < 0);
+
+ /* Adjust DAYS and Y to match the guessed year. */
+ days -= ((yg - y) * 365
+ + LEAPS_THRU_END_OF (yg - 1)
+ - LEAPS_THRU_END_OF (y - 1));
+ y = yg;
+ }
+ *yearp = y - 1900;
+ yday = days; /* day in the year. Not currently used. */
+ ip = __mon_yday[__isleap(y)];
+ for (y = 11; days < (long int) ip[y]; --y)
+ continue;
+ days -= ip[y];
+ *monp = y;
+ *dayp = days + 1; /* day in the month */
+ return;
+}
- *dayp = time;
+/*
+ * Return the boot time for use in initializing the kernel clock.
+ *
+ * I'd like to read the hardware clock here but many machines read
+ * the PRAM through ADB, and interrupts aren't initialized when this
+ * is called so ADB obviously won't work.
+ */
- return;
+static void mac_gettod(int *yearp, int *monp, int *dayp,
+ int *hourp, int *minp, int *secp)
+{
+ /* Yes the GMT bias is backwards. It looks like Penguin is
+ screwing up the boottime it gives us... This works for me
+ in Canada/Eastern but it might be wrong everywhere else. */
+ unmktime(mac_bi_data.boottime, -mac_bi_data.gmtbias * 60,
+ yearp, monp, dayp, hourp, minp, secp);
+ /* For some reason this is off by one */
+ *monp = *monp + 1;
}
/*
- * TBI: read and write hwclock
+ * Read/write the hardware clock.
*/
-static int mac_hwclk( int op, struct hwclk_time *t )
+static int mac_hwclk(int op, struct hwclk_time *t)
{
- return 0;
+ unsigned long now;
+
+ if (!op) { /* read */
+ if (macintosh_config->adb_type == MAC_ADB_II) {
+ now = via_read_time();
+ } else if ((macintosh_config->adb_type == MAC_ADB_IISI) ||
+ (macintosh_config->adb_type == MAC_ADB_CUDA)) {
+ now = adb_read_time();
+ } else if (macintosh_config->adb_type == MAC_ADB_IOP) {
+ now = via_read_time();
+ } else {
+ now = MAC_TIME_OFFSET;
+ }
+
+ now -= MAC_TIME_OFFSET;
+
+ t->wday = 0;
+ unmktime(now, 0,
+ &t->year, &t->mon, &t->day,
+ &t->hour, &t->min, &t->sec);
+ } else { /* write */
+ now = mktime(t->year + 1900, t->mon + 1, t->day,
+ t->hour, t->min, t->sec) + MAC_TIME_OFFSET;
+
+ if (macintosh_config->adb_type == MAC_ADB_II) {
+ via_write_time(now);
+ } else if ((macintosh_config->adb_type == MAC_ADB_IISI) ||
+ (macintosh_config->adb_type == MAC_ADB_CUDA)) {
+ adb_write_time(now);
+ } else if (macintosh_config->adb_type == MAC_ADB_IOP) {
+ via_write_time(now);
+ }
+ }
+ return 0;
}
/*
- * TBI: set minutes/seconds in hwclock
+ * Set minutes/seconds in the hardware clock
*/
static int mac_set_clock_mmss (unsigned long nowtime)
{
- short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
+ struct hwclk_time now;
+
+ mac_hwclk(0, &now);
+ now.sec = nowtime % 60;
+ now.min = (nowtime / 60) % 60;
+ mac_hwclk(1, &now);
- return 0;
+ return 0;
}
+#if 0
void mac_waitbut (void)
{
;
}
+#endif
extern struct consw fb_con;
extern struct fb_info *mac_fb_init(long *);
-extern void mac_video_setup(char *, int *);
-
-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 __init mac_parse_bootinfo(const struct bi_record *record)
{
int unknown = 0;
const u_long *data = record->data;
@@ -237,7 +344,7 @@ __initfunc(int mac_parse_bootinfo(const struct bi_record *record))
mac_bi_data.id = *data;
break;
case BI_MAC_VADDR:
- mac_bi_data.videoaddr = VIDEOMEMBASE + (*data & ~VIDEOMEMMASK);
+ mac_bi_data.videoaddr = *data;
break;
case BI_MAC_VDEPTH:
mac_bi_data.videodepth = *data;
@@ -249,7 +356,8 @@ __initfunc(int mac_parse_bootinfo(const struct bi_record *record))
mac_bi_data.dimensions = *data;
break;
case BI_MAC_VLOGICAL:
- mac_bi_data.videological = *data;
+ mac_bi_data.videological = VIDEOMEMBASE + (*data & ~VIDEOMEMMASK);
+ mac_orig_videoaddr = *data;
break;
case BI_MAC_SCCBASE:
mac_bi_data.sccbase = *data;
@@ -266,6 +374,9 @@ __initfunc(int mac_parse_bootinfo(const struct bi_record *record))
case BI_MAC_CPUID:
mac_bi_data.cpuid = *data;
break;
+ case BI_MAC_ROMBASE:
+ mac_bi_data.rombase = *data;
+ break;
default:
unknown = 1;
}
@@ -280,37 +391,29 @@ __initfunc(int mac_parse_bootinfo(const struct bi_record *record))
static void mac_cache_card_flush(int writeback)
{
- unsigned long flags;
- save_flags(flags);
+ unsigned long cpu_flags;
+ save_flags(cpu_flags);
cli();
- via_write(via2, vBufB, via_read(via2,vBufB)&~VIA2B_vMode32);
- via_write(via2, vBufB, via_read(via2,vBufB)|VIA2B_vMode32);
- restore_flags(flags);
+ via_flush_cache();
+ restore_flags(cpu_flags);
}
-__initfunc(void config_mac(void))
+void __init config_mac(void)
{
if (!MACH_IS_MAC) {
printk("ERROR: no Mac, but config_mac() called!! \n");
}
- 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_keyb_init = mackbd_init_hw;
+ mach_kbd_leds = mackbd_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;
mach_hwclk = mac_hwclk;
@@ -319,11 +422,12 @@ __initfunc(void config_mac(void))
mach_mksound = mac_mksound;
#endif
mach_reset = mac_reset;
+ mach_halt = mac_poweroff;
+ mach_power_off = mac_poweroff;
conswitchp = &dummy_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
@@ -346,18 +450,15 @@ __initfunc(void config_mac(void))
mac_identify();
mac_report_hardware();
- if(
- /* Cache cards */
- macintosh_config->ident == MAC_MODEL_IICI||
- macintosh_config->ident == MAC_MODEL_IISI||
- macintosh_config->ident == MAC_MODEL_IICX||
- /* On board L2 cache */
- macintosh_config->ident == MAC_MODEL_IIFX)
- {
+ /* AFAIK only the IIci takes a cache card. The IIfx has onboard
+ cache ... someone needs to figure out how to tell if it's on or
+ not. */
+ if (macintosh_config->ident == MAC_MODEL_IICI
+ || macintosh_config->ident == MAC_MODEL_IIFX) {
mach_l2_flush = mac_cache_card_flush;
}
- /* goes on forever if timers broken */
#ifdef MAC_DEBUG_SOUND
+ /* goes on forever if timers broken */
mac_mksound(1000,10);
#endif
@@ -365,7 +466,9 @@ __initfunc(void config_mac(void))
* Check for machine specific fixups.
*/
+#ifdef OLD_NUBUS_CODE
nubus_sweep_video();
+#endif
}
@@ -386,6 +489,13 @@ struct mac_model *macintosh_config;
static struct mac_model mac_data_table[]=
{
/*
+ * The default machine, in case we get an unsupported one
+ * We'll pretend to be a Macintosh II, that's pretty safe.
+ */
+
+ { MAC_MODEL_II, "Unknown", MAC_ADB_II, MAC_VIA_II, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
+
+ /*
* Original MacII hardware
*
*/
@@ -403,10 +513,11 @@ static struct mac_model mac_data_table[]=
* The IIfx apparently has different ADB hardware, and stuff
* so zany nobody knows how to drive it.
* Even so, with Marten's help we'll try to deal with it :-)
+ * CSA: see http://developer.apple.com/technotes/hw/hw_09.html
*/
{ 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_II, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_IIFX, "IIfx", MAC_ADB_IOP, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_IOP, 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},
@@ -435,70 +546,72 @@ static struct mac_model mac_data_table[]=
* confuse us. The 840AV has a SCSI location of its own (same as
* the 660AV).
*/
-
+
{ MAC_MODEL_Q605, "Quadra 605", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
{ MAC_MODEL_Q610, "Quadra 610", MAC_ADB_II, 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_QUADRA, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS},
{ MAC_MODEL_Q650, "Quadra 650", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS},
/* The Q700 does have a NS Sonic */
- { 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_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},
{ MAC_MODEL_Q840, "Quadra 840AV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA3, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_MACE, MAC_NUBUS},
- /* These might have IOP problems */
- { MAC_MODEL_Q900, "Quadra 900", MAC_ADB_IISI, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE, MAC_SCC_IOP, MAC_ETHER_SONIC, MAC_NUBUS},
- { MAC_MODEL_Q950, "Quadra 950", MAC_ADB_IISI, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE, MAC_SCC_IOP, MAC_ETHER_SONIC, MAC_NUBUS},
+ { MAC_MODEL_Q900, "Quadra 900", MAC_ADB_IOP, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE, MAC_SCC_IOP, MAC_ETHER_SONIC, MAC_NUBUS},
+ { MAC_MODEL_Q950, "Quadra 950", MAC_ADB_IOP, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE, MAC_SCC_IOP, MAC_ETHER_SONIC, MAC_NUBUS},
/*
* Performa - more LC type machines
*/
- { MAC_MODEL_P460, "Performa 460", MAC_ADB_IISI, MAC_VIA_IIci, 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_P475F, "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_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
- { MAC_MODEL_P550, "Performa 550", MAC_ADB_CUDA, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
- { MAC_MODEL_P575, "Performa 575", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
- { MAC_MODEL_P588, "Performa 588", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, 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},
- { MAC_MODEL_P600, "Performa 600", MAC_ADB_IISI, MAC_VIA_IIci, 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
+ { MAC_MODEL_P460, "Performa 460", MAC_ADB_IISI, MAC_VIA_IIci, 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_P475F, "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_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
+
+ { MAC_MODEL_P550, "Performa 550", MAC_ADB_CUDA, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_P575, "Performa 575", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
+ /* These have the comm slot, and therefore the possibility of SONIC ethernet */
+ { MAC_MODEL_P588, "Performa 588", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_QUADRA, MAC_SCC_II, MAC_ETHER_SONIC, 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},
+ { MAC_MODEL_P600, "Performa 600", MAC_ADB_IISI, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
+
/*
* Centris - just guessing again; maybe like Quadra
*/
- { MAC_MODEL_C610, "Centris 610", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS},
- { MAC_MODEL_C650, "Centris 650", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS},
- { MAC_MODEL_C660, "Centris 660AV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA3, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
+ /* The C610 may or may not have SONIC. We probe to make sure */
+ { MAC_MODEL_C610, "Centris 610", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS},
+ { MAC_MODEL_C650, "Centris 650", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS},
+ { MAC_MODEL_C660, "Centris 660AV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA3, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_MACE, MAC_NUBUS},
/*
* Power books - seem similar to early Quadras ? (most have 030 though)
*/
- { MAC_MODEL_PB140, "PowerBook 140", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
- { MAC_MODEL_PB145, "PowerBook 145", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_PB140, "PowerBook 140", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_PB145, "PowerBook 145", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_NONE, 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_PB1, MAC_VIA_IIci, MAC_SCSI_QUADRA, MAC_IDE_PB, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
- { MAC_MODEL_PB160, "PowerBook 160", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
- { MAC_MODEL_PB165, "PowerBook 165", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
- { MAC_MODEL_PB165C, "PowerBook 165c", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
- { MAC_MODEL_PB170, "PowerBook 170", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
- { MAC_MODEL_PB180, "PowerBook 180", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
- { MAC_MODEL_PB180C, "PowerBook 180c", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
- { MAC_MODEL_PB190, "PowerBook 190", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_PB, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
- { MAC_MODEL_PB520, "PowerBook 520", MAC_ADB_PB2, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_PB150, "PowerBook 150", MAC_ADB_PB1, MAC_VIA_IIci, MAC_SCSI_NONE, MAC_IDE_PB, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_PB160, "PowerBook 160", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_NONE, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_PB165, "PowerBook 165", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_NONE, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_PB165C, "PowerBook 165c", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_NONE, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_PB170, "PowerBook 170", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_PB180, "PowerBook 180", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_NONE, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_PB180C, "PowerBook 180c", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_NONE, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_PB190, "PowerBook 190cs", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_NONE, MAC_IDE_PB, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
+ /* These have onboard SONIC */
+ { MAC_MODEL_PB520, "PowerBook 520", MAC_ADB_PB2, MAC_VIA_QUADRA, MAC_SCSI_NONE, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS},
/*
* Power book Duos - similar to Power books, I hope
*/
- { MAC_MODEL_PB210, "PowerBook Duo 210", MAC_ADB_PB2, 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_PB2, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
- { MAC_MODEL_PB250, "PowerBook Duo 250", MAC_ADB_PB2, 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_PB2, 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_PB2, 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_PB2, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
+ /* All of these might have onboard SONIC in the Dock but I'm not quite sure */
+ { MAC_MODEL_PB210, "PowerBook Duo 210", MAC_ADB_PB2, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_PB230, "PowerBook Duo 230", MAC_ADB_PB2, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_PB250, "PowerBook Duo 250", MAC_ADB_PB2, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_PB270C, "PowerBook Duo 270c", MAC_ADB_PB2, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_PB280, "PowerBook Duo 280", MAC_ADB_PB2, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_PB280C, "PowerBook Duo 280c", MAC_ADB_PB2, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
/*
* Other stuff ??
@@ -508,7 +621,7 @@ static struct mac_model mac_data_table[]=
void mac_identify(void)
{
- struct mac_model *m=&mac_data_table[0];
+ struct mac_model *m;
/* Penguin data useful? */
int model = mac_bi_data.id;
@@ -519,32 +632,23 @@ void mac_identify(void)
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)
+ macintosh_config = mac_data_table;
+ for (m = macintosh_config ; m->ident != -1 ; m++) {
+ if (m->ident == model) {
+ macintosh_config = m;
break;
- m++;
- }
- if(m->ident==-1)
- {
- printk("\nUnknown macintosh model %d, probably unsupported.\n",
- 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)
- panic("mac model config data corrupt!\n");
}
+ /* We need to pre-init the IOPs, if any. Otherwise */
+ /* the serial console won't work if the user had */
+ /* the serial ports set to "Faster" mode in MacOS. */
+
+ iop_preinit();
+ mac_debug_init();
+
+ printk ("Detected Macintosh model: %d \n", model);
+
/*
* Report booter data:
*/
@@ -566,12 +670,6 @@ void mac_identify(void)
#endif
/*
- * Save the pointer
- */
-
- macintosh_config=m;
-
- /*
* TODO: set the various fields in macintosh_config->hw_present here!
*/
switch (macintosh_config->scsi_type) {
@@ -592,7 +690,10 @@ void mac_identify(void)
break;
}
- via_configure_base();
+ iop_init();
+ via_init();
+ oss_init();
+ psc_init();
}
void mac_report_hardware(void)
@@ -604,8 +705,133 @@ static void mac_get_model(char *str)
{
strcpy(str,"Macintosh ");
strcat(str, macintosh_config->name);
- if(mach_l2_flush && !(via_read(via2, vBufB)&VIA2B_vCDis))
- strcat(str, "(+L2 cache)");
+}
+
+/*
+ * The power switch - yes it's software!
+ */
+
+void mac_poweroff(void)
+{
+ /*
+ * MAC_ADB_IISI may need to be moved up here if it doesn't actually
+ * work using the ADB packet method. --David Kilzer
+ */
+
+ if (oss_present) {
+ oss_poweroff();
+ } else if (macintosh_config->adb_type == MAC_ADB_II) {
+ via_poweroff();
+ } else {
+ adb_poweroff();
+ }
+}
+
+/*
+ * Not all Macs support software power down; for the rest, just
+ * try the ROM reset vector ...
+ */
+void mac_reset(void)
+{
+ /*
+ * MAC_ADB_IISI may need to be moved up here if it doesn't actually
+ * work using the ADB packet method. --David Kilzer
+ */
+
+ if (macintosh_config->adb_type == MAC_ADB_II) {
+ unsigned long cpu_flags;
+
+ /* need ROMBASE in booter */
+ /* indeed, plus need to MAP THE ROM !! */
+
+ if (mac_bi_data.rombase == 0)
+ mac_bi_data.rombase = 0x40800000;
+
+ /* works on some */
+ rom_reset = (void *) (mac_bi_data.rombase + 0xa);
+
+ if (macintosh_config->ident == MAC_MODEL_SE30) {
+ /*
+ * MSch: Machines known to crash on ROM reset ...
+ */
+ printk("System halted.\n");
+ while(1);
+ } else {
+ save_flags(cpu_flags);
+ cli();
+
+ rom_reset();
+
+ restore_flags(cpu_flags);
+ }
+
+ /* We never make it this far... it usually panics above. */
+ printk ("Restart failed. Please restart manually.\n");
+
+ /* XXX - delay do we need to spin here ? */
+ while(1); /* Just in case .. */
+ } else if (macintosh_config->adb_type == MAC_ADB_IISI
+ || macintosh_config->adb_type == MAC_ADB_CUDA) {
+ adb_hwreset();
+ } else if (CPU_IS_030) {
+
+ /* 030-specific reset routine. The idea is general, but the
+ * specific registers to reset are '030-specific. Until I
+ * have a non-030 machine, I can't test anything else.
+ * -- C. Scott Ananian <cananian@alumni.princeton.edu>
+ */
+
+ unsigned long rombase = 0x40000000;
+
+ /* make a 1-to-1 mapping, using the transparent tran. reg. */
+ unsigned long virt = (unsigned long) mac_reset;
+ unsigned long phys = virt_to_phys(mac_reset);
+ unsigned long offset = phys-virt;
+ cli(); /* lets not screw this up, ok? */
+ __asm__ __volatile__(".chip 68030\n\t"
+ "pmove %0,%/tt0\n\t"
+ ".chip 68k"
+ : : "m" ((phys&0xFF000000)|0x8777));
+ /* Now jump to physical address so we can disable MMU */
+ __asm__ __volatile__(
+ ".chip 68030\n\t"
+ "lea %/pc@(1f),%/a0\n\t"
+ "addl %0,%/a0\n\t"/* fixup target address and stack ptr */
+ "addl %0,%/sp\n\t"
+ "pflusha\n\t"
+ "jmp %/a0@\n\t" /* jump into physical memory */
+ "0:.long 0\n\t" /* a constant zero. */
+ /* OK. Now reset everything and jump to reset vector. */
+ "1:\n\t"
+ "lea %/pc@(0b),%/a0\n\t"
+ "pmove %/a0@, %/tc\n\t" /* disable mmu */
+ "pmove %/a0@, %/tt0\n\t" /* disable tt0 */
+ "pmove %/a0@, %/tt1\n\t" /* disable tt1 */
+ "movel #0, %/a0\n\t"
+ "movec %/a0, %/vbr\n\t" /* clear vector base register */
+ "movec %/a0, %/cacr\n\t" /* disable caches */
+ "movel #0x0808,%/a0\n\t"
+ "movec %/a0, %/cacr\n\t" /* flush i&d caches */
+ "movew #0x2700,%/sr\n\t" /* set up status register */
+ "movel %1@(0x0),%/a0\n\t"/* load interrupt stack pointer */
+ "movec %/a0, %/isp\n\t"
+ "movel %1@(0x4),%/a0\n\t" /* load reset vector */
+ "reset\n\t" /* reset external devices */
+ "jmp %/a0@\n\t" /* jump to the reset vector */
+ ".chip 68k"
+ : : "r" (offset), "a" (rombase) : "a0");
+
+ /* should never get here */
+ sti(); /* sure, why not */
+ printk ("030 Restart failed. Please restart manually.\n");
+ while(1);
+ } else {
+ /* We never make it here... The above shoule handle all cases. */
+ printk ("Restart failed. Please restart manually.\n");
+
+ /* XXX - delay do we need to spin here ? */
+ while(1); /* Just in case .. */
+ }
}
/*
diff --git a/arch/m68k/mac/debug.c b/arch/m68k/mac/debug.c
index 5aa7ce6cf..98cb2a695 100644
--- a/arch/m68k/mac/debug.c
+++ b/arch/m68k/mac/debug.c
@@ -243,7 +243,7 @@ void mac_scca_console_write (struct console *co, const char *str,
}
}
-#ifdef CONFIG_SERIAL_CONSOLE
+#if defined(CONFIG_SERIAL_CONSOLE) || defined(DEBUG_SERIAL)
int mac_sccb_console_wait_key(struct console *co)
{
int i;
@@ -305,7 +305,7 @@ int mac_scca_console_wait_key(struct console *co)
} while(0)
#ifndef CONFIG_SERIAL_CONSOLE
-__initfunc(static void mac_init_scc_port( int cflag, int port ))
+static void __init mac_init_scc_port( int cflag, int port )
#else
void mac_init_scc_port( int cflag, int port )
#endif
@@ -385,7 +385,17 @@ void mac_init_scc_port( int cflag, int port )
}
#endif /* DEBUG_SERIAL */
-__initfunc(void mac_debug_init(void))
+void mac_init_scca_port( int cflag )
+{
+ mac_init_scc_port(cflag, 0);
+}
+
+void mac_init_sccb_port( int cflag )
+{
+ mac_init_scc_port(cflag, 1);
+}
+
+void __init mac_debug_init(void)
{
#ifdef CONFIG_KGDB
/* the m68k_debug_device is used by the GDB stub, do nothing here */
diff --git a/arch/m68k/mac/iop.c b/arch/m68k/mac/iop.c
new file mode 100644
index 000000000..ab07e3d48
--- /dev/null
+++ b/arch/m68k/mac/iop.c
@@ -0,0 +1,725 @@
+/*
+ * I/O Processor (IOP) management
+ * Written and (C) 1999 by Joshua M. Thompson (funaho@jurai.org)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice and this list of conditions.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice and this list of conditions in the documentation and/or other
+ * materials provided with the distribution.
+ */
+
+/*
+ * The IOP chips are used in the IIfx and some Quadras (900, 950) to manage
+ * serial and ADB. They are actually a 6502 processor and some glue logic.
+ *
+ * 990429 (jmt) - Initial implementation, just enough to knock the SCC IOP
+ * into compatible mode so nobody has to fiddle with the
+ * Serial Switch control panel anymore.
+ * 990603 (jmt) - Added code to grab the correct ISM IOP interrupt for OSS
+ * and non-OSS machines (at least I hope it's correct on a
+ * non-OSS machine -- someone with a Q900 or Q950 needs to
+ * check this.)
+ * 990605 (jmt) - Rearranged things a bit wrt IOP detection; iop_present is
+ * gone, IOP base addresses are now in an array and the
+ * globally-visible functions take an IOP number instead of an
+ * an actual base address.
+ * 990610 (jmt) - Finished the message passing framework and it seems to work.
+ * Sending _definately_ works; my adb-bus.c mods can send
+ * messages and receive the MSG_COMPLETED status back from the
+ * IOP. The trick now is figuring out the message formats.
+ * 990611 (jmt) - More cleanups. Fixed problem where unclaimed messages on a
+ * receive channel were never properly acknowledged. Bracketed
+ * the remaining debug printk's with #ifdef's and disabled
+ * debugging. I can now type on the console.
+ * 990612 (jmt) - Copyright notice added. Reworked the way replies are handled.
+ * It turns out that replies are placed back in the send buffer
+ * for that channel; messages on the receive channels are always
+ * unsolicited messages from the IOP (and our replies to them
+ * should go back in the receive channel.) Also added tracking
+ * of device names to the listener functions ala the interrupt
+ * handlers.
+ * 990729 (jmt) - Added passing of pt_regs structure to IOP handlers. This is
+ * used by the new unified ADB driver.
+ *
+ * TODO:
+ *
+ * o Something should be periodically checking iop_alive() to make sure the
+ * IOP hasn't died.
+ * o Some of the IOP manager routines need better error checking and
+ * return codes. Nothing major, just prettying up.
+ */
+
+/*
+ * -----------------------
+ * IOP Message Passing 101
+ * -----------------------
+ *
+ * The host talks to the IOPs using a rather simple message-passing scheme via
+ * a shared memory area in the IOP RAM. Each IOP has seven "channels"; each
+ * channel is conneced to a specific software driver on the IOP. For example
+ * on the SCC IOP there is one channel for each serial port. Each channel has
+ * an incoming and and outgoing message queue with a depth of one.
+ *
+ * A message is 32 bytes plus a state byte for the channel (MSG_IDLE, MSG_NEW,
+ * MSG_RCVD, MSG_COMPLETE). To send a message you copy the message into the
+ * buffer, set the state to MSG_NEW and signal the IOP by setting the IRQ flag
+ * in the IOP control to 1. The IOP will move the state to MSG_RCVD when it
+ * receives the message and then to MSG_COMPLETE when the message processing
+ * has completed. It is the host's responsibility at that point to read the
+ * reply back out of the send channel buffer and reset the channel state back
+ * to MSG_IDLE.
+ *
+ * To receive message from the IOP the same procedure is used except the roles
+ * are reversed. That is, the IOP puts message in the channel with a state of
+ * MSG_NEW, and the host receives the message and move its state to MSG_RCVD
+ * and then to MSG_COMPLETE when processing is completed and the reply (if any)
+ * has been placed back in the receive channel. The IOP will then reset the
+ * channel state to MSG_IDLE.
+ *
+ * Two sets of host interrupts are provided, INT0 and INT1. Both appear on one
+ * interrupt level; they are distinguished by a pair of bits in the IOP status
+ * register. The IOP will raise INT0 when one or more messages in the send
+ * channels have gone to the MSG_COMPLETE state and it will raise INT1 when one
+ * or more messages on the receive channels have gone to the MSG_NEW state.
+ *
+ * Since each channel handles only one message we have to implement a small
+ * interrupt-driven queue on our end. Messages to e sent are placed on the
+ * queue for sending and contain a pointer to an optional callback function.
+ * The handler for a message is called when the message state goes to
+ * MSG_COMPLETE.
+ *
+ * For receiving message we maintain a list of handler functions to call when
+ * a message is received on that IOP/channel combination. The handlers are
+ * called much like an interrupt handler and are passed a copy of the message
+ * from the IOP. The message state will be in MSG_RCVD while the handler runs;
+ * it is the handler's responsibility to call iop_complete_message() when
+ * finished; this function moves the message state to MSG_COMPLETE and signals
+ * the IOP. This two-step process is provided to allow the handler to defer
+ * message processing to a bottom-half handler if the processing will take
+ * a signifigant amount of time (handlers are called at interrupt time so they
+ * should execute quickly.)
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+
+#include <asm/bootinfo.h>
+#include <asm/macintosh.h>
+#include <asm/macints.h>
+#include <asm/mac_iop.h>
+#include <asm/mac_oss.h>
+
+/*#define DEBUG_IOP*/
+
+/* Set to nonezero if the IOPs are present. Set by iop_init() */
+
+int iop_scc_present,iop_ism_present;
+
+#ifdef CONFIG_PROC_FS
+
+/*
+ * sneaky reuse of the PROC_MAC_VIA inode. It's not needed by via.c
+ * anymore so we'll use it to debut the IOPs.
+ */
+
+int iop_get_proc_info(char *, char **, off_t, int, int);
+
+static struct proc_dir_entry proc_mac_iop = {
+ PROC_MAC_VIA, 7, "mac_iop",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_array_inode_operations,
+ &iop_get_proc_info
+};
+
+#endif /* CONFIG_PROC_FS */
+
+/* structure for tracking channel listeners */
+
+struct listener {
+ const char *devname;
+ void (*handler)(struct iop_msg *, struct pt_regs *);
+};
+
+/*
+ * IOP structures for the two IOPs
+ *
+ * The SCC IOP controls both serial ports (A and B) as its two functions.
+ * The ISM IOP controls the SWIM (floppy drive) and ADB.
+ */
+
+static volatile struct mac_iop *iop_base[NUM_IOPS];
+
+/*
+ * IOP message queues
+ */
+
+static struct iop_msg iop_msg_pool[NUM_IOP_MSGS];
+static struct iop_msg *iop_send_queue[NUM_IOPS][NUM_IOP_CHAN];
+static struct listener iop_listeners[NUM_IOPS][NUM_IOP_CHAN];
+
+void iop_ism_irq(int, void *, struct pt_regs *);
+
+extern void oss_irq_enable(int);
+
+/*
+ * Private access functions
+ */
+
+static __inline__ void iop_loadaddr(volatile struct mac_iop *iop, __u16 addr)
+{
+ iop->ram_addr_lo = addr;
+ iop->ram_addr_hi = addr >> 8;
+}
+
+static __inline__ __u8 iop_readb(volatile struct mac_iop *iop, __u16 addr)
+{
+ iop->ram_addr_lo = addr;
+ iop->ram_addr_hi = addr >> 8;
+ return iop->ram_data;
+}
+
+static __inline__ void iop_writeb(volatile struct mac_iop *iop, __u16 addr, __u8 data)
+{
+ iop->ram_addr_lo = addr;
+ iop->ram_addr_hi = addr >> 8;
+ iop->ram_data = data;
+}
+
+static __inline__ void iop_stop(volatile struct mac_iop *iop)
+{
+ iop->status_ctrl &= ~IOP_RUN;
+}
+
+static __inline__ void iop_start(volatile struct mac_iop *iop)
+{
+ iop->status_ctrl = IOP_RUN | IOP_AUTOINC;
+}
+
+static __inline__ void iop_bypass(volatile struct mac_iop *iop)
+{
+ iop->status_ctrl |= IOP_BYPASS;
+}
+
+static __inline__ void iop_interrupt(volatile struct mac_iop *iop)
+{
+ iop->status_ctrl |= IOP_IRQ;
+}
+
+static int iop_alive(volatile struct mac_iop *iop)
+{
+ int retval;
+
+ retval = (iop_readb(iop, IOP_ADDR_ALIVE) == 0xFF);
+ iop_writeb(iop, IOP_ADDR_ALIVE, 0);
+ return retval;
+}
+
+static struct iop_msg *iop_alloc_msg(void)
+{
+ int i;
+ ulong cpu_flags;
+
+ save_flags(cpu_flags);
+ cli();
+
+ for (i = 0 ; i < NUM_IOP_MSGS ; i++) {
+ if (iop_msg_pool[i].status == IOP_MSGSTATUS_UNUSED) {
+ iop_msg_pool[i].status = IOP_MSGSTATUS_WAITING;
+ restore_flags(cpu_flags);
+ return &iop_msg_pool[i];
+ }
+ }
+
+ restore_flags(cpu_flags);
+ return NULL;
+}
+
+static void iop_free_msg(struct iop_msg *msg)
+{
+ msg->status = IOP_MSGSTATUS_UNUSED;
+}
+
+/*
+ * This is called by the startup code before anything else. Its purpose
+ * is to find and initalize the IOPs early in the boot sequence, so that
+ * the serial IOP can be placed into bypass mode _before_ we try to
+ * initialize the serial console.
+ */
+
+void __init iop_preinit(void)
+{
+ if (macintosh_config->scc_type == MAC_SCC_IOP) {
+ if (macintosh_config->ident == MAC_MODEL_IIFX) {
+ iop_base[IOP_NUM_SCC] = (struct mac_iop *) SCC_IOP_BASE_IIFX;
+ } else {
+ iop_base[IOP_NUM_SCC] = (struct mac_iop *) SCC_IOP_BASE_QUADRA;
+ }
+ iop_base[IOP_NUM_SCC]->status_ctrl = 0x87;
+ iop_scc_present = 1;
+ } else {
+ iop_base[IOP_NUM_SCC] = NULL;
+ iop_scc_present = 0;
+ }
+ if (macintosh_config->adb_type == MAC_ADB_IOP) {
+ if (macintosh_config->ident == MAC_MODEL_IIFX) {
+ iop_base[IOP_NUM_ISM] = (struct mac_iop *) ISM_IOP_BASE_IIFX;
+ } else {
+ iop_base[IOP_NUM_ISM] = (struct mac_iop *) ISM_IOP_BASE_QUADRA;
+ }
+ iop_base[IOP_NUM_SCC]->status_ctrl = 0;
+ iop_ism_present = 1;
+ } else {
+ iop_base[IOP_NUM_ISM] = NULL;
+ iop_ism_present = 0;
+ }
+}
+
+/*
+ * Initialize the IOPs, if present.
+ */
+
+void __init iop_init(void)
+{
+ int i;
+
+ if (iop_scc_present) {
+ printk("IOP: detected SCC IOP at %p\n", iop_base[IOP_NUM_SCC]);
+ }
+ if (iop_ism_present) {
+ printk("IOP: detected ISM IOP at %p\n", iop_base[IOP_NUM_ISM]);
+ iop_start(iop_base[IOP_NUM_ISM]);
+ iop_alive(iop_base[IOP_NUM_ISM]); /* clears the alive flag */
+ }
+
+ /* Make the whole pool available and empty the queues */
+
+ for (i = 0 ; i < NUM_IOP_MSGS ; i++) {
+ iop_msg_pool[i].status = IOP_MSGSTATUS_UNUSED;
+ }
+
+ for (i = 0 ; i < NUM_IOP_CHAN ; i++) {
+ iop_send_queue[IOP_NUM_SCC][i] = 0;
+ iop_send_queue[IOP_NUM_ISM][i] = 0;
+ iop_listeners[IOP_NUM_SCC][i].devname = NULL;
+ iop_listeners[IOP_NUM_SCC][i].handler = NULL;
+ iop_listeners[IOP_NUM_ISM][i].devname = NULL;
+ iop_listeners[IOP_NUM_ISM][i].handler = NULL;
+ }
+
+#ifdef CONFIG_PROC_FS
+ proc_register(&proc_root, &proc_mac_iop);
+#endif
+}
+
+/*
+ * Register the interrupt handler for the IOPs.
+ * TODO: might be wrong for non-OSS machines. Anyone?
+ */
+
+void __init iop_register_interrupts(void)
+{
+ if (iop_ism_present) {
+ if (oss_present) {
+ request_irq(OSS_IRQLEV_IOPISM, iop_ism_irq,
+ IRQ_FLG_LOCK, "ISM IOP",
+ (void *) IOP_NUM_ISM);
+ oss_irq_enable(IRQ_MAC_ADB);
+ } else {
+ request_irq(IRQ_VIA2_0, iop_ism_irq,
+ IRQ_FLG_LOCK|IRQ_FLG_FAST, "ISM IOP",
+ (void *) IOP_NUM_ISM);
+ }
+ if (!iop_alive(iop_base[IOP_NUM_ISM])) {
+ printk("IOP: oh my god, they killed the ISM IOP!\n");
+ } else {
+ printk("IOP: the ISM IOP seems to be alive.\n");
+ }
+ }
+}
+
+/*
+ * Register or unregister a listener for a specific IOP and channel
+ *
+ * If the handler pointer is NULL the current listener (if any) is
+ * unregistered. Otherwise the new listener is registered provided
+ * there is no existing listener registered.
+ */
+
+int iop_listen(uint iop_num, uint chan,
+ void (*handler)(struct iop_msg *, struct pt_regs *),
+ const char *devname)
+{
+ if ((iop_num >= NUM_IOPS) || !iop_base[iop_num]) return -EINVAL;
+ if (chan >= NUM_IOP_CHAN) return -EINVAL;
+ if (iop_listeners[iop_num][chan].handler && handler) return -EINVAL;
+ iop_listeners[iop_num][chan].devname = devname;
+ iop_listeners[iop_num][chan].handler = handler;
+ return 0;
+}
+
+/*
+ * Complete reception of a message, which just means copying the reply
+ * into the buffer, setting the channel state to MSG_COMPLETE and
+ * notifying the IOP.
+ */
+
+void iop_complete_message(struct iop_msg *msg)
+{
+ int iop_num = msg->iop_num;
+ int chan = msg->channel;
+ int i,offset;
+
+#ifdef DEBUG_IOP
+ printk("iop_complete(%p): iop %d chan %d\n", msg, msg->iop_num, msg->channel);
+#endif
+
+ offset = IOP_ADDR_RECV_MSG + (msg->channel * IOP_MSG_LEN);
+
+ for (i = 0 ; i < IOP_MSG_LEN ; i++, offset++) {
+ iop_writeb(iop_base[iop_num], offset, msg->reply[i]);
+ }
+
+ iop_writeb(iop_base[iop_num],
+ IOP_ADDR_RECV_STATE + chan, IOP_MSG_COMPLETE);
+ iop_interrupt(iop_base[msg->iop_num]);
+
+ iop_free_msg(msg);
+}
+
+/*
+ * Actually put a message into a send channel buffer
+ */
+
+static void iop_do_send(struct iop_msg *msg)
+{
+ volatile struct mac_iop *iop = iop_base[msg->iop_num];
+ int i,offset;
+
+ offset = IOP_ADDR_SEND_MSG + (msg->channel * IOP_MSG_LEN);
+
+ for (i = 0 ; i < IOP_MSG_LEN ; i++, offset++) {
+ iop_writeb(iop, offset, msg->message[i]);
+ }
+
+ iop_writeb(iop, IOP_ADDR_SEND_STATE + msg->channel, IOP_MSG_NEW);
+
+ iop_interrupt(iop);
+}
+
+/*
+ * Handle sending a message on a channel that
+ * has gone into the IOP_MSG_COMPLETE state.
+ */
+
+static void iop_handle_send(uint iop_num, uint chan, struct pt_regs *regs)
+{
+ volatile struct mac_iop *iop = iop_base[iop_num];
+ struct iop_msg *msg,*msg2;
+ int i,offset;
+
+#ifdef DEBUG_IOP
+ printk("iop_handle_send: iop %d channel %d\n", iop_num, chan);
+#endif
+
+ iop_writeb(iop, IOP_ADDR_SEND_STATE + chan, IOP_MSG_IDLE);
+
+ if (!(msg = iop_send_queue[iop_num][chan])) return;
+
+ msg->status = IOP_MSGSTATUS_COMPLETE;
+ offset = IOP_ADDR_SEND_MSG + (chan * IOP_MSG_LEN);
+ for (i = 0 ; i < IOP_MSG_LEN ; i++, offset++) {
+ msg->reply[i] = iop_readb(iop, offset);
+ }
+ if (msg->handler) (*msg->handler)(msg, regs);
+ msg2 = msg;
+ msg = msg->next;
+ iop_free_msg(msg2);
+
+ iop_send_queue[iop_num][chan] = msg;
+ if (msg) iop_do_send(msg);
+}
+
+/*
+ * Handle reception of a message on a channel that has
+ * gone into the IOP_MSG_NEW state.
+ */
+
+static void iop_handle_recv(uint iop_num, uint chan, struct pt_regs *regs)
+{
+ volatile struct mac_iop *iop = iop_base[iop_num];
+ int i,offset;
+ struct iop_msg *msg;
+
+#ifdef DEBUG_IOP
+ printk("iop_handle_recv: iop %d channel %d\n", iop_num, chan);
+#endif
+
+ msg = iop_alloc_msg();
+ msg->iop_num = iop_num;
+ msg->channel = chan;
+ msg->status = IOP_MSGSTATUS_UNSOL;
+ msg->handler = iop_listeners[iop_num][chan].handler;
+
+ offset = IOP_ADDR_RECV_MSG + (chan * IOP_MSG_LEN);
+
+ for (i = 0 ; i < IOP_MSG_LEN ; i++, offset++) {
+ msg->message[i] = iop_readb(iop, offset);
+ }
+
+ iop_writeb(iop, IOP_ADDR_RECV_STATE + chan, IOP_MSG_RCVD);
+
+ /* If there is a listener, call it now. Otherwise complete */
+ /* the message ourselves to avoid possible stalls. */
+
+ if (msg->handler) {
+ (*msg->handler)(msg, regs);
+ } else {
+#ifdef DEBUG_IOP
+ printk("iop_handle_recv: unclaimed message on iop %d channel %d\n", iop_num, chan);
+ printk("iop_handle_recv:");
+ for (i = 0 ; i < IOP_MSG_LEN ; i++) {
+ printk(" %02X", (uint) msg->message[i]);
+ }
+ printk("\n");
+#endif
+ iop_complete_message(msg);
+ }
+}
+
+/*
+ * Send a message
+ *
+ * The message is placed at the end of the send queue. Afterwards if the
+ * channel is idle we force an immediate send of the next message in the
+ * queue.
+ */
+
+int iop_send_message(uint iop_num, uint chan, void *privdata,
+ uint msg_len, __u8 *msg_data,
+ void (*handler)(struct iop_msg *, struct pt_regs *))
+{
+ struct iop_msg *msg, *q;
+
+ if ((iop_num >= NUM_IOPS) || !iop_base[iop_num]) return -EINVAL;
+ if (chan >= NUM_IOP_CHAN) return -EINVAL;
+ if (msg_len > IOP_MSG_LEN) return -EINVAL;
+
+ msg = iop_alloc_msg();
+ if (!msg) return -ENOMEM;
+
+ msg->next = NULL;
+ msg->status = IOP_MSGSTATUS_WAITING;
+ msg->iop_num = iop_num;
+ msg->channel = chan;
+ msg->caller_priv = privdata;
+ memcpy(msg->message, msg_data, msg_len);
+ msg->handler = handler;
+
+ if (!(q = iop_send_queue[iop_num][chan])) {
+ iop_send_queue[iop_num][chan] = msg;
+ } else {
+ while (q->next) q = q->next;
+ q->next = msg;
+ }
+
+ if (iop_readb(iop_base[iop_num],
+ IOP_ADDR_SEND_STATE + chan) == IOP_MSG_IDLE) {
+ iop_do_send(msg);
+ }
+
+ return 0;
+}
+
+/*
+ * Upload code to the shared RAM of an IOP.
+ */
+
+void iop_upload_code(uint iop_num, __u8 *code_start,
+ uint code_len, __u16 shared_ram_start)
+{
+ if ((iop_num >= NUM_IOPS) || !iop_base[iop_num]) return;
+
+ iop_loadaddr(iop_base[iop_num], shared_ram_start);
+
+ while (code_len--) {
+ iop_base[iop_num]->ram_data = *code_start++;
+ }
+}
+
+/*
+ * Download code from the shared RAM of an IOP.
+ */
+
+void iop_download_code(uint iop_num, __u8 *code_start,
+ uint code_len, __u16 shared_ram_start)
+{
+ if ((iop_num >= NUM_IOPS) || !iop_base[iop_num]) return;
+
+ iop_loadaddr(iop_base[iop_num], shared_ram_start);
+
+ while (code_len--) {
+ *code_start++ = iop_base[iop_num]->ram_data;
+ }
+}
+
+/*
+ * Compare the code in the shared RAM of an IOP with a copy in system memory
+ * and return 0 on match or the first nonmatching system memory address on
+ * failure.
+ */
+
+__u8 *iop_compare_code(uint iop_num, __u8 *code_start,
+ uint code_len, __u16 shared_ram_start)
+{
+ if ((iop_num >= NUM_IOPS) || !iop_base[iop_num]) return code_start;
+
+ iop_loadaddr(iop_base[iop_num], shared_ram_start);
+
+ while (code_len--) {
+ if (*code_start != iop_base[iop_num]->ram_data) {
+ return code_start;
+ }
+ code_start++;
+ }
+ return (__u8 *) 0;
+}
+
+/*
+ * Handle an ISM IOP interrupt
+ */
+
+void iop_ism_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+ uint iop_num = (uint) dev_id;
+ volatile struct mac_iop *iop = iop_base[iop_num];
+ int i,state;
+
+#ifdef DEBUG_IOP
+ printk("iop_ism_irq: status = %02X\n", (uint) iop->status_ctrl);
+#endif
+
+ /* INT0 indicates a state change on an outgoing message channel */
+
+ if (iop->status_ctrl & IOP_INT0) {
+ iop->status_ctrl = IOP_INT0 | IOP_RUN | IOP_AUTOINC;
+#ifdef DEBUG_IOP
+ printk("iop_ism_irq: new status = %02X, send states",
+ (uint) iop->status_ctrl);
+#endif
+ for (i = 0 ; i < NUM_IOP_CHAN ; i++) {
+ state = iop_readb(iop, IOP_ADDR_SEND_STATE + i);
+#ifdef DEBUG_IOP
+ printk(" %02X", state);
+#endif
+ if (state == IOP_MSG_COMPLETE) {
+ iop_handle_send(iop_num, i, regs);
+ }
+ }
+#ifdef DEBUG_IOP
+ printk("\n");
+#endif
+ }
+
+ if (iop->status_ctrl & IOP_INT1) { /* INT1 for incoming msgs */
+ iop->status_ctrl = IOP_INT1 | IOP_RUN | IOP_AUTOINC;
+#ifdef DEBUG_IOP
+ printk("iop_ism_irq: new status = %02X, recv states",
+ (uint) iop->status_ctrl);
+#endif
+ for (i = 0 ; i < NUM_IOP_CHAN ; i++) {
+ state = iop_readb(iop, IOP_ADDR_RECV_STATE + i);
+#ifdef DEBUG_IOP
+ printk(" %02X", state);
+#endif
+ if (state == IOP_MSG_NEW) {
+ iop_handle_recv(iop_num, i, regs);
+ }
+ }
+#ifdef DEBUG_IOP
+ printk("\n");
+#endif
+ }
+
+}
+
+#ifdef CONFIG_PROC_FS
+
+char *iop_chan_state(int state)
+{
+ switch(state) {
+ case IOP_MSG_IDLE : return "idle ";
+ case IOP_MSG_NEW : return "new ";
+ case IOP_MSG_RCVD : return "received ";
+ case IOP_MSG_COMPLETE : return "completed ";
+ default : return "unknown ";
+ }
+}
+
+int iop_dump_one_iop(char *buf, int iop_num, char *iop_name)
+{
+ int i,len = 0;
+ volatile struct mac_iop *iop = iop_base[iop_num];
+
+ len += sprintf(buf+len, "%s IOP channel states:\n\n", iop_name);
+ len += sprintf(buf+len, "## send_state recv_state device\n");
+ len += sprintf(buf+len, "------------------------------------------------\n");
+ for (i = 0 ; i < NUM_IOP_CHAN ; i++) {
+ len += sprintf(buf+len, "%2d %10s %10s %s\n", i,
+ iop_chan_state(iop_readb(iop, IOP_ADDR_SEND_STATE+i)),
+ iop_chan_state(iop_readb(iop, IOP_ADDR_RECV_STATE+i)),
+ iop_listeners[iop_num][i].handler?
+ iop_listeners[iop_num][i].devname : "");
+
+ }
+ len += sprintf(buf+len, "\n");
+ return len;
+}
+
+int iop_get_proc_info(char *buf, char **start, off_t pos, int count, int wr)
+{
+ int len, cnt;
+
+ cnt = 0;
+ len = sprintf(buf, "IOPs detected:\n\n");
+
+ if (iop_scc_present) {
+ len += sprintf(buf+len, "SCC IOP (%p): status %02X\n",
+ iop_base[IOP_NUM_SCC],
+ (uint) iop_base[IOP_NUM_SCC]->status_ctrl);
+ }
+ if (iop_ism_present) {
+ len += sprintf(buf+len, "ISM IOP (%p): status %02X\n\n",
+ iop_base[IOP_NUM_ISM],
+ (uint) iop_base[IOP_NUM_ISM]->status_ctrl);
+ }
+
+ if (iop_scc_present) {
+ len += iop_dump_one_iop(buf+len, IOP_NUM_SCC, "SCC");
+
+ }
+
+ if (iop_ism_present) {
+ len += iop_dump_one_iop(buf+len, IOP_NUM_ISM, "ISM");
+
+ }
+
+ if (len >= pos) {
+ if (!*start) {
+ *start = buf + pos;
+ cnt = len - pos;
+ } else {
+ cnt += len;
+ }
+ }
+ return (count > cnt) ? cnt : count;
+}
+#endif /* CONFIG_PROC_FS */
diff --git a/arch/m68k/mac/mac_ksyms.c b/arch/m68k/mac/mac_ksyms.c
index a558d1684..6e37ceb0f 100644
--- a/arch/m68k/mac/mac_ksyms.c
+++ b/arch/m68k/mac/mac_ksyms.c
@@ -1,7 +1,8 @@
#include <linux/module.h>
#include <asm/ptrace.h>
#include <asm/traps.h>
-/* Hook for mouse driver */
-extern void (*adb_mouse_interrupt_hook) (char *);
-EXPORT_SYMBOL(adb_mouse_interrupt_hook);
+/* Says whether we're using A/UX interrupts or not */
+extern int via_alt_mapping;
+
+EXPORT_SYMBOL(via_alt_mapping);
diff --git a/arch/m68k/mac/mac_penguin.S b/arch/m68k/mac/mac_penguin.S
new file mode 100644
index 000000000..b3ce30b60
--- /dev/null
+++ b/arch/m68k/mac/mac_penguin.S
@@ -0,0 +1,75 @@
+.byte \
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xF0,0x0F,0xFF,0xFF,0xF0,0x00,0x0F,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0xFF,0xF0,0xFF,0xFF,0x0F,0xF0,0xF0,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0xFF,0x00,0xFF,0xFF,0x0F,0xFF,0x00,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0xFF,0xF0,0x0F,0xFF,0x0F,0xFF,0xF0,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x0F,0xFF,0x00,0x0F,0x0F,0xFF,0xF0,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x0F,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xF0,0x00,0x00,0x00,0x00,0xFF,0x00,0xFF,0xF0,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x0F,0xF0,0x00,0x00,0xFF,0xF0,0x0F,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x0F,0xF0,0xFF,0xFF,0x00,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0xFF,0xF0,0x00,0x0F,0xFF,0xF0,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0x0F,0xFF,0x00,0xFF,0xF0,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xF0,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xF0,0x00,0x0F,0xFF,0xF0,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xF0,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xF0,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x0F,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xF0,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xF0,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x0F,0xF0,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x0F,0xF0,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0xFF,0xF0,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0xFF,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x0F,0xFF,0xF0,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0xFF,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x0F,0xFF,0xF0,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0xFF,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x0F,0xF0,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0xF0,0x00,0x00,0x0F,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xF0,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x0F,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x0F,0xFF,0xFF,0xFF,0x00,0x00,0xF0,0x00,0x00,\
+0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x0F,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0xFF,0xFF,0xF0,0x00,0x00,0xF0,0x00,0x00,\
+0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x00,\
+0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,\
+0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,\
+0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xF0,0x00,\
+0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xF0,\
+0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,\
+0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x0F,0xF0,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,\
+0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xF0,0xFF,0xF0,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,\
+0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0x00,0x00,\
+0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0xFF,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0x00,0x00,0x00,\
+0x0F,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0xFF,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xF0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0xFF,0xF0,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xF0,0x00,0x00,0x0F,0xFF,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0x00,0x0F,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00
diff --git a/arch/m68k/mac/macboing.c b/arch/m68k/mac/macboing.c
index 1731c929c..557bcba27 100644
--- a/arch/m68k/mac/macboing.c
+++ b/arch/m68k/mac/macboing.c
@@ -91,14 +91,8 @@ static void mac_init_asc( void )
mac_special_bell = mac_quadra_start_bell;
mac_asc_samplespersec = 22150;
break;
- case MAC_MODEL_Q650:
- case MAC_MODEL_Q700:
- case MAC_MODEL_Q800:
- case MAC_MODEL_Q900:
- case MAC_MODEL_Q950:
- /*
- * Currently not implemented!
- */
+ case MAC_MODEL_C660:
+ case MAC_MODEL_Q840:
/*
* The Quadra 660AV and 840AV use the "Singer" custom ASIC for sound I/O.
* It appears to be similar to the "AWACS" custom ASIC in the Power Mac
@@ -126,6 +120,22 @@ static void mac_init_asc( void )
*/
mac_special_bell = mac_av_start_bell;
break;
+ case MAC_MODEL_Q650:
+ case MAC_MODEL_Q700:
+ case MAC_MODEL_Q800:
+ case MAC_MODEL_Q900:
+ case MAC_MODEL_Q950:
+ /*
+ * Currently not implemented!
+ */
+ mac_special_bell = NULL;
+ break;
+ default:
+ /*
+ * Every switch needs a default
+ */
+ mac_special_bell = NULL;
+ break;
}
/*
@@ -155,6 +165,12 @@ void mac_mksound( unsigned int freq, unsigned int length )
__u32 flags;
int i;
+ if ( mac_special_bell == NULL )
+ {
+ /* Do nothing */
+ return;
+ }
+
if ( !mac_asc_inited )
mac_init_asc();
diff --git a/arch/m68k/mac/macints.c b/arch/m68k/mac/macints.c
index 87e6692d4..0068effa5 100644
--- a/arch/m68k/mac/macints.c
+++ b/arch/m68k/mac/macints.c
@@ -7,8 +7,8 @@
* interrupts with exception vectors 0x19-0x1f). The following interrupt levels
* are used:
* 1 - VIA1
- * - slot 0: one second interrupt
- * - slot 1: VBlank
+ * - slot 0: one second interrupt (CA2)
+ * - slot 1: VBlank (CA1)
* - slot 2: ADB data ready (SR full)
* - slot 3: ADB data (CB2)
* - slot 4: ADB clock (CB1)
@@ -16,57 +16,103 @@
* - 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
+ * 2 - VIA2 or RBV
+ * - slot 0: SCSI DRQ (CA2)
+ * - slot 1: NUBUS IRQ (CA1) need to read port A to find which
+ * - slot 2: /EXP IRQ (only on IIci)
+ * - slot 3: SCSI IRQ (CB2)
+ * - slot 4: ASC IRQ (CB1)
+ * - slot 5: timer 2 (not on IIci)
+ * - slot 6: timer 1 (not on IIci)
+ * - slot 7: status of IRQ; signals 'any enabled int.'
+ *
+ * 2 - OSS (IIfx only?)
+ * - slot 0: SCSI interrupt
+ * - slot 1: Sound interrupt
+ *
+ * Levels 3-6 vary by machine type. For VIA or RBV Macintohes:
+ *
+ * 3 - unused (?)
+ *
+ * 4 - SCC (slot number determined by reading RR3 on the SSC itself)
+ * - slot 0: SCC channel A
+ * - slot 1: SCC channel B
+ *
+ * 5 - unused (?)
+ * [serial errors or special conditions seem to raise level 6
+ * interrupts on some models (LC4xx?)]
+ *
+ * 6 - off switch (?)
+ *
+ * For OSS Macintoshes (IIfx only at this point):
*
- * 4 - SCC
- * - subdivided into Channel B and Channel A interrupts
+ * 3 - Nubus interrupt
+ * - slot 0: Slot $9
+ * - slot 1: Slot $A
+ * - slot 2: Slot $B
+ * - slot 3: Slot $C
+ * - slot 4: Slot $D
+ * - slot 5: Slot $E
*
- * 6 - Off switch (??)
+ * 4 - SCC IOP
+ * - slot 0: SCC channel A
+ * - slot 1: SCC channel B
*
- * 7 - Debug output
+ * 5 - ISM IOP (ADB?)
*
- * AV Macs only, handled by PSC:
+ * 6 - unused
*
- * 3 - MACE ethernet IRQ (DMA complete on level 4)
+ * For PSC Macintoshes (660AV, 840AV):
*
- * 5 - DSP ??
+ * 3 - PSC level 3
+ * - slot 0: MACE
*
- * 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:
+ * 4 - PSC level 4
+ * - slot 1: SCC channel A interrupt
+ * - slot 2: SCC channel B interrupt
+ * - slot 3: MACE DMA
*
- * - 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).
+ * 5 - PSC level 5
*
- * - 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.
+ * 6 - PSC level 6
*
- * - 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 !
+ * Finally we have good 'ole level 7, the non-maskable interrupt:
*
- * - 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!).
+ * 7 - NMI (programmer's switch on the back of some Macs)
+ * Also RAM parity error on models which support it (IIc, IIfx?)
+ *
+ * The current interrupt logic looks something like this:
+ *
+ * - We install dispatchers for the autovector interrupts (1-7). These
+ * dispatchers are responsible for querying the hardware (the
+ * VIA/RBV/OSS/PSC chips) to determine the actual interrupt source. Using
+ * this information a machspec interrupt number is generated by placing the
+ * index of the interrupt hardware into the low three bits and the original
+ * autovector interrupt number in the upper 5 bits. The handlers for the
+ * resulting machspec interrupt are then called.
+ *
+ * - Nubus is a special case because its interrupts are hidden behind two
+ * layers of hardware. Nubus interrupts come in as index 1 on VIA #2,
+ * which translates to IRQ number 17. In this spot we install _another_
+ * dispatcher. This dispatcher finds the interrupting slot number (9-F) and
+ * then forms a new machspec interrupt number as above with the slot number
+ * minus 9 in the low three bits and the pseudo-level 7 in the upper five
+ * bits. The handlers for this new machspec interrupt number are then
+ * called. This puts Nubus interrupts into the range 56-62.
+ *
+ * - We support "fast" and "slow" handlers, just like the Amiga port. The
+ * fast handlers are called first and with all interrupts disabled. They
+ * are expected to execute quickly (hence the name). The slow handlers are
+ * called last with interrupts enabled and the interrupt level restored.
+ * They must therefore be reentrant.
+ *
+ * - Drivers should never try to request autovector interrupt numbers. It
+ * won't work.
*
* TODO:
- * - integrate Nubus interrupts in request/free_irq
*
- * -
+ * o Perhaps build some intelligence into mac_SCC_handler(); we could check
+ * the SCC ourselves and only call the handler for the appopriate channel.
*/
#include <linux/config.h>
@@ -82,124 +128,53 @@
#include <asm/traps.h>
#include <asm/machw.h>
#include <asm/macintosh.h>
-#include "via6522.h"
+#include <asm/mac_via.h>
+#include <asm/mac_psc.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 psc3_handler[8];
-static struct irqhandler scc_handler[8];
-static struct irqhandler psc5_handler[8];
-static struct irqhandler psc6_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 psc3_param[8];
-static struct irqparam scc_param[8];
-static struct irqparam psc5_param[8];
-static struct irqparam psc6_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, indexed by interrupt level
+ * VIA/RBV hooks
*/
-static volatile unsigned char *via_table[8];
+extern void via_init(void);
+extern void via_register_interrupts(void);
+extern void via_irq_enable(int);
+extern void via_irq_disable(int);
+extern void via_irq_clear(int);
+extern int via_irq_pending(int);
/*
- * Arrays with irq statistics
+ * OSS hooks
*/
-static unsigned long via1_irqs[8];
-static unsigned long via2_irqs[8];
-static unsigned long rbv_irqs[8];
-static unsigned long psc3_irqs[8];
-static unsigned long scc_irqs[8];
-static unsigned long psc5_irqs[8];
-static unsigned long psc6_irqs[8];
-static unsigned long nubus_irqs[8];
-static unsigned long *mac_irqs[8];
+extern int oss_present;
-/*
- * Some special nutcases ...
- */
-
-static unsigned long mac_ide_irqs = 0;
-static unsigned long nubus_stuck_events = 0;
+extern void oss_init(void);
+extern void oss_register_interrupts(void);
+extern void oss_irq_enable(int);
+extern void oss_irq_disable(int);
+extern void oss_irq_clear(int);
+extern int oss_irq_pending(int);
/*
- * VIA/RBV/OSS/PSC register base pointers
+ * PSC hooks
*/
-volatile unsigned char *via2_regp=(volatile unsigned char *)VIA2_BAS;
-volatile unsigned char *rbv_regp=(volatile unsigned char *)VIA2_BAS_IIci;
-volatile unsigned char *oss_regp=(volatile unsigned char *)OSS_BAS;
-volatile unsigned char *psc_regp=(volatile unsigned char *)PSC_BAS;
-
-/*
- * Flags to control via2 / rbv behaviour
- */
-
-static int via2_is_rbv = 0;
-static int via2_is_oss = 0;
-static int rbv_clear = 0;
-
-/* fake VIA2 to OSS bit mapping */
-static int oss_map[8] = {2, 7, 0, 1, 3, 4, 5};
+extern int psc_present;
-void oss_irq(int irq, void *dev_id, struct pt_regs *regs);
-static void oss_do_nubus(int irq, void *dev_id, struct pt_regs *regs);
-
-/* PSC ints */
-void psc_irq(int irq, void *dev_id, struct pt_regs *regs);
+extern void psc_init(void);
+extern void psc_register_interrupts(void);
+extern void psc_irq_enable(int);
+extern void psc_irq_disable(int);
+extern void psc_irq_clear(int);
+extern int psc_irq_pending(int);
/*
- * PSC hooks
+ * IOP hooks
*/
-extern void psc_init(void);
+extern void iop_register_interrupts(void);
/*
* console_loglevel determines NMI handler function
@@ -207,656 +182,317 @@ extern void psc_init(void);
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);
+extern void mac_bang(int, void *, struct pt_regs *);
-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);
+void mac_nmi_handler(int, void *, struct pt_regs *);
+void mac_SCC_handler(int, void *, struct pt_regs *);
/* #define DEBUG_MACINTS */
-#define DEBUG_SPURIOUS
-#define DEBUG_NUBUS_SPURIOUS
-#define DEBUG_NUBUS_INT
-
-/* #define DEBUG_VIA */
-#define DEBUG_VIA_NUBUS
-
void mac_init_IRQ(void)
{
- int i;
-
#ifdef DEBUG_MACINTS
- printk("Mac interrupt stuff initializing ...\n");
+ printk("mac_init_IRQ(): Setting things up...\n");
#endif
-
- via2_regp = (unsigned char *)VIA2_BAS;
- rbv_regp = (unsigned char *)VIA2_BAS_IIci;
-
- /* 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) {
- /*
- * A word of caution: the definitions here only affect interrupt
- * handling, see via6522.c for yet another file to change
- * base addresses and RBV flags
- */
-
- /* yes, this is messy - the IIfx deserves a class of his own */
- if (macintosh_config->ident == MAC_MODEL_IIFX) {
- /* no real VIA2, the OSS seems _very_ different */
- via2_is_oss = 1;
- /* IIfx has OSS, at a different base address than RBV */
- rbv_regp = (unsigned char *) OSS_BAS;
- sys_request_irq(2, oss_irq, IRQ_FLG_LOCK, "oss", oss_irq);
- } else {
- /* 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!
+ * Register the handlers for the the master IRQ handlers
+ * at levels 1-7. Most of the work is done elsewhere.
*/
- sys_request_irq(4, mac_debug_handler, IRQ_FLG_STD, "INT4", 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];
- mac_irqs[0] = &via1_irqs[0];
-
- if (via2_is_rbv || via2_is_oss) {
- via_table[1] = rbv_regp;
- handler_table[1] = &rbv_handler[0];
- param_table[1] = &rbv_param[0];
- mac_irqs[1] = &rbv_irqs[0];
+ if (oss_present) {
+ oss_register_interrupts();
} else {
- via_table[1] = via2_regp;
- handler_table[1] = &via2_handler[0];
- param_table[1] = &via2_param[0];
- mac_irqs[1] = &via2_irqs[0];
- }
- via_table[2] = NULL;
- via_table[3] = NULL;
-
- handler_table[2] = &rbv_handler[0];
- handler_table[3] = &scc_handler[0];
- handler_table[4] = NULL;
- handler_table[5] = NULL;
- handler_table[6] = NULL;
- handler_table[7] = &nubus_handler[0];
-
- param_table[2] = &rbv_param[0];
- param_table[3] = &scc_param[0];
- param_table[7] = &nubus_param[0];
-
- mac_irqs[2] = &rbv_irqs[0];
- mac_irqs[3] = &scc_irqs[0];
- mac_irqs[7] = &nubus_irqs[0];
-
- /*
- * Nubus Macs: turn off the Nubus dispatch interrupt for now
- */
-
- mac_turnoff_irq(IRQ_MAC_NUBUS);
-
- /*
- * AV Macs: shutup the PSC ints
- */
- if (macintosh_config->ident == MAC_MODEL_C660
- || macintosh_config->ident == MAC_MODEL_Q840)
- {
- psc_init();
-
- handler_table[2] = &psc3_handler[0];
- /* handler_table[3] = &psc4_handler[0]; */
- handler_table[4] = &psc5_handler[0];
- handler_table[5] = &psc6_handler[0];
-
- param_table[2] = &psc3_param[0];
- /* param_table[3] = &psc4_param[0]; */
- param_table[4] = &psc5_param[0];
- param_table[5] = &psc6_param[0];
-
- mac_irqs[2] = &psc3_irqs[0];
- /* mac_irqs[3] = &psc4_irqs[0]; */
- mac_irqs[4] = &psc5_irqs[0];
- mac_irqs[5] = &psc6_irqs[0];
-
- sys_request_irq(3, psc_irq, IRQ_FLG_STD, "PSC3", psc_irq);
- sys_request_irq(4, psc_irq, IRQ_FLG_STD, "PSC4", psc_irq);
- sys_request_irq(5, psc_irq, IRQ_FLG_STD, "PSC5", psc_irq);
- sys_request_irq(6, psc_irq, IRQ_FLG_STD, "PSC6", psc_irq);
+ via_register_interrupts();
}
-
+ if (psc_present) psc_register_interrupts();
+ iop_register_interrupts();
+ request_irq(7, mac_nmi_handler, IRQ_FLG_LOCK, "NMI", mac_nmi_handler);
#ifdef DEBUG_MACINTS
- printk("Mac interrupt init done!\n");
+ printk("mac_init_IRQ(): 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 (use nubus_request_irq!).
+ * Routines to work with irq_node_t's on linked lists lifted from
+ * the Amiga code written by Roman Zippel.
*/
-
-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 (redundant ??) */
- if (irq >= IRQ_IDX(IRQ_SCC) && irq < IRQ_IDX(IRQ_PSC5_0)) {
- /* 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;
- }
-
- /*
- * code below: only for VIA irqs currently
- * add similar hack for Nubus pseudo-irq here - hide nubus_request_irq
- */
- 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 ... careful, that's VIA only ... */
- if (srcidx == SRC_VIA2 && via2_is_rbv)
- via_write(via, rIER, via_read(via, rIER)|0x80|(1<<(irqidx)));
- else if (srcidx == SRC_VIA2 && via2_is_oss)
- via_write(oss_regp, oss_map[irqidx]+8, 2);
- 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?)
- * 980429 MS: RBV is ok, OSS seems to be different
- */
- if (!via2_is_oss)
- if (macintosh_config->scsi_type == MAC_SCSI_OLD) {
- /* CB2 (IRQ) indep. interrupt input, positive edge */
- /* CA2 (DRQ) indep. interrupt input, positive edge */
- via_write(via, vPCR, 0x66);
- } else {
- /* CB2 (IRQ) indep. interrupt input, negative edge */
- /* CA2 (DRQ) indep. interrupt input, negative edge */
- via_write(via, vPCR, 0x22);
- }
-#if 0
- else
- /* CB2 (IRQ) indep. interrupt input, negative edge */
- /* CA2 (DRQ) indep. interrupt input, negative edge */
- via_write(via, vPCR, 0x22);
-#endif
- }
-
- return 0;
-}
-
-void mac_free_irq (unsigned int irq, void *dev_id)
+static inline void mac_insert_irq(irq_node_t **list, irq_node_t *node)
{
- 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;
+ unsigned long cpu_flags;
+ irq_node_t *cur;
-#ifdef DEBUG_MACINTS
- printk ("%s: IRQ %d on VIA%d[%d] freed\n",
- __FUNCTION__, irq, srcidx+1, irqidx);
-#endif
+ if (!node->dev_id)
+ printk("%s: Warning: dev_id of %s is zero\n",
+ __FUNCTION__, node->devname);
- /* 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);
+ save_flags(cpu_flags);
cli();
- /* figure out if SCC pseudo-irq */
- if (irq >= IRQ_IDX(IRQ_SCC) && irq < IRQ_IDX(IRQ_PSC5_0)) {
- /* 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];
+ cur = *list;
- if ( !via || (via_handler[irqidx].dev_id != dev_id) ) {
- restore_flags(flags);
- goto not_found;
+ if (node->flags & IRQ_FLG_FAST) {
+ node->flags &= ~IRQ_FLG_SLOW;
+ while (cur && cur->flags & IRQ_FLG_FAST) {
+ list = &cur->next;
+ cur = cur->next;
+ }
+ } else if (node->flags & IRQ_FLG_SLOW) {
+ while (cur) {
+ list = &cur->next;
+ cur = cur->next;
+ }
+ } else {
+ while (cur && !(cur->flags & IRQ_FLG_SLOW)) {
+ list = &cur->next;
+ cur = cur->next;
+ }
}
- /* 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;
+ node->next = cur;
+ *list = node;
- /* and turn it off */
- if (srcidx == SRC_VIA2 && via2_is_rbv)
- via_write(via, rIER, (via_read(via, rIER)&(1<<irqidx)));
- else if (srcidx == SRC_VIA2 && via2_is_oss)
- via_write(oss_regp, oss_map[irqidx]+8, 0);
- else
- via_write(via, vIER, (via_read(via, vIER)&(1<<irqidx)));
+ restore_flags(cpu_flags);
+}
- restore_flags(flags);
- return;
+static inline void mac_delete_irq(irq_node_t **list, void *dev_id)
+{
+ unsigned long cpu_flags;
+ irq_node_t *node;
-not_found:
- printk("%s: tried to remove invalid irq\n", __FUNCTION__);
- return;
+ save_flags(cpu_flags);
+ cli();
+ for (node = *list; node; list = &node->next, node = *list) {
+ if (node->dev_id == dev_id) {
+ *list = node->next;
+ /* Mark it as free. */
+ node->handler = NULL;
+ restore_flags(cpu_flags);
+ return;
+ }
+ }
+ restore_flags(cpu_flags);
+ printk ("%s: tried to remove invalid irq\n", __FUNCTION__);
}
/*
- * {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).
+ * Call all the handlers for a given interrupt. Fast handlers are called
+ * first followed by slow handlers.
*
- * 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 ...
+ * This code taken from the original Amiga code written by Roman Zippel.
*/
-void mac_enable_irq (unsigned int irq)
+void mac_do_irq_list(int irq, struct pt_regs *fp)
{
- int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
- int irqidx = (irq & IRQ_IDX_MASK);
+ irq_node_t *node, *slow_nodes, **list = NULL;
+ unsigned long cpu_flags;
- 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?
- */
-}
+ kstat.irqs[0][irq]++;
-void mac_disable_irq (unsigned int irq)
-{
- int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
- int irqidx = (irq & IRQ_IDX_MASK);
+ if (irq < VIA1_SOURCE_BASE) {
+ list = &autoirq_list[irq];
+ } else if (irq < NUM_MAC_SOURCES) {
+ list = &userirq_list[irq - VIA1_SOURCE_BASE];
+ }
+ if (!list) return;
+
+#ifdef DEBUG_SPURIOUS
+ if (!*list && (console_loglevel > 7)) {
+ printk("mac_do_irq_list: spurious interrupt %d!\n", irq);
+ return;
+ }
+#endif
- irq_flags[srcidx].disabled |= (1<<irqidx);
+ /* serve first fast and normal handlers */
+ for (node = *list;
+ node && (!(node->flags & IRQ_FLG_SLOW));
+ node = node->next)
+ node->handler(irq, node->dev_id, fp);
+ if (!node) return;
+ save_flags(cpu_flags);
+ restore_flags((cpu_flags & ~0x0700) | (fp->sr & 0x0700));
+ /* if slow handlers exists, serve them now */
+ slow_nodes = node;
+ for (; node; node = node->next) {
+ node->handler(irq, node->dev_id, fp);
+ }
}
/*
- * 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 on VIAs.
+ * mac_enable_irq - enable an interrupt source
+ * mac_disable_irq - disable an interrupt source
+ * mac_clear_irq - clears a pending interrupt
+ * mac_pending_irq - Returns the pending status of an IRQ (nonzero = pending)
*
- * Note: Using these functions on non-VIA/OSS/PSC ints will panic, or at least
- * have undesired side effects.
+ * These routines are just dispatchers to the VIA/OSS/PSC routines.
*/
-void mac_turnon_irq( unsigned int irq )
+void mac_enable_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) /* RBV as VIA2 */
- via_write(via, rIER, via_read(via, rIER)|0x80|(1<<(irqidx)));
- else if (srcidx == SRC_VIA2 && via2_is_oss) /* OSS */
- via_write(oss_regp, oss_map[irqidx]+8, 2);
- else if (srcidx > SRC_VIA2) /* hope AVs have VIA2 */
- via_write(via, (0x104 + 0x10*srcidx),
- via_read(via, (0x104 + 0x10*srcidx))|0x80|(1<<(irqidx)));
- else /* VIA1+2 */
- via_write(via, vIER, via_read(via, vIER)|0x80|(1<<(irqidx)));
-
+ switch(IRQ_SRC(irq)) {
+ case 1: via_irq_enable(irq);
+ break;
+ case 2:
+ case 7: if (oss_present) {
+ oss_irq_enable(irq);
+ } else {
+ via_irq_enable(irq);
+ }
+ break;
+ case 3:
+ case 4:
+ case 5:
+ case 6: if (psc_present) {
+ psc_irq_enable(irq);
+ } else if (oss_present) {
+ oss_irq_enable(irq);
+ }
+ break;
+ }
}
-void mac_turnoff_irq( unsigned int irq )
+void mac_disable_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) /* RBV as VIA2 */
- via_write(via, rIER, (via_read(via, rIER)&(1<<irqidx)));
- else if (srcidx == SRC_VIA2 && via2_is_oss) /* OSS */
- via_write(oss_regp, oss_map[irqidx]+8, 0);
- /*
- * VIA2 is fixed. The stuff above VIA2 is for later
- * macintoshes only.
- */
- else if (srcidx > SRC_VIA2)
- via_write(via, (0x104 + 0x10*srcidx),
- via_read(via, (0x104 + 0x10*srcidx))|(1<<(irqidx)));
- else /* VIA1+2 */
- via_write(via, vIER, (via_read(via, vIER)&(1<<irqidx)));
+ switch(IRQ_SRC(irq)) {
+ case 1: via_irq_disable(irq);
+ break;
+ case 2:
+ case 7:
+ if (oss_present) {
+ oss_irq_disable(irq);
+ } else {
+ via_irq_disable(irq);
+ }
+ break;
+ case 3:
+ case 4:
+ case 5:
+ case 6: if (psc_present) {
+ psc_irq_disable(irq);
+ } else if (oss_present) {
+ oss_irq_disable(irq);
+ }
+ break;
+ }
}
-/*
- * 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 )
+void mac_clear_irq( unsigned int irq )
{
- int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
- int irqidx = (irq & IRQ_IDX_MASK);
-
- irq_flags[srcidx].pending &= ~(1<<irqidx);
+ switch(IRQ_SRC(irq)) {
+ case 1: via_irq_clear(irq);
+ break;
+ case 2:
+ case 7: if (oss_present) {
+ oss_irq_clear(irq);
+ } else {
+ via_irq_clear(irq);
+ }
+ break;
+ case 3:
+ case 4:
+ case 5:
+ case 6: if (psc_present) {
+ psc_irq_clear(irq);
+ } else if (oss_present) {
+ oss_irq_clear(irq);
+ }
+ break;
+ }
}
-int mac_irq_pending( unsigned int irq )
+int mac_irq_pending( unsigned int irq )
{
- int pending = 0;
- volatile unsigned char *via;
-
- int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
- int irqidx = (irq & IRQ_IDX_MASK);
-
- pending = irq_flags[srcidx].pending & (1<<irqidx);
-
- via = (volatile unsigned char *) via_table[srcidx];
- if (!via)
- return (pending);
-
- if (srcidx == SRC_VIA2 && via2_is_rbv)
- pending |= via_read(via, rIFR)&(1<<irqidx);
- else if (srcidx == SRC_VIA2 && via2_is_oss)
- pending |= via_read(via, oIFR)&0x03&(1<<oss_map[irqidx]);
- else if (srcidx > SRC_VIA2)
- pending |= via_read(via, (0x100 + 0x10*srcidx))&(1<<irqidx);
- else
- pending |= via_read(via, vIFR)&(1<<irqidx);
-
- return (pending);
+ switch(IRQ_SRC(irq)) {
+ case 1: return via_irq_pending(irq);
+ case 2:
+ case 7: if (oss_present) {
+ return oss_irq_pending(irq);
+ } else {
+ return via_irq_pending(irq);
+ }
+ case 3:
+ case 4:
+ case 5:
+ case 6: if (psc_present) {
+ return psc_irq_pending(irq);
+ } else if (oss_present) {
+ return oss_irq_pending(irq);
+ }
+ }
+ return 0;
}
/*
- * for /proc/interrupts: log interrupt stats broken down by
- * autovector int first, then by actual interrupt source.
+ * Add an interrupt service routine to an interrupt source.
+ * Returns 0 on success.
+ *
+ * FIXME: You can register interrupts on nonexistant source (ie PSC4 on a
+ * non-PSC machine). We should return -EINVAL in those cases.
*/
-
-int mac_get_irq_list (char *buf)
+
+int mac_request_irq(unsigned int irq,
+ void (*handler)(int, void *, struct pt_regs *),
+ unsigned long flags, const char *devname, void *dev_id)
{
- int i, len = 0;
- int srcidx, irqidx;
-
- for (i = VIA1_SOURCE_BASE; i < NUM_MAC_SOURCES+8; ++i) {
- /* XXX fixme: IRQ_SRC_MASK should cover VIA1 - Nubus */
- srcidx = ((i & IRQ_SRC_MASK)>>3) - 1;
- irqidx = (i & IRQ_IDX_MASK);
-
- /*
- * Not present: skip
- */
-
- if (mac_irqs[srcidx] == NULL)
- continue;
-
- /*
- * never used by VIAs, unused by others so far, counts
- * the magic 'nothing pending' cases ...
- */
- if (irqidx == 7 && mac_irqs[srcidx][irqidx]) {
- len += sprintf(buf+len, "Level %01d: %10lu (spurious) \n",
- srcidx,
- mac_irqs[srcidx][irqidx]);
- continue;
- }
+ int vec, ret;
- /*
- * Nothing registered for this IPL: skip
- */
-
- if (handler_table[srcidx] == NULL)
- continue;
-
- /*
- * No handler installed: skip
- */
-
- if (handler_table[srcidx][irqidx].handler == mac_default_handler ||
- handler_table[srcidx][irqidx].handler == nubus_wtf)
- continue;
-
-
- if (i < VIA2_SOURCE_BASE)
- len += sprintf(buf+len, "via1 %01d: %10lu ",
- irqidx,
- mac_irqs[srcidx][irqidx]);
- else if (i < RBV_SOURCE_BASE)
- len += sprintf(buf+len, "via2 %01d: %10lu ",
- irqidx,
- mac_irqs[srcidx][irqidx]);
- else if (i < MAC_SCC_SOURCE_BASE)
- len += sprintf(buf+len, "rbv %01d: %10lu ",
- irqidx,
- mac_irqs[srcidx][irqidx]);
- else if (i < NUBUS_SOURCE_BASE)
- len += sprintf(buf+len, "scc %01d: %10lu ",
- irqidx,
- mac_irqs[srcidx][irqidx]);
- else /* Nubus */
- len += sprintf(buf+len, "nubus %01d: %10lu ",
- irqidx,
- mac_irqs[srcidx][irqidx]);
-
- len += sprintf(buf+len, "%s\n",
- param_table[srcidx][irqidx].devname);
+#ifdef DEBUG_MACINTS
+ printk ("%s: irq %d requested for %s\n", __FUNCTION__, irq, devname);
+#endif
+ if (irq < VIA1_SOURCE_BASE) {
+ vec = VEC_SPUR + irq;
+ } else if (irq < NUM_MAC_SOURCES) {
+ vec = VEC_USER + irq - VIA1_SOURCE_BASE;
+ } else {
+ printk ("%s: unknown irq %d requested by %s\n",
+ __FUNCTION__, irq, devname);
+ return -EAGAIN;
}
- if (num_spurious)
- len += sprintf(buf+len, "spurio.: %10u\n", num_spurious);
-
- /*
- * XXX Fixme: Nubus sources are never logged above ...
- */
-
- len += sprintf(buf+len, "Nubus interrupts:\n");
-
- for (i = 0; i < 7; i++) {
- if (nubus_handler[i].handler == nubus_wtf)
- continue;
- len += sprintf(buf+len, "nubus %01X: %10lu ",
- i+9,
- nubus_irqs[i]);
- len += sprintf(buf+len, "%s\n",
- nubus_param[i].devname);
+ ret = sys_request_listirq(vec, handler, flags, devname, dev_id);
+ if (!ret) {
+ vectors[vec] = autoirq_listhandler;
+ mac_enable_irq(irq);
}
- len += sprintf(buf+len, "nubus spurious ints: %10lu\n",
- nubus_irqs[7]);
- len += sprintf(buf+len, "nubus stuck events : %10lu\n",
- nubus_stuck_events);
-#ifdef CONFIG_BLK_DEV_IDE
- len += sprintf(buf+len, "nubus/IDE interrupt: %10lu\n",
- mac_ide_irqs);
-#endif
- return len;
+ return ret;
}
+
+/*
+ * Removes an interrupt service routine from an interrupt source.
+ */
-void via_scsi_clear(void)
+void mac_free_irq(unsigned int irq, void *dev_id)
{
- 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 if (via2_is_oss) {
- /* nothing */
- /* via_write(oss_regp, 9, 0) */;
- } else
- deep_magic = via_read(via2_regp, vBufB);
- mac_enable_irq( IRQ_IDX(IRQ_MAC_SCSI) );
-}
-
+ irq_node_t **list = NULL;
+ int vec = 0;
-void mac_default_handler(int irq, void *dev_id, struct pt_regs *regs)
-{
-#ifdef DEBUG_SPURIOUS
- if (console_loglevel > 6)
- printk("Unexpected IRQ %d on device %p\n", irq, dev_id);
+#ifdef DEBUG_MACINTS
+ printk ("%s: irq %d freed by %p\n", __FUNCTION__, irq, dev_id);
#endif
-}
-static int num_debug[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+ if (irq < VIA1_SOURCE_BASE) {
+ vec = VEC_SPUR + irq;
+ list = &autoirq_list[irq];
+ } else if (irq < NUM_MAC_SOURCES) {
+ vec = VEC_USER + irq - VIA1_SOURCE_BASE;
+ list = &userirq_list[irq - VIA1_SOURCE_BASE];
+ }
+ if (!list) return;
-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]++;
+ sys_free_irq(vec, dev_id);
+
+ /* If the list for this interrupt is */
+ /* empty then disable the source. */
+
+ if (!*list) {
+ mac_disable_irq(irq);
+ vectors[vec] = bad_interrupt;
}
}
-void scsi_mac_debug(void);
-void scsi_mac_polled(void);
-
static int in_nmi = 0;
static volatile int nmi_hold = 0;
@@ -869,10 +505,6 @@ void mac_nmi_handler(int irq, void *dev_id, struct pt_regs *fp)
*/
in_nmi++;
-#if 0
- scsi_mac_debug();
- printk("PC: %08lx\nSR: %04x SP: %p\n", fp->pc, fp->sr, fp);
-#endif
for (i=0; i<100; i++)
udelay(1000);
@@ -889,10 +521,6 @@ void mac_nmi_handler(int irq, void *dev_id, struct pt_regs *fp)
while (nmi_hold == 1)
udelay(1000);
-#if 0
- scsi_mac_polled();
-#endif
-
if ( console_loglevel >= 8 ) {
#if 0
show_state();
@@ -916,799 +544,12 @@ void mac_nmi_handler(int irq, void *dev_id, struct pt_regs *fp)
}
/*
- * Unexpected via interrupt
- */
-
-void via_wtf(int slot, void *via, struct pt_regs *regs)
-{
-#ifdef DEBUG_SPURIOUS
- if (console_loglevel > 6)
- printk("Unexpected nubus event %d on via %p\n",slot,via);
-#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];
- unsigned long *via_irqs = mac_irqs[*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)
- {
-#ifdef DEBUG_VIA
- /* should go away; mostly missing timer ticks and ADB events */
- printk("via%d_irq: nothing pending, flags %x mask %x!\n",
- *viaidx + 1, via_read(via, vIFR), via_read(via,vIER));
-#endif
- via_irqs[7]++;
- 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)) {
- if (!irq_flags[*viaidx].pending&(1<<i))
- via_irqs[i]++;
- /* irq disabled -> mark pending */
- irq_flags[*viaidx].pending |= (1<<i);
- } else {
- via_irqs[i]++;
- /* 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)
- {
-#ifdef DEBUG_VIA
- printk("via%d: stuck events %x\n", (*viaidx)+1, events);
-#endif
- 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];
-
- /* shouldn't we disable interrupts here ?? */
-
-
- /*
- * Shouldnt happen
- */
-
- if(events==0)
- {
-#ifdef DEBUG_VIA
- printk("rbv_irq: nothing pending, flags %x mask %x!\n",
- via_read(via, rIFR), via_read(via,rIER));
-#endif
- rbv_irqs[7]++;
- return;
- }
-
-#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.
- */
-
- 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)) {
- if (!irq_flags[srcidx].pending&(1<<i))
- rbv_irqs[i]++;
- /* irq disabled -> mark pending */
- irq_flags[srcidx].pending |= (1<<i);
- } else {
- rbv_irqs[i]++;
- /* 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
-}
-
-/*
- * Nubus / SCSI interrupts; OSS style
- * The OSS is even more different than the RBV. OSS appears to stand for
- * Obscenely Screwed Silicon ...
- *
- * Latest NetBSD sources suggest the OSS should behave like a RBV, but
- * that's probably true for the 0x203 offset (Nubus/ADB-SWIM IOP) at best
- */
-
-void oss_irq(int irq, void *dev_id, struct pt_regs *regs)
-{
- int srcidx = IRQ_IDX(irq) - 1; /* MUST be 1 !! */
- volatile unsigned char *via = oss_regp;
- unsigned char events=(via_read(via, oIFR))&0x03;
- unsigned char nub_ev=(via_read(via, nIFR))&0x4F;
- unsigned char adb_ev;
- int i;
- int ct = 0;
- struct irqhandler *via_handler = handler_table[srcidx];
- struct irqparam *via_param = param_table[srcidx];
-
- /* shouldn't we disable interrupts here ?? */
-
- adb_ev = nub_ev & 0x40;
- nub_ev &= 0x3F;
-
- /*
- * Shouldnt happen
- */
-
- if (events==0 && adb_ev==0 && nub_ev==0)
- {
- printk("oss_irq: nothing pending, flags %x %x!\n",
- via_read(via, oIFR), via_read(via, nIFR));
- rbv_irqs[7]++;
- return;
- }
-
-#ifdef DEBUG_VIA
- /*
- * limited verbosity for RBV interrupts (add more if needed)
- */
- if ( events != 1<<3 ) /* SCSI IRQ */
- printk("oss_irq: irq %d srcidx+1 %d events %x %x %x !\n", irq, srcidx+1,
- events, adb_ev, nub_ev);
-#endif
-
- /*
- * OSS priorities: call ADB handler first if registered, other events,
- * then Nubus
- * ADB: yet to be implemented!
- */
-
- /*
- * ADB: try to shutup the IOP
- */
- if (adb_ev) {
- printk("Hands off ! Don't press this button ever again !!!\n");
- via_write(via, 6, 0);
- }
-
- do {
- /*
- * Clear the pending flags
- * How exactly is that supposed to work ??
- */
-
- /*
- * Now see what bits are raised
- */
-
- for(i=0;i<7;i++)
- {
- /* HACK HACK: map to bit number in OSS register */
- int irqidx = oss_map[i];
- /* determine machspec. irq no. */
- int irq = (srcidx+1)* 8 + i;
- /* call corresponding handlers */
- if ( (events&(1<<irqidx)) && /* bit set*/
- (via_read(via, irqidx+8)&0x7) ) { /* irq enabled */
- if (irq_flags[srcidx].disabled & (1<<i)) {
- if (!irq_flags[srcidx].pending&(1<<i))
- rbv_irqs[i]++;
- /* irq disabled -> mark pending */
- irq_flags[srcidx].pending |= (1<<i);
- } else {
- rbv_irqs[i]++;
- /* 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, oIFR)/*&via_read(via,rIER)*/)&0x03;
- ct++;
- if(events && ct>8)
- {
- printk("oss: stuck events %x\n",events);
- for(i=0;i<7;i++)
- {
- if(events&(1<<i))
- {
- printk("oss - bashing source %d\n",
- i);
- /* that should disable it */
- via_write(via, 8+i, 0);
- }
- }
- break;
- }
- }
- while(events);
-#if 0
- scsi_mac_polled();
-#endif
-
- if (nub_ev)
- oss_do_nubus(irq, via, regs);
-
-}
-
-/*
- * Unexpected slot interrupt
- */
-
-void nubus_wtf(int slot, void *via, struct pt_regs *regs)
-{
-#ifdef DEBUG_NUBUS_SPURIOUS
- if (console_loglevel > 6)
- printk("Unexpected interrupt on nubus slot %d\n",slot);
-#endif
-}
-
-/*
* SCC master interrupt handler; sole purpose: pass the registered
* async struct to the SCC handler proper.
*/
void mac_SCC_handler(int irq, void *dev_id, struct pt_regs *regs)
{
- int i;
- /* 1+2: compatibility with PSC ! */
- for (i = 1; i < 3; i++) /* currently only these two used */
- if (scc_handler[i].handler != mac_default_handler) {
- (scc_handler[i].handler)(i, scc_handler[i].dev_id, regs);
- scc_irqs[i]++;
- }
-}
-
-/*
- * PSC interrupt handler
- */
-
-void psc_irq(int irq, void *dev_id, struct pt_regs *regs)
-{
- int srcidx = IRQ_IDX(irq) - 1;
- volatile unsigned char *via = psc_regp;
- unsigned int pIFR = 0x100 + 0x10*srcidx;
- unsigned int pIER = 0x104 + 0x10*srcidx;
- unsigned char events=(via_read(via, pIFR)&via_read(via,pIER))&0xF;
- int i;
- int ct = 0;
- struct irqhandler *via_handler = handler_table[srcidx];
- struct irqparam *via_param = param_table[srcidx];
-
- /* shouldn't we disable interrupts here ?? */
-
-
- /*
- * Shouldnt happen
- */
-
- if(events==0)
- {
-#ifdef DEBUG_VIA
- printk("psc_irq: nothing pending, flags %x mask %x!\n",
- via_read(via, pIFR), via_read(via,pIER));
-#endif
- mac_irqs[srcidx][7]++;
- return;
- }
-
-#ifdef DEBUG_VIA
- /*
- * limited verbosity for PSC interrupts (add more if needed)
- */
- if ( srcidx == 1 && events != 1<<3 && events != 1<<1 ) /* SCSI IRQ */
- printk("psc_irq: irq %d srcidx+1 %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.
- */
-
- do {
- /*
- * Clear the pending flag
- */
-
- /* via_write(via, pIFR, events); */
-
- /*
- * 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)) {
- if (!irq_flags[srcidx].pending&(1<<i))
- mac_irqs[srcidx][i]++;
- /* irq disabled -> mark pending */
- irq_flags[srcidx].pending |= (1<<i);
- } else {
- mac_irqs[srcidx][i]++;
- /* 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,pIFR)&via_read(via,pIER))&0x7F;
- ct++;
- if(events && ct>8)
- {
- printk("psc: stuck events %x\n",events);
- for(i=0;i<7;i++)
- {
- if(events&(1<<i))
- {
- printk("psc - bashing source %d\n",
- i);
- via_write(via, pIER, 1<<i);
- /* via_write(via, pIFR, (1<<i)); */
- }
- }
- break;
- }
- }
- while(events);
-}
-
-
-/*
- * 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 *dev_id, 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 =dev_id;
- nubus_param[slot].flags = IRQ_FLG_LOCK;
- nubus_param[slot].devname = "nubus slot";
-
- /*
- * if no nubus int. was active previously: register the main nubus irq
- * handler now!
- */
-
- if (!nubus_active && !via2_is_oss) {
- request_irq(IRQ_MAC_NUBUS, via_do_nubus, IRQ_FLG_LOCK,
- "nubus dispatch", via_do_nubus);
- mac_turnon_irq(IRQ_MAC_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_oss)
- via_write(oss_regp, slot, 2);
- else 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 if (via2_is_oss)
- via_write(oss_regp, slot, 0);
- 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;
-}
-
-#ifdef CONFIG_BLK_DEV_MAC_IDE
-/*
- * IDE interrupt hook
- */
-extern void (*mac_ide_intr_hook)(int, void *, struct pt_regs *);
-extern int (*mac_ide_irq_p_hook)(void);
-#endif
-
-/*
- * Nubus dispatch handler - VIA/RBV style
- */
-static void via_do_nubus(int slot, void *via, struct pt_regs *regs)
-{
- unsigned char map, allints;
- int i;
- int ct=0;
- int ide_pending = 0;
-
- /* lock the nubus interrupt */
- /* That's just 'clear Nubus IRQ bit in VIA2' BTW. Pretty obsolete ? */
- if (via2_is_rbv)
- via_write(rbv_regp, rIFR, 0x82);
- else
- via_write(via2_regp, vIFR, 0x82);
-
-#ifdef CONFIG_BLK_DEV_MAC_IDE
- /* IDE hack */
- if (mac_ide_intr_hook) {
- /* 'slot' is lacking the machspec bit in 2.0 */
- /* need to pass proper dev_id = hwgroup here */
- mac_ide_intr_hook(IRQ_MAC_NUBUS, via, regs);
- mac_ide_irqs++;
- }
-#endif
-
- while(1)
- {
- if (via2_is_rbv)
- allints = ~via_read(rbv_regp, rBufA);
- else
- allints = ~via_read(via2_regp, vBufA);
-
-#ifdef CONFIG_BLK_DEV_MAC_IDE
- if (mac_ide_irq_p_hook)
- ide_pending = mac_ide_irq_p_hook();
-#endif
-
- if ( (map = (allints&nubus_active)) == 0
-#ifdef CONFIG_BLK_DEV_MAC_IDE
- && !ide_pending
-#endif
- )
- {
- if (ct == 0) {
-#ifdef DEBUG_VIA_NUBUS
- if (console_loglevel > 5)
- printk("nubus_irq: nothing pending, map %x mask %x active %x\n",
- allints, nubus_active, map);
-#endif
- nubus_irqs[7]++;
- }
- /* clear it */
- if (allints)
- if (via2_is_rbv)
- via_write(rbv_regp, rIFR, 0x02);
- else
- via_write(via2_regp, vIFR, 0x02);
- break;
- }
-
-#ifdef DEBUG_VIA_NUBUS
- if (console_loglevel > 6)
- printk("nubus_irq: map %x mask %x active %x\n",
- allints, nubus_active, map);
-#endif
-
-#ifdef CONFIG_BLK_DEV_MAC_IDE
- if (mac_ide_intr_hook && ide_pending) {
- mac_ide_intr_hook(IRQ_MAC_NUBUS, via, regs);
- mac_ide_irqs++;
- }
-#endif
-
- if(ct++>2)
- {
- if (console_loglevel > 5)
- printk("nubus stuck events - %x/%x/%x ide %x\n",
- allints, nubus_active, map, ide_pending);
- nubus_stuck_events++;
-
- return;
- }
-
- for(i=0;i<7;i++)
- {
- if(map&(1<<i))
- {
- nubus_irqs[i]++;
- (nubus_handler[i].handler)(i+9, nubus_handler[i].dev_id, regs);
- }
- }
- /* clear it */
- if (via2_is_rbv)
- via_write(rbv_regp, rIFR, 0x02);
- else
- via_write(via2_regp, vIFR, 0x02);
-
- }
-
- /* And done */
-}
-
-/*
- * Nubus dispatch handler - OSS style
- */
-static void oss_do_nubus(int slot, void *via, struct pt_regs *regs)
-{
- unsigned char map;
- int i;
- int ct=0;
-
-/* printk("nubus interrupt\n");*/
-
-#if 0
- /* lock the nubus interrupt */
- if (via2_is_rbv)
- via_write(rbv_regp, rIFR, 0x82);
- else
- via_write(via2_regp, vIFR, 0x82);
-#endif
-
- /* IDE hack for Quadra: uses Nubus interrupt without any slot bit set */
-#ifdef CONFIG_BLK_DEV_MAC_IDE
- if (mac_ide_intr_hook)
- mac_ide_intr_hook(IRQ_MAC_NUBUS, via, regs);
-#endif
-
- while(1)
- {
- /* pending events */
- map=(via_read(via, nIFR))&0x3F;
-
-#ifdef DEBUG_VIA_NUBUS
- printk("nubus_irq: map %x mask %x\n", map, nubus_active);
-#endif
- if( (map = (map&nubus_active)) ==0 ) {
- if (ct == 0) {
-#ifdef CONFIG_BLK_DEV_MAC_IDE
- if (!mac_ide_intr_hook)
- printk("nubus_irq: nothing pending, map %x mask %x\n",
- map, nubus_active);
-#endif
- nubus_irqs[7]++;
- }
- break;
- }
-
- if(ct++>2)
- {
-#if 0
- printk("nubus stuck events - %d/%d\n", map, nubus_active);
-#endif
- return;
- }
-
- for(i=0;i<7;i++)
- {
- if(map&(1<<i))
- {
- nubus_irqs[i]++;
- /* call handler */
- (nubus_handler[i].handler)((i+9), nubus_handler[i].dev_id, regs);
- /* clear interrupt ?? */
-#if 0
- via_write(oss_regp, i, 0);
-#endif
- }
- }
- /* clear it */
-#if 0
- via_write(oss_regp, nIFR, map);
-#endif
- }
-
- /* And done */
+ mac_do_irq_list(IRQ_SCCA, regs);
+ mac_do_irq_list(IRQ_SCCB, regs);
}
diff --git a/arch/m68k/mac/mackeyb.c b/arch/m68k/mac/mackeyb.c
index a128a6314..0d70357dc 100644
--- a/arch/m68k/mac/mackeyb.c
+++ b/arch/m68k/mac/mackeyb.c
@@ -613,7 +613,7 @@ int mac_kbdrate(struct kbd_repeat *k)
return 0;
}
-__initfunc(int mac_keyb_init(void))
+int __init mac_keyb_init(void)
{
static struct adb_request autopoll_req, confcod_req, mouse_req, readkey_req;
volatile int ct;
diff --git a/arch/m68k/mac/oss.c b/arch/m68k/mac/oss.c
new file mode 100644
index 000000000..442d72802
--- /dev/null
+++ b/arch/m68k/mac/oss.c
@@ -0,0 +1,314 @@
+/*
+ * OSS handling
+ * Written by Joshua M. Thompson (funaho@jurai.org)
+ *
+ *
+ * This chip is used in the IIfx in place of VIA #2. It acts like a fancy
+ * VIA chip with prorammable interrupt levels.
+ *
+ * 990502 (jmt) - Major rewrite for new interrupt architecture as well as some
+ * recent insights into OSS operational details.
+ * 990610 (jmt) - Now taking fulll advantage of the OSS. Interrupts are mapped
+ * to mostly match the A/UX interrupt scheme supported on the
+ * VIA side. Also added support for enabling the ISM irq again
+ * since we now have a functional IOP manager.
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+
+#include <asm/bootinfo.h>
+#include <asm/machw.h>
+#include <asm/macintosh.h>
+#include <asm/macints.h>
+#include <asm/mac_via.h>
+#include <asm/mac_oss.h>
+
+int oss_present;
+volatile struct mac_oss *oss;
+
+void oss_irq(int, void *, struct pt_regs *);
+void oss_nubus_irq(int, void *, struct pt_regs *);
+
+extern void via1_irq(int, void *, struct pt_regs *);
+extern void mac_SCC_handler(int, void *, struct pt_regs *);
+extern int console_loglevel;
+
+/*
+ * Initialize the OSS
+ *
+ * The OSS "detection" code is actually in via_init() which is always called
+ * before us. Thus we can count on oss_present being valid on entry.
+ */
+
+void __init oss_init(void)
+{
+ int i;
+
+ if (!oss_present) return;
+
+ oss = (struct mac_oss *) OSS_BASE;
+
+ /* Disable all interrupts. Unlike a VIA it looks like we */
+ /* do this by setting the source's interrupt level to zero. */
+
+ for (i = 0; i <= OSS_NUM_SOURCES; i++) {
+ oss->irq_level[i] = OSS_IRQLEV_DISABLED;
+ }
+ /* If we disable VIA1 here, we never really handle it... */
+ oss->irq_level[OSS_VIA1] = OSS_IRQLEV_VIA1;
+}
+
+/*
+ * Register the OSS and NuBus interrupt dispatchers.
+ */
+
+void __init oss_register_interrupts(void)
+{
+ request_irq(OSS_IRQLEV_SCSI, oss_irq, IRQ_FLG_LOCK,
+ "OSS SCSI Dispatch", (void *) oss);
+ request_irq(OSS_IRQLEV_IOPSCC, mac_SCC_handler, IRQ_FLG_LOCK,
+ "SCC Dispatch", mac_SCC_handler);
+ request_irq(OSS_IRQLEV_NUBUS, oss_nubus_irq, IRQ_FLG_LOCK,
+ "Nubus Dispatch", (void *) oss);
+ request_irq(OSS_IRQLEV_SOUND, oss_irq, IRQ_FLG_LOCK,
+ "OSS Sound Dispatch", (void *) oss);
+ request_irq(OSS_IRQLEV_VIA1, via1_irq, IRQ_FLG_LOCK,
+ "VIA1 Dispatch", (void *) via1);
+}
+
+/*
+ * Initialize OSS for Nubus access
+ */
+
+void __init oss_nubus_init(void)
+{
+}
+
+/*
+ * Turn off the power via the ROM control register
+ *
+ * FIXME: not sure how this is supposed to work exactly...
+ */
+
+void oss_poweroff(void)
+{
+ oss->rom_ctrl = OSS_POWEROFF;
+
+ /* We should never make it this far... */
+
+ printk ("It is now safe to switch off your machine.\n");
+ while(1);
+}
+
+/*
+ * Handle miscellaneous OSS interrupts. Right now that's just sound
+ * and SCSI; everything else is routed to its own autovector IRQ.
+ */
+
+void oss_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+ int events;
+
+ events = oss->irq_pending & (OSS_IP_SOUND|OSS_IP_SCSI);
+ if (!events) return;
+
+#ifdef DEBUG_IRQS
+ if ((console_loglevel == 10) && !(events & OSS_IP_SCSI)) {
+ printk("oss_irq: irq %d events = 0x%04X\n", irq,
+ (int) oss->irq_pending);
+ }
+#endif
+ /* FIXME: how do you clear a pending IRQ? */
+
+ if (events & OSS_IP_SOUND) {
+ /* FIXME: call sound handler */
+ oss->irq_pending &= ~OSS_IP_SOUND;
+ } else if (events & OSS_IP_SCSI) {
+ oss->irq_level[OSS_SCSI] = OSS_IRQLEV_DISABLED;
+ mac_do_irq_list(IRQ_MAC_SCSI, regs);
+ oss->irq_pending &= ~OSS_IP_SCSI;
+ oss->irq_level[OSS_SCSI] = OSS_IRQLEV_SCSI;
+ } else {
+ /* FIXME: error check here? */
+ }
+}
+
+/*
+ * Nubus IRQ handler, OSS style
+ *
+ * Unlike the VIA/RBV this is on its own autovector interupt level.
+ */
+
+void oss_nubus_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+ int events, irq_bit, i;
+
+ events = oss->irq_pending & OSS_IP_NUBUS;
+ if (!events) return;
+
+#ifdef DEBUG_NUBUS_INT
+ if (console_loglevel > 7) {
+ printk("oss_nubus_irq: events = 0x%04X\n", events);
+ }
+#endif
+ /* There are only six slots on the OSS, not seven */
+
+ for (i = 0, irq_bit = 1 ; i < 6 ; i++, irq_bit <<= 1) {
+ if (events & irq_bit) {
+ oss->irq_level[i] = OSS_IRQLEV_DISABLED;
+ mac_do_irq_list(NUBUS_SOURCE_BASE + i, regs);
+ oss->irq_pending &= ~irq_bit;
+ oss->irq_level[i] = OSS_IRQLEV_NUBUS;
+ }
+ }
+}
+
+/*
+ * Enable an OSS interrupt
+ *
+ * It looks messy but it's rather straightforward. The switch() statement
+ * just maps the machspec interrupt numbers to the right OSS interrupt
+ * source (if the OSS handles that interrupt) and then sets the interrupt
+ * level for that source to nonzero, thus enabling the interrupt.
+ */
+
+void oss_irq_enable(int irq) {
+#ifdef DEBUG_IRQUSE
+ printk("oss_irq_enable(%d)\n", irq);
+#endif
+ switch(irq) {
+ case IRQ_SCC:
+ case IRQ_SCCA:
+ case IRQ_SCCB:
+ oss->irq_level[OSS_IOPSCC] = OSS_IRQLEV_IOPSCC;
+ break;
+ case IRQ_MAC_ADB:
+ oss->irq_level[OSS_IOPISM] = OSS_IRQLEV_IOPISM;
+ break;
+ case IRQ_MAC_SCSI:
+ oss->irq_level[OSS_SCSI] = OSS_IRQLEV_SCSI;
+ break;
+ case IRQ_NUBUS_9:
+ case IRQ_NUBUS_A:
+ case IRQ_NUBUS_B:
+ case IRQ_NUBUS_C:
+ case IRQ_NUBUS_D:
+ case IRQ_NUBUS_E:
+ irq -= NUBUS_SOURCE_BASE;
+ oss->irq_level[irq] = OSS_IRQLEV_NUBUS;
+ break;
+#ifdef DEBUG_IRQUSE
+ default:
+ printk("%s unknown irq %d\n",__FUNCTION__, irq);
+ break;
+#endif
+ }
+}
+
+/*
+ * Disable an OSS interrupt
+ *
+ * Same as above except we set the source's interrupt level to zero,
+ * to disable the interrupt.
+ */
+
+void oss_irq_disable(int irq) {
+#ifdef DEBUG_IRQUSE
+ printk("oss_irq_disable(%d)\n", irq);
+#endif
+ switch(irq) {
+ case IRQ_SCC:
+ case IRQ_SCCA:
+ case IRQ_SCCB:
+ oss->irq_level[OSS_IOPSCC] = OSS_IRQLEV_DISABLED;
+ break;
+ case IRQ_MAC_ADB:
+ oss->irq_level[OSS_IOPISM] = OSS_IRQLEV_DISABLED;
+ break;
+ case IRQ_MAC_SCSI:
+ oss->irq_level[OSS_SCSI] = OSS_IRQLEV_DISABLED;
+ break;
+ case IRQ_NUBUS_9:
+ case IRQ_NUBUS_A:
+ case IRQ_NUBUS_B:
+ case IRQ_NUBUS_C:
+ case IRQ_NUBUS_D:
+ case IRQ_NUBUS_E:
+ irq -= NUBUS_SOURCE_BASE;
+ oss->irq_level[irq] = OSS_IRQLEV_DISABLED;
+ break;
+#ifdef DEBUG_IRQUSE
+ default:
+ printk("%s unknown irq %d\n", __FUNCTION__, irq);
+ break;
+#endif
+ }
+}
+
+/*
+ * Clear an OSS interrupt
+ *
+ * Not sure if this works or not but it's the only method I could
+ * think of based on the contents of the mac_oss structure.
+ */
+
+void oss_irq_clear(int irq) {
+ /* FIXME: how to do this on OSS? */
+ switch(irq) {
+ case IRQ_SCC:
+ case IRQ_SCCA:
+ case IRQ_SCCB:
+ oss->irq_pending &= ~OSS_IP_IOPSCC;
+ break;
+ case IRQ_MAC_ADB:
+ oss->irq_pending &= ~OSS_IP_IOPISM;
+ break;
+ case IRQ_MAC_SCSI:
+ oss->irq_pending &= ~OSS_IP_SCSI;
+ break;
+ case IRQ_NUBUS_9:
+ case IRQ_NUBUS_A:
+ case IRQ_NUBUS_B:
+ case IRQ_NUBUS_C:
+ case IRQ_NUBUS_D:
+ case IRQ_NUBUS_E:
+ irq -= NUBUS_SOURCE_BASE;
+ oss->irq_pending &= ~(1 << irq);
+ break;
+ }
+}
+
+/*
+ * Check to see if a specific OSS interrupt is pending
+ */
+
+int oss_irq_pending(int irq)
+{
+ switch(irq) {
+ case IRQ_SCC:
+ case IRQ_SCCA:
+ case IRQ_SCCB:
+ return oss->irq_pending & OSS_IP_IOPSCC;
+ break;
+ case IRQ_MAC_ADB:
+ return oss->irq_pending & OSS_IP_IOPISM;
+ break;
+ case IRQ_MAC_SCSI:
+ return oss->irq_pending & OSS_IP_SCSI;
+ break;
+ case IRQ_NUBUS_9:
+ case IRQ_NUBUS_A:
+ case IRQ_NUBUS_B:
+ case IRQ_NUBUS_C:
+ case IRQ_NUBUS_D:
+ case IRQ_NUBUS_E:
+ irq -= NUBUS_SOURCE_BASE;
+ return oss->irq_pending & (1 << irq);
+ break;
+ }
+ return 0;
+}
diff --git a/arch/m68k/mac/psc.c b/arch/m68k/mac/psc.c
new file mode 100644
index 000000000..122659555
--- /dev/null
+++ b/arch/m68k/mac/psc.c
@@ -0,0 +1,203 @@
+/*
+ * Apple Peripheral System Controller (PSC)
+ *
+ * The PSC is used on the AV Macs to control IO functions not handled
+ * by the VIAs (Ethernet, DSP, SCC).
+ *
+ * TO DO:
+ *
+ * Try to figure out what's going on in pIFR5 and pIFR6. There seem to be
+ * persisant interrupt conditions in those registers and I have no idea what
+ * they are. Granted it doesn't affect since we're not enabling any interrupts
+ * on those levels at the moment, but it would be nice to know. I have a feeling
+ * they aren't actually interrupt lines but data lines (to the DSP?)
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+
+#include <asm/traps.h>
+#include <asm/bootinfo.h>
+#include <asm/macintosh.h>
+#include <asm/macints.h>
+#include <asm/mac_psc.h>
+
+#define DEBUG_PSC
+
+int psc_present;
+volatile __u8 *psc;
+
+void psc_irq(int, void *, struct pt_regs *);
+
+extern int console_loglevel;
+
+/*
+ * Debugging dump, used in various places to see what's going on.
+ */
+
+void psc_debug_dump(void)
+{
+ int i;
+
+ if (!psc_present) return;
+ for (i = 0x30 ; i < 0x70 ; i += 0x10) {
+ printk("PSC #%d: IFR = 0x%02X IER = 0x%02X\n",
+ i >> 4,
+ (int) psc_read_byte(pIFRbase + i),
+ (int) psc_read_byte(pIERbase + i));
+ }
+}
+
+/*
+ * Try to kill all DMA channels on the PSC. Not sure how this his
+ * supposed to work; this is code lifted from macmace.c and then
+ * expanded to cover what I think are the other 7 channels.
+ */
+
+void psc_dma_die_die_die(void)
+{
+ int i;
+
+ printk("Killing all PSC DMA channels...");
+ for (i = 0 ; i < 9 ; i++) {
+ psc_write_word(PSC_CTL_BASE + (i << 4), 0x8800);
+ psc_write_word(PSC_CTL_BASE + (i << 4), 0x1000);
+ psc_write_word(PSC_CMD_BASE + (i << 5), 0x1100);
+ psc_write_word(PSC_CMD_BASE + (i << 5) + 0x10, 0x1100);
+ }
+ printk("done!\n");
+}
+
+/*
+ * Initialize the PSC. For now this just involves shutting down all
+ * interrupt sources using the IERs.
+ */
+
+void __init psc_init(void)
+{
+ int i;
+
+ if (macintosh_config->ident != MAC_MODEL_C660
+ && macintosh_config->ident != MAC_MODEL_Q840)
+ {
+ psc = NULL;
+ psc_present = 0;
+ return;
+ }
+
+ /*
+ * The PSC is always at the same spot, but using psc
+ * keeps things consisant with the psc_xxxx functions.
+ */
+
+ psc = (void *) PSC_BASE;
+ psc_present = 1;
+
+ printk("PSC detected at %p\n", psc);
+
+ psc_dma_die_die_die();
+
+#ifdef DEBUG_PSC
+ psc_debug_dump();
+#endif
+ /*
+ * Mask and clear all possible interrupts
+ */
+
+ for (i = 0x30 ; i < 0x70 ; i += 0x10) {
+ psc_write_byte(pIERbase + i, 0x0F);
+ psc_write_byte(pIFRbase + i, 0x0F);
+ }
+}
+
+/*
+ * Register the PSC interrupt dispatchers for autovector interrupts 3-6.
+ */
+
+void __init psc_register_interrupts(void)
+{
+ request_irq(3, psc_irq, IRQ_FLG_LOCK, "PSC Dispatch",
+ (void *) 0x30);
+ request_irq(4, psc_irq, IRQ_FLG_LOCK, "PSC Dispatch",
+ (void *) 0x40);
+ request_irq(5, psc_irq, IRQ_FLG_LOCK, "PSC Dispatch",
+ (void *) 0x50);
+ request_irq(6, psc_irq, IRQ_FLG_LOCK, "PSC Dispatch",
+ (void *) 0x60);
+}
+
+/*
+ * PSC interrupt handler. It's a lot like the VIA interrupt handler.
+ */
+
+void psc_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+ int pIFR = pIFRbase + ((int) dev_id);
+ int pIER = pIERbase + ((int) dev_id);
+ int base_irq;
+ int irq_bit,i;
+ unsigned char events;
+
+ irq -= VEC_SPUR;
+ base_irq = irq << 3;
+
+#ifdef DEBUG_IRQS
+ printk("psc_irq: irq %d pIFR = 0x%02X pIER = 0x%02X\n",
+ irq, (int) psc_read_byte(pIFR), (int) psc_read_byte(pIER));
+#endif
+
+ events = psc_read_byte(pIFR) & psc_read_byte(pIER) & 0xF;
+ if (!events) return;
+
+ for (i = 0, irq_bit = 1 ; i < 4 ; i++, irq_bit <<= 1) {
+ if (events & irq_bit) {
+ psc_write_byte(pIER, irq_bit);
+ mac_do_irq_list(base_irq + i, regs);
+ psc_write_byte(pIFR, irq_bit);
+ psc_write_byte(pIER, irq_bit | 0x80);
+ }
+ }
+}
+
+void psc_irq_enable(int irq) {
+ int irq_src = IRQ_SRC(irq);
+ int irq_idx = IRQ_IDX(irq);
+ int pIER = pIERbase + (irq_src << 4);
+
+#ifdef DEBUG_IRQUSE
+ printk("psc_irq_enable(%d)\n", irq);
+#endif
+ psc_write_byte(pIER, (1 << irq_idx) | 0x80);
+}
+
+void psc_irq_disable(int irq) {
+ int irq_src = IRQ_SRC(irq);
+ int irq_idx = IRQ_IDX(irq);
+ int pIER = pIERbase + (irq_src << 4);
+
+#ifdef DEBUG_IRQUSE
+ printk("psc_irq_disable(%d)\n", irq);
+#endif
+ psc_write_byte(pIER, 1 << irq_idx);
+}
+
+void psc_irq_clear(int irq) {
+ int irq_src = IRQ_SRC(irq);
+ int irq_idx = IRQ_IDX(irq);
+ int pIFR = pIERbase + (irq_src << 4);
+
+ psc_write_byte(pIFR, 1 << irq_idx);
+}
+
+int psc_irq_pending(int irq)
+{
+ int irq_src = IRQ_SRC(irq);
+ int irq_idx = IRQ_IDX(irq);
+ int pIFR = pIERbase + (irq_src << 4);
+
+ return psc_read_byte(pIFR) & (1 << irq_idx);
+}
diff --git a/arch/m68k/mac/via.c b/arch/m68k/mac/via.c
new file mode 100644
index 000000000..2205b226c
--- /dev/null
+++ b/arch/m68k/mac/via.c
@@ -0,0 +1,774 @@
+/*
+ * 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.
+ *
+ * CSA: Motorola seems to have removed documentation on the 6522 from
+ * their web site; try
+ * http://nerini.drf.com/vectrex/other/text/chips/6522/
+ * http://www.zymurgy.net/classic/vic20/vicdet1.htm
+ * and
+ * http://193.23.168.87/mikro_laborversuche/via_iobaustein/via6522_1.html
+ * for info. A full-text web search on 6522 AND VIA will probably also
+ * net some usefulness. <cananian@alumni.princeton.edu> 20apr1999
+ *
+ * PRAM/RTC access algorithms are from the NetBSD RTC toolkit version 1.08b
+ * by Erik Vogan and adapted to Linux by Joshua M. Thompson (funaho@jurai.org)
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+
+#include <asm/traps.h>
+#include <asm/bootinfo.h>
+#include <asm/macintosh.h>
+#include <asm/macints.h>
+#include <asm/machw.h>
+#include <asm/mac_via.h>
+#include <asm/mac_psc.h>
+
+volatile __u8 *via1, *via2;
+#if 0
+/* See note in mac_via.h about how this is possibly not useful */
+volatile long *via_memory_bogon=(long *)&via_memory_bogon;
+#endif
+int rbv_present,via_alt_mapping;
+__u8 rbv_clear;
+
+/*
+ * Globals for accessing the VIA chip registers without having to
+ * check if we're hitting a real VIA or an RBV. Normally you could
+ * just hit the combined register (ie, vIER|rIER) but that seems to
+ * break on AV Macs...probably because they actually decode more than
+ * eight address bits. Why can't Apple engineers at least be
+ * _consistantly_ lazy? - 1999-05-21 (jmt)
+ */
+
+static int gIER,gIFR,gBufA,gBufB;
+
+/*
+ * Timer defs.
+ */
+
+#define TICK_SIZE 10000
+#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)
+
+static int nubus_active;
+
+void via_debug_dump(void);
+void via1_irq(int, void *, struct pt_regs *);
+void via2_irq(int, void *, struct pt_regs *);
+void via_nubus_irq(int, void *, struct pt_regs *);
+void via_irq_enable(int irq);
+void via_irq_disable(int irq);
+void via_irq_clear(int irq);
+
+extern void mac_bang(int, void *, struct pt_regs *);
+extern void mac_SCC_handler(int, void *, struct pt_regs *);
+extern int console_loglevel;
+extern int oss_present;
+
+/*
+ * Initialize the VIAs
+ *
+ * First we figure out where they actually _are_ as well as what type of
+ * VIA we have for VIA2 (it could be a real VIA or an RBV or even an OSS.)
+ * Then we pretty much clear them out and disable all IRQ sources.
+ *
+ * Note: the OSS is actually "detected" here and not in oss_init(). It just
+ * seems more logical to do it here since via_init() needs to know
+ * these things anyways.
+ */
+
+void __init via_init(void)
+{
+ switch(macintosh_config->via_type) {
+
+ /* IIci, IIsi, IIvx, IIvi (P6xx), LC series */
+
+ case MAC_VIA_IIci:
+ via1 = (void *) VIA1_BASE;
+ if (macintosh_config->ident == MAC_MODEL_IIFX) {
+ via2 = NULL;
+ rbv_present = 0;
+ oss_present = 1;
+ } else {
+ via2 = (void *) RBV_BASE;
+ rbv_present = 1;
+ oss_present = 0;
+ }
+ if (macintosh_config->ident == MAC_MODEL_LCIII) {
+ rbv_clear = 0x00;
+ } else {
+ /* on most RBVs (& unlike the VIAs), you */
+ /* need to set bit 7 when you write to IFR */
+ /* in order for your clear to occur. */
+ rbv_clear = 0x80;
+ }
+ gIER = rIER;
+ gIFR = rIFR;
+ gBufA = rSIFR;
+ gBufB = rBufB;
+ break;
+
+ /* Quadra and early MacIIs agree on the VIA locations */
+
+ case MAC_VIA_QUADRA:
+ case MAC_VIA_II:
+ via1 = (void *) VIA1_BASE;
+ via2 = (void *) VIA2_BASE;
+ rbv_present = 0;
+ oss_present = 0;
+ rbv_clear = 0x00;
+ gIER = vIER;
+ gIFR = vIFR;
+ gBufA = vBufA;
+ gBufB = vBufB;
+ break;
+ default:
+ panic("UNKNOWN VIA TYPE");
+ }
+
+ printk("VIA1 at %p is a 6522 or clone\n", via1);
+
+ printk("VIA2 at %p is ", via2);
+ if (rbv_present) {
+ printk("an RBV\n");
+ } else if (oss_present) {
+ printk("an OSS\n");
+ } else {
+ printk("a 6522 or clone\n");
+ }
+
+#ifdef DEBUG_VIA
+ via_debug_dump();
+#endif
+
+ /*
+ * Shut down all IRQ sources, reset the timers, and
+ * kill the timer latch on VIA1.
+ */
+
+ via1[vIER] = 0x7F;
+ via1[vIFR] = 0x7F;
+ via1[vT1LL] = 0;
+ via1[vT1LH] = 0;
+ via1[vT1CL] = 0;
+ via1[vT1CH] = 0;
+ via1[vT2CL] = 0;
+ via1[vT2CH] = 0;
+ via1[vACR] &= 0x3F;
+
+ /*
+ * SE/30: disable video IRQ
+ * XXX: testing for SE/30 VBL
+ */
+
+ if (macintosh_config->ident == MAC_MODEL_SE30) {
+ via1[vDirB] |= 0x40;
+ via1[vBufB] |= 0x40;
+ }
+
+ /*
+ * Set the RTC bits to a known state: all lines to outputs and
+ * RTC disabled (yes that's 0 to enable and 1 to disable).
+ */
+
+ via1[vDirB] |= (VIA1B_vRTCEnb | VIA1B_vRTCClk | VIA1B_vRTCData);
+ via1[vBufB] |= (VIA1B_vRTCEnb | VIA1B_vRTCClk);
+
+ /* Everything below this point is VIA2/RBV only... */
+
+ if (oss_present) return;
+
+#if 1
+ /* Some machines support an alternate IRQ mapping that spreads */
+ /* Ethernet and Sound out to their own autolevel IRQs and moves */
+ /* VIA1 to level 6. A/UX uses this mapping and we do too. Note */
+ /* that the IIfx emulates this alternate mapping using the OSS. */
+
+ switch(macintosh_config->ident) {
+ case MAC_MODEL_C610:
+ case MAC_MODEL_Q610:
+ case MAC_MODEL_C650:
+ case MAC_MODEL_Q650:
+ case MAC_MODEL_Q700:
+ case MAC_MODEL_Q800:
+ case MAC_MODEL_Q900:
+ case MAC_MODEL_Q950:
+ via_alt_mapping = 1;
+ via1[vDirB] |= 0x40;
+ via1[vBufB] &= ~0x40;
+ break;
+ default:
+ via_alt_mapping = 0;
+ break;
+ }
+#else
+ /* The alernate IRQ mapping seems to just not work. Anyone with a */
+ /* supported machine is welcome to take a stab at fixing it. It */
+ /* _should_ work on the following Quadras: 610,650,700,800,900,950 */
+ /* - 1999-06-12 (jmt) */
+
+ via_alt_mapping = 0;
+#endif
+
+ /*
+ * Now initialize VIA2. For RBV we just kill all interrupts;
+ * for a regular VIA we also reset the timers and stuff.
+ */
+
+ via2[gIER] = 0x7F;
+ via2[gIFR] = 0x7F | rbv_clear;
+ if (!rbv_present) {
+ via2[vT1LL] = 0;
+ via2[vT1LH] = 0;
+ via2[vT1CL] = 0;
+ via2[vT1CH] = 0;
+ via2[vT2CL] = 0;
+ via2[vT2CH] = 0;
+ via2[vACR] &= 0x3F;
+ }
+}
+
+/*
+ * Start the 100 Hz clock
+ */
+
+void __init via_init_clock(void (*func)(int, void *, struct pt_regs *))
+{
+ via1[vACR] |= 0x40;
+ via1[vT1LL] = MAC_CLOCK_LOW;
+ via1[vT1LH] = MAC_CLOCK_HIGH;
+ via1[vT1CL] = MAC_CLOCK_LOW;
+ via1[vT1CH] = MAC_CLOCK_HIGH;
+
+ request_irq(IRQ_MAC_TIMER_1, func, IRQ_FLG_LOCK, "timer", func);
+}
+
+/*
+ * Register the interrupt dispatchers for VIA or RBV machines only.
+ */
+
+void __init via_register_interrupts(void)
+{
+ if (via_alt_mapping) {
+ request_irq(IRQ_AUTO_1, via1_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST,
+ "Software IRQ", (void *) via1);
+ request_irq(IRQ_AUTO_6, via1_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST,
+ "VIA1 Dispatch", (void *) via1);
+ } else {
+ request_irq(IRQ_AUTO_1, via1_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST,
+ "VIA1 Dispatch", (void *) via1);
+#if 0 /* interferes with serial on some machines */
+ if (!psc_present) {
+ request_irq(IRQ_AUTO_6, mac_bang, IRQ_FLG_LOCK,
+ "Off Switch", mac_bang);
+ }
+#endif
+ }
+ request_irq(IRQ_AUTO_2, via2_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST,
+ "VIA2 Dispatch", (void *) via2);
+ if (!psc_present) {
+ request_irq(IRQ_AUTO_4, mac_SCC_handler, IRQ_FLG_LOCK,
+ "SCC Dispatch", mac_SCC_handler);
+ }
+ request_irq(IRQ_MAC_NUBUS, via_nubus_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST,
+ "Nubus Dispatch", (void *) via2);
+}
+
+/*
+ * Debugging dump, used in various places to see what's going on.
+ */
+
+void via_debug_dump(void)
+{
+ printk("VIA1: DDRA = 0x%02X DDRB = 0x%02X ACR = 0x%02X\n",
+ (uint) via1[vDirA], (uint) via1[vDirB], (uint) via1[vACR]);
+ printk(" PCR = 0x%02X IFR = 0x%02X IER = 0x%02X\n",
+ (uint) via1[vPCR], (uint) via1[vIFR], (uint) via1[vIER]);
+ if (oss_present) {
+ printk("VIA2: <OSS>\n");
+ } else if (rbv_present) {
+ printk("VIA2: IFR = 0x%02X IER = 0x%02X\n",
+ (uint) via2[rIFR], (uint) via2[rIER]);
+ printk(" SIFR = 0x%02X SIER = 0x%02X\n",
+ (uint) via2[rSIFR], (uint) via2[rSIER]);
+ } else {
+ printk("VIA2: DDRA = 0x%02X DDRB = 0x%02X ACR = 0x%02X\n",
+ (uint) via2[vDirA], (uint) via2[vDirB],
+ (uint) via2[vACR]);
+ printk(" PCR = 0x%02X IFR = 0x%02X IER = 0x%02X\n",
+ (uint) via2[vPCR],
+ (uint) via2[vIFR], (uint) via2[vIER]);
+ }
+}
+
+/*
+ * This is always executed with interrupts disabled.
+ *
+ * TBI: get time offset between scheduling timer ticks
+ */
+
+unsigned long mac_gettimeoffset (void)
+{
+ unsigned long ticks, offset = 0;
+
+ /* read VIA1 timer 2 current value */
+ ticks = via1[vT1CL] | (via1[vT1CH] << 8);
+ /* The probability of underflow is less than 2% */
+ if (ticks > MAC_CLOCK_TICK - MAC_CLOCK_TICK / 50)
+ /* Check for pending timer interrupt in VIA1 IFR */
+ if (via1[vIFR] & 0x40) offset = TICK_SIZE;
+
+ ticks = MAC_CLOCK_TICK - ticks;
+ ticks = ticks * 10000L / MAC_CLOCK_TICK;
+
+ return ticks + offset;
+}
+
+/*
+ * Flush the L2 cache on Macs that have it by flipping
+ * the system into 24-bit mode for an instant.
+ */
+
+void via_flush_cache(void)
+{
+ via2[gBufB] &= ~VIA2B_vMode32;
+ via2[gBufB] |= VIA2B_vMode32;
+}
+
+/*
+ * Return the status of the L2 cache on a IIci
+ */
+
+int via_get_cache_disable(void)
+{
+ /* Safeguard against being called accidentally */
+ if (!via2) {
+ printk(KERN_ERR "via_get_cache_disable called on a non-VIA machine!\n");
+ return 1;
+ }
+
+ return (int) via2[gBufB] & VIA2B_vCDis;
+}
+
+/*
+ * VIA-based power switch, for machines that support it.
+ */
+
+void via_poweroff(void)
+{
+ if (rbv_present) {
+ via2[rBufB] &= ~0x04;
+ } else {
+ /* Direction of vDirB is output */
+ via2[vDirB] |= 0x04;
+ /* Send a value of 0 on that line */
+ via2[vBufB] &= ~0x04;
+ /* Otherwise it prints "It is now.." then shuts off */
+ mdelay(1000);
+ }
+
+ /* We should never make it this far... */
+ printk ("It is now safe to switch off your machine.\n");
+ while(1);
+}
+
+/*
+ * Initialize VIA2 for Nubus access
+ */
+
+void __init via_nubus_init(void)
+{
+ nubus_active = 0;
+
+ /* unlock nubus transactions */
+
+ if (!rbv_present) {
+ /* set the line to be an output on non-RBV machines */
+ via2[vDirB] |= 0x02;
+ }
+ via2[gBufB] |= 0x02;
+
+ /* disable nubus slot interrupts. */
+ if (rbv_present) {
+ via2[rSIER] = 0x7F; /* like VIA; bit 7=clr,set */
+ } else {
+ via2[vBufA] = 0xFF; /* active low irqs, force high */
+ via2[vDirA] = 0xFF; /* ddr to output. */
+ }
+}
+
+/*
+ * The generic VIA interrupt routines (shamelessly stolen from Alan Cox's
+ * via6522.c :-), disable/pending masks added.
+ *
+ * The new interrupt architecture in macints.c takes care of a lot of the
+ * gruntwork for us, including tallying the interrupts and calling the
+ * handlers on the linked list. All we need to do here is basically generate
+ * the machspec interrupt number after clearing the interrupt.
+ */
+
+void via1_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+ int irq_bit, i;
+ unsigned char events, mask;
+
+ irq -= VEC_SPUR;
+
+ mask = via1[vIER] & 0x7F;
+ if (!(events = via1[vIFR] & mask)) return;
+
+ for (i = 0, irq_bit = 1 ; i < 7 ; i++, irq_bit <<= 1)
+ if (events & irq_bit) {
+ via1[vIER] = irq_bit;
+ mac_do_irq_list(VIA1_SOURCE_BASE + i, regs);
+ via1[vIFR] = irq_bit;
+ via1[vIER] = irq_bit | 0x80;
+ }
+
+ if (!oss_present) {
+ /* This (still) seems to be necessary to get IDE
+ working. However, if you enable VBL interrupts,
+ you're screwed... */
+ /* FIXME: should we check the SLOTIRQ bit before
+ pulling this stunt? */
+ /* No, it won't be set. that's why we're doing this. */
+ via_irq_disable(IRQ_MAC_NUBUS);
+ via_irq_clear(IRQ_MAC_NUBUS);
+ mac_do_irq_list(IRQ_MAC_NUBUS, regs);
+ via_irq_enable(IRQ_MAC_NUBUS);
+ }
+}
+
+void via2_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+ int irq_bit, i;
+ unsigned char events, mask;
+
+ irq -= VEC_SPUR;
+
+ mask = via2[gIER] & 0x7F;
+ if (!(events = via2[gIFR] & mask)) return;
+
+ for (i = 0, irq_bit = 1 ; i < 7 ; i++, irq_bit <<= 1)
+ if (events & irq_bit) {
+ via2[gIER] = irq_bit;
+ mac_do_irq_list(VIA2_SOURCE_BASE + i, regs);
+ via2[gIFR] = irq_bit | rbv_clear;
+ via2[gIER] = irq_bit | 0x80;
+ }
+}
+
+/*
+ * Dispatch Nubus interrupts. We are called as a secondary dispatch by the
+ * VIA2 dispatcher as a fast interrupt handler.
+ */
+
+void via_nubus_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+ int irq_bit, i;
+ unsigned char events;
+
+ if (!(events = ~via2[gBufA] & nubus_active)) return;
+
+ for (i = 0, irq_bit = 1 ; i < 7 ; i++, irq_bit <<= 1) {
+ if (events & irq_bit) {
+ via_irq_disable(NUBUS_SOURCE_BASE + i);
+ mac_do_irq_list(NUBUS_SOURCE_BASE + i, regs);
+ via_irq_enable(NUBUS_SOURCE_BASE + i);
+ }
+ }
+}
+
+void via_irq_enable(int irq) {
+ int irq_src = IRQ_SRC(irq);
+ int irq_idx = IRQ_IDX(irq);
+ int irq_bit = 1 << irq_idx;
+
+#ifdef DEBUG_IRQUSE
+ printk("via_irq_enable(%d)\n", irq);
+#endif
+
+ if (irq_src == 1) {
+ via1[vIER] = irq_bit | 0x80;
+ } else if (irq_src == 2) {
+ /*
+ * Set vPCR for SCSI interrupts (but not on RBV)
+ */
+ if ((irq_idx == 0) && !rbv_present) {
+ if (macintosh_config->scsi_type == MAC_SCSI_OLD) {
+ /* CB2 (IRQ) indep. input, positive edge */
+ /* CA2 (DRQ) indep. input, positive edge */
+ via2[vPCR] = 0x66;
+ } else {
+ /* CB2 (IRQ) indep. input, negative edge */
+ /* CA2 (DRQ) indep. input, negative edge */
+ via2[vPCR] = 0x22;
+ }
+ }
+ via2[gIER] = irq_bit | 0x80;
+ } else if (irq_src == 7) {
+ if (rbv_present) {
+ /* enable the slot interrupt. SIER works like IER. */
+ via2[rSIER] = IER_SET_BIT(irq_idx);
+ } else {
+ /* Make sure the bit is an input, to enable the irq */
+ via2[vDirA] &= ~irq_bit;
+ }
+ nubus_active |= irq_bit;
+ }
+}
+
+void via_irq_disable(int irq) {
+ int irq_src = IRQ_SRC(irq);
+ int irq_idx = IRQ_IDX(irq);
+ int irq_bit = 1 << irq_idx;
+
+#ifdef DEBUG_IRQUSE
+ printk("via_irq_disable(%d)\n", irq);
+#endif
+
+ if (irq_src == 1) {
+ via1[vIER] = irq_bit;
+ } else if (irq_src == 2) {
+ via2[gIER] = irq_bit;
+ } else if (irq_src == 7) {
+ if (rbv_present) {
+ /* disable the slot interrupt. SIER works like IER. */
+ via2[rSIER] = IER_CLR_BIT(irq_idx);
+ } else {
+ /* disable the nubus irq by changing dir to output */
+ via2[vDirA] |= irq_bit;
+ }
+ nubus_active &= ~irq_bit;
+ }
+}
+
+void via_irq_clear(int irq) {
+ int irq_src = IRQ_SRC(irq);
+ int irq_idx = IRQ_IDX(irq);
+ int irq_bit = 1 << irq_idx;
+
+ if (irq_src == 1) {
+ via1[vIFR] = irq_bit;
+ } else if (irq_src == 2) {
+ via2[gIFR] = irq_bit | rbv_clear;
+ } else if (irq_src == 7) {
+ /* FIXME: hmm.. */
+ }
+}
+
+/*
+ * Returns nonzero if an interrupt is pending on the given
+ * VIA/IRQ combination.
+ */
+
+int via_irq_pending(int irq)
+{
+ int irq_src = IRQ_SRC(irq);
+ int irq_idx = IRQ_IDX(irq);
+ int irq_bit = 1 << irq_idx;
+
+ if (irq_src == 1) {
+ return via1[vIFR] & irq_bit;
+ } else if (irq_src == 2) {
+ return via2[gIFR] & irq_bit;
+ } else if (irq_src == 7) {
+ return ~via2[gBufA] & irq_bit;
+ }
+ return 0;
+}
+
+void via_scsi_clear(void)
+{
+ volatile unsigned char deep_magic;
+
+#ifdef DEBUG_IRQUSE
+ printk("via_scsi_clear()\n");
+#endif
+
+ /* We handle this in oss.c , but this gets called in mac_scsinew.c */
+ if(oss_present) return;
+
+ if (rbv_present) {
+ via2[rIFR] = (1<<3) | (1<<0) | rbv_clear;
+ deep_magic = via2[rBufB];
+ } else {
+ deep_magic = via2[vBufB];
+ }
+ mac_enable_irq(IRQ_MAC_SCSI);
+}
+
+/*
+ * PRAM/RTC access routines
+ *
+ * Must be called with interrupts disabled and
+ * the RTC should be enabled.
+ */
+
+static __u8 via_pram_readbyte(void)
+{
+ int i,reg;
+ __u8 data;
+
+ reg = via1[vBufB] & ~VIA1B_vRTCClk;
+
+ /* Set the RTC data line to be an input. */
+
+ via1[vDirB] &= ~VIA1B_vRTCData;
+
+ /* The bits of the byte come out in MSB order */
+
+ data = 0;
+ for (i = 0 ; i < 8 ; i++) {
+ via1[vBufB] = reg;
+ via1[vBufB] = reg | VIA1B_vRTCClk;
+ data = (data << 1) | (via1[vBufB] & VIA1B_vRTCData);
+ }
+
+ /* Return RTC data line to output state */
+
+ via1[vDirB] |= VIA1B_vRTCData;
+
+ return data;
+}
+
+static void via_pram_writebyte(__u8 data)
+{
+ int i,reg,bit;
+
+ reg = via1[vBufB] & ~(VIA1B_vRTCClk | VIA1B_vRTCData);
+
+ /* The bits of the byte go in in MSB order */
+
+ for (i = 0 ; i < 8 ; i++) {
+ bit = data & 0x80? 1 : 0;
+ data <<= 1;
+ via1[vBufB] = reg | bit;
+ via1[vBufB] = reg | bit | VIA1B_vRTCClk;
+ }
+}
+
+/*
+ * Execute a PRAM/RTC command. For read commands
+ * data should point to a one-byte buffer for the
+ * resulting data. For write commands it should point
+ * to the data byte to for the command.
+ *
+ * This function disables all interrupts while running.
+ */
+
+void via_pram_command(int command, __u8 *data)
+{
+ unsigned long cpu_flags;
+ int is_read;
+
+ save_flags(cpu_flags);
+ cli();
+
+ /* Enable the RTC and make sure the strobe line is high */
+
+ via1[vBufB] = (via1[vBufB] | VIA1B_vRTCClk) & ~VIA1B_vRTCEnb;
+
+ if (command & 0xFF00) { /* extended (two-byte) command */
+ via_pram_writebyte((command & 0xFF00) >> 8);
+ via_pram_writebyte(command & 0xFF);
+ is_read = command & 0x8000;
+ } else { /* one-byte command */
+ via_pram_writebyte(command);
+ is_read = command & 0x80;
+ }
+ if (is_read) {
+ *data = via_pram_readbyte();
+ } else {
+ via_pram_writebyte(*data);
+ }
+
+ /* All done, disable the RTC */
+
+ via1[vBufB] |= VIA1B_vRTCEnb;
+
+ restore_flags(cpu_flags);
+}
+
+/*
+ * Return the current time in seconds since January 1, 1904.
+ *
+ * This only works on machines with the VIA-based PRAM/RTC, which
+ * is basically any machine with Mac II-style ADB.
+ */
+
+__u32 via_read_time(void)
+{
+ union {
+ __u8 cdata[4];
+ __u32 idata;
+ } result, last_result;
+ int ct;
+
+ /*
+ * The NetBSD guys say to loop until you get the same reading
+ * twice in a row.
+ */
+
+ ct = 0;
+ do {
+ if (++ct > 10) {
+ printk("via_read_time: couldn't get valid time, "
+ "last read = 0x%08X and 0x%08X\n", last_result.idata,
+ result.idata);
+ break;
+ }
+
+ last_result.idata = result.idata;
+ result.idata = 0;
+
+ via_pram_command(0x81, &result.cdata[3]);
+ via_pram_command(0x85, &result.cdata[2]);
+ via_pram_command(0x89, &result.cdata[1]);
+ via_pram_command(0x8D, &result.cdata[0]);
+ } while (result.idata != last_result.idata);
+
+ return result.idata;
+}
+
+/*
+ * Set the current time to a number of seconds since January 1, 1904.
+ *
+ * This only works on machines with the VIA-based PRAM/RTC, which
+ * is basically any machine with Mac II-style ADB.
+ */
+
+void via_write_time(__u32 time)
+{
+ union {
+ __u8 cdata[4];
+ __u32 idata;
+ } data;
+ __u8 temp;
+
+ /* Clear the write protect bit */
+
+ temp = 0x55;
+ via_pram_command(0x35, &temp);
+
+ data.idata = time;
+ via_pram_command(0x01, &data.cdata[3]);
+ via_pram_command(0x05, &data.cdata[2]);
+ via_pram_command(0x09, &data.cdata[1]);
+ via_pram_command(0x0D, &data.cdata[0]);
+
+ /* Set the write protect bit */
+
+ temp = 0xD5;
+ via_pram_command(0x35, &temp);
+}
diff --git a/arch/m68k/mac/via6522.c b/arch/m68k/mac/via6522.c
deleted file mode 100644
index 05e6f44e4..000000000
--- a/arch/m68k/mac/via6522.c
+++ /dev/null
@@ -1,419 +0,0 @@
-/*
- * 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 <linux/delay.h>
-
-#include <asm/adb.h>
-#include <asm/bootinfo.h>
-#include <asm/macintosh.h>
-#include <asm/macints.h>
-#include "via6522.h"
-#include <asm/mac_psc.h>
-
-volatile unsigned char *via1=(unsigned char *)VIABASE;
-volatile unsigned char *via2=(unsigned char *)VIABASE2;
-volatile unsigned char *psc=(unsigned char *)PSCBASE;
-
-volatile long *via_memory_bogon=(long *)&via_memory_bogon;
-
-unsigned char via1_clock, via1_datab;
-
-static int rbv=0;
-static int oss=0;
-
-extern void adb_interrupt(int slot, void *via, struct pt_regs *regs);
-
-/*
- * hardware reset vector
- */
-static void (*rom_reset)(void);
-
-/*
- * Timer defs.
- */
-#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_configure_base(void)
-{
-
- switch(macintosh_config->via_type)
- {
- /*
- * CI, SI, VX, LC
- */
- case MAC_VIA_IIci:
- via1=(void *)0x50F00000;
- via2=(void *)0x50F26000;
- rbv=1;
- if (macintosh_config->ident == MAC_MODEL_IIFX) {
- via2=(void *)0x50F1A000;
- oss=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:
- }
-}
-
-
-void via_init_clock(void (*func)(int, void *, struct pt_regs *))
-{
- unsigned char c;
-
- 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 if (oss==0)
- {
- /*
- * 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);
-
- /*
- * SE/30: disable video int.
- * XXX: testing for SE/30 VBL
- */
-
- if (macintosh_config->ident == MAC_MODEL_SE30) {
- c = via_read(via1, vBufB);
- via_write(via1, vBufB, c|(0x40));
- c = via_read(via1, vDirB);
- via_write(via1, vDirB, c|(0x40));
- }
-
-#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
-
-}
-
-/*
- * TBI: get time offset between scheduling timer ticks
- */
-#define TICK_SIZE 10000
-
-/* This is always executed with interrupts disabled. */
-
-unsigned long mac_gettimeoffset (void)
-{
- unsigned long ticks, offset = 0;
-
- /* read VIA1 timer 2 current value */
- ticks = via_read(via1, vT1CL) + (via_read(via1, vT1CH)<<8);
- /* The probability of underflow is less than 2% */
- if (ticks > MAC_CLOCK_TICK - MAC_CLOCK_TICK / 50)
- /* Check for pending timer interrupt in VIA1 IFR */
- if (via_read(via1, vIFR) & 0x40)
- offset = TICK_SIZE;
-
- ticks = MAC_CLOCK_TICK - ticks;
- ticks = ticks * 10000L / MAC_CLOCK_TICK;
-
- return ticks + offset;
-}
-
-/*
- * PSC (AV Macs; level 3-6): initialize interrupt enable registers
- */
-
-void psc_init(void)
-{
- via_write(psc, pIER3, 0x01);
- via_write(psc, pIER4, 0x09);
- via_write(psc, pIER4, 0x86);
- via_write(psc, pIER5, 0x03);
- via_write(psc, pIER6, 0x07);
-}
-
-/*
- * The power switch - yes it's software!
- */
-
-void mac_poweroff(void)
-{
-
- /*
- * MAC_ADB_IISI may need to be moved up here if it doesn't actually
- * work using the ADB packet method. --David Kilzer
- */
-
- if (macintosh_config->adb_type == MAC_ADB_II)
- {
- 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);
- /* Otherwise it prints "It is now.." then shuts off */
- mdelay(1000);
- }
-
- /* We should never make it this far... */
- printk ("It is now safe to switch off your machine.\n");
-
- /* XXX - delay do we need to spin here ? */
- while(1); /* Just in case .. */
- }
-
- /*
- * Initially discovered this technique in the Mach kernel of MkLinux in
- * osfmk/src/mach_kernel/ppc/POWERMAC/cuda_power.c. Found equivalent LinuxPPC
- * code in arch/ppc/kernel/setup.c, which also has a PMU technique for PowerBooks!
- * --David Kilzer
- */
-
- else if (macintosh_config->adb_type == MAC_ADB_IISI
- || macintosh_config->adb_type == MAC_ADB_CUDA)
- {
- struct adb_request req;
-
- /*
- * Print our "safe" message before we send the request
- * just in case the request never returns.
- */
-
- printk ("It is now safe to switch off your machine.\n");
-
- adb_request (&req, NULL, 2, CUDA_PACKET, CUDA_POWERDOWN);
-
- printk ("ADB powerdown request sent.\n");
- for (;;)
- {
- adb_poll();
- }
- }
-}
-
-/*
- * Not all Macs support software power down; for the rest, just
- * try the ROM reset vector ...
- */
-void mac_reset(void)
-{
- /*
- * MAC_ADB_IISI may need to be moved up here if it doesn't actually
- * work using the ADB packet method. --David Kilzer
- */
-
- if (macintosh_config->adb_type == MAC_ADB_II)
- {
- unsigned long flags;
- unsigned long *reset_hook;
-
- /* need ROMBASE in booter */
- /* indeed, plus need to MAP THE ROM !! */
-
- if (mac_bi_data.rombase == 0)
- mac_bi_data.rombase = 0x40800000;
-
- /* works on some */
- rom_reset = (void *) (mac_bi_data.rombase + 0xa);
-
-#if 0
- /* testing, doesn't work on SE/30 either */
- reset_hook = (unsigned long *) (mac_bi_data.rombase + 0x4);
- printk("ROM reset hook: %p\n", *reset_hook);
- rom_reset = *reset_hook;
-#endif
- if (macintosh_config->ident == MAC_MODEL_SE30) {
- /*
- * MSch: Machines known to crash on ROM reset ...
- */
- printk("System halted.\n");
- while(1);
- } else {
- save_flags(flags);
- cli();
-
- rom_reset();
-
- restore_flags(flags);
- }
-
- /* We never make it this far... it usually panics above. */
- printk ("Restart failed. Please restart manually.\n");
-
- /* XXX - delay do we need to spin here ? */
- while(1); /* Just in case .. */
- }
-
- /*
- * Initially discovered this technique in the Mach kernel of MkLinux in
- * osfmk/src/mach_kernel/ppc/POWERMAC/cuda_power.c. Found equivalent LinuxPPC
- * code in arch/ppc/kernel/setup.c, which also has a PMU technique!
- * --David Kilzer
- *
- * I suspect the MAC_ADB_CUDA code might work with other ADB types of machines
- * but have no way to test this myself. --DDK
- */
-
- else if (macintosh_config->adb_type == MAC_ADB_IISI
- || macintosh_config->adb_type == MAC_ADB_CUDA)
- {
- struct adb_request req;
-
- adb_request (&req, NULL, 2, CUDA_PACKET, CUDA_RESET_SYSTEM);
-
- printk ("Restart failed. Please restart manually.\n");
- for (;;)
- {
- adb_poll();
- }
- }
-}
-
-/*
- * 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);
-}
-
-void nubus_init_via(void)
-{
- if (rbv) {
- if (oss==0) {
- 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("nubus_init_via: via1 acr=%X datab=%X pcr=%X\n",
- (int)via_read(via1, vACR), (int)via_read(via1, vBufB),
- (int)via_read(via1, vPCR));
-
- if (rbv==0)
- printk("nubus_init_via: via2 acr=%X datab=%X pcr=%X\n",
- (int)via_read(via2, vACR), (int)via_read(via2, vBufB),
- (int)via_read(via2, vPCR));
-}
diff --git a/arch/m68k/mac/via6522.h b/arch/m68k/mac/via6522.h
deleted file mode 100644
index 91ba1d58e..000000000
--- a/arch/m68k/mac/via6522.h
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * 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
- */
-
-#ifndef _ASM_VIA6522_H_
-#define _ASM_VIA6522_H_
-
-#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_vMode32 0x08 /* 24/32bit switch - doubles as cache flush */
-#define VIA2B_vPower 0x04 /* Off switch */
-#define VIA2B_vBusLk 0x02 /* Nubus in use ?? */
-#define VIA2B_vCDis 0x01 /* Cache disable */
-
-/*
- * The 6522 via is a 2MHz part, and needs a delay. MacOS seems to
- * execute MOV (Ax),(Ax) for this... Oh and we can't use udelay
- * here... see we need the via to calibrate the udelay loop ...
- */
-
-extern volatile long *via_memory_bogon;
-
-extern __inline__ void via_write(volatile unsigned char *via,int reg, int v)
-{
- *via_memory_bogon;
- *via_memory_bogon;
- *via_memory_bogon;
- via[reg]=v;
-}
-
-extern __inline__ int via_read(volatile unsigned char *via,int reg)
-{
- *via_memory_bogon;
- *via_memory_bogon;
- *via_memory_bogon;
- 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);
-
-#endif /* _ASM_VIA6522_H_ */