diff options
Diffstat (limited to 'arch/m68k/mac')
-rw-r--r-- | arch/m68k/mac/Makefile | 6 | ||||
-rw-r--r-- | arch/m68k/mac/adb-bus.c | 9 | ||||
-rw-r--r-- | arch/m68k/mac/bootparse.c | 1 | ||||
-rw-r--r-- | arch/m68k/mac/config.c | 596 | ||||
-rw-r--r-- | arch/m68k/mac/debug.c | 16 | ||||
-rw-r--r-- | arch/m68k/mac/iop.c | 725 | ||||
-rw-r--r-- | arch/m68k/mac/mac_ksyms.c | 7 | ||||
-rw-r--r-- | arch/m68k/mac/mac_penguin.S | 75 | ||||
-rw-r--r-- | arch/m68k/mac/macboing.c | 32 | ||||
-rw-r--r-- | arch/m68k/mac/macints.c | 1851 | ||||
-rw-r--r-- | arch/m68k/mac/mackeyb.c | 2 | ||||
-rw-r--r-- | arch/m68k/mac/oss.c | 314 | ||||
-rw-r--r-- | arch/m68k/mac/psc.c | 203 | ||||
-rw-r--r-- | arch/m68k/mac/via.c | 774 | ||||
-rw-r--r-- | arch/m68k/mac/via6522.c | 419 | ||||
-rw-r--r-- | arch/m68k/mac/via6522.h | 131 |
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_ */ |