Resent-Date: Thu, 31 Dec 1998 00:33:46 +0100 (MET)
Sender: schmitz@lbl.gov
Date: Wed, 30 Dec 1998 15:33:37 -0800
From: Michael Schmitz <MSchmitz@lbl.gov>
Organization: Tinoco Lab, UC Berkekely / Lawrence Berkeley Laboratory
To: linux-m68k@lists.linux-m68k.org
CC: linux-mac68k@baltimore.wwaves.com, ddkilzer@earthlink.net
Subject: Mac68k patch for 2.1.131
Resent-From: linux-m68k@phil.uni-sb.de

This is a multi-part message in MIME format.
--------------4512410F37455D20F52AFE7B
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Hi,

it's getting smaller with each time, but there's still some Mac stuff
missing in Jes' 
2.1.131 (I know, I'm lame to post a 2.1.131 patch while 2.2 is out but
what the heck :-P). 
I take it as the ideal opportunity to sync my changes with Dave Kilzer
before he takes
over the Mac operations again (have fun with 2.2, Dave).

In particular:

 - head.S, the Mac version again (and I'm not taking "there's Roman's
experimental
   patch" for an answer; it didn't even compile). It's mainly for the
benefit of Mac
   hackers, and for those of the m68k crowd who want to test this
version on other
   machines. It works on my Falcon, but broke on Jes' Amiga. 

 - arch/m68k/mac/config.c: Changes to the Mac model config table: Color
Classic ADB is 
   CUDA, Centris 610/650 have Sonic ethernet.

 - arch/m68k/mac/debug.c: avoid undefined *console_wait_key if building
without serial
   console support.

 - arch/m68k/mac/macboing.c: Juergen Mellinger's patches for Quadra
sound chips. Needs 
   someone to write a nice algorithm to interpolate a 800 point sine
wave instead of 
   the triangle function.

 - arch/m68k/mac/macints.c: cleanup Nubus interrupt handling and add IDE
IRQ pending
   check to run IDE interrupts just like other Nubus interrupts in the
inner loop. 
   Fix mis-counting of spurious interrupts, fix Nubus interrupt logging
in /proc/
   and disable Nubus interrupt until the first handler is registered.

 - arch/m68k/config.in: comment out MACE ethernet option (driver not
included).

 - drivers/block/macide.c: implement Mac IDE interrupt check function
for Nubus code
   (should probably be registered in the Mac IDE driver struct?). Geert:
If that 
   solution is a major no-no, I'll change the interrupt handler for
Quadra IDE so
   can always be called and will only call ide_intr if there's a pending
IRQ. 

 - drivers/net/macsonic.c: Mac specific Sonic driver

 - drivers/net/jazzsonic.c: Mips specific Sonic driver

 - drivers/net/sonic.[ch]: core code included by the above. 

 - drivers/net/Makefile, drivers/net/Space.c: include macsonic and
jazzsonic.

   The Sonic driver is basically functional on Mac, so I see no reason
not to
   include it. The split into Jazz and Mac and generic parts was Alan's 
   work, I just got the Mac part to work.

Left out, pending: 

5380 SCSI patches - the current status is most probably broken when
using 
disconnects and multiple disks, but I'm leaving it that way until
someone bothers 
to tell me what exactly is OK to do about the race conditions in the
driver without 
stepping on the Intel people's toes. BTW, I'm still waiting for a reply
from Lenoard 
Zubkoff. 
5380 pseudo DMA has been started to evolve but I haven't seen any
patches yet.

Mac Quadra color mapping code from Juergen Mellinger (no time to
separate that code
from the other macfb.c changes, sorry).

Machine specfic reset, halt and poweroff code: needs more work on
non-CUDA
Macs (map in ROM and pass ROM base address from booter), Dave has the
original
code.

The mystical Powerbook ADB: wishlist item, nice to have to complete the
Mac support, 
no time for it. Same goes for other nifty ADB features. 

FPU emulator - basics are working in 2.1, badly broken in 2.0, waitng
for David 
Huggins-Daines to add one missing addressing mode and it should work for
most 
things in 2.1. Not quite there yet, but definitely coming soon.
Credits for the FOU emulator are due Roman Zippel (for the gory work of
the trap
handling, instruction decoding and addressing stuff) and David
Huggins-Daines 
(for addimg some more gory stuff, filling in the basic math and bringing
it to
life on a LC040).

(For the very adventurous: FPE patches are on the Mac FTP site. I'd be
glad if 
someone familiar with the entry.S and signal code could carefully check
the 2.0 
patch; I've done something very silly there so it works fine when
testing it with 
nonstandard FPU IDs on my Falcon, but crashes horribly on a 030 without
FPU).

I'll keep helping with the FPU support, 5380 SCSI unless someone else
volunteers 
to push that one (and some of the pending items, but that'll be merged
via Dave 
again in future).

	Michael
--------------4512410F37455D20F52AFE7B
Content-Type: application/octet-stream; name="mac-2.1.131-981229"
Content-Transfer-Encoding: x-uuencode
Content-Disposition: attachment; filename="mac-2.1.131-981229"

--- linux-2.1.131/arch/m68k/kernel/head.S.org	Wed Dec 30 10:08:59 1998
+++ linux-2.1.131/arch/m68k/kernel/head.S	Wed Dec 30 10:09:06 1998
@@ -7,9 +7,11 @@
 **
 ** 68040 fixes by Michael Rausch
 ** 68060 fixes by Roman Hodek
+** MMU cleanup by Randy Thelen
 **
 ** Atari support by Andreas Schwab, using ideas of Robert de Vries
 ** and Bjoern Brauel
+** VME Support by Richard Hirst
 **
 ** 94/11/14 Andreas Schwab: put kernel at PAGESIZE
 ** 94/11/18 Andreas Schwab: remove identity mapping of STRAM for Atari
@@ -18,13 +20,15 @@
 ** 96/04/26 Guenther Kelleter: fixed identity mapping for Falcon with
 ** 			      Magnum- and FX-alternate ram
 ** 98/04/25 Phil Blundell: added HP300 support
+** 1998/08/30 David Kilzer: Added support for fbcon_font_desc structures
+**            for linux-2.1.115
 **
 ** This file is subject to the terms and conditions of the GNU General Public
 ** License. See the file README.legal in the main directory of this archive
 ** for more details.
 **
 */
-
+	
 /*
  * Linux startup code.
  *
@@ -34,37 +38,225 @@
  * Put us in supervisor state.
  *
  * The kernel setup code takes the following steps:
- *   Raise interrupt level
- *   Set up initial kernel memory mapping.
- *	This sets up a mapping of the 4M of memory the kernel
- *	is located in.	It also does a mapping of any initial
- *	machine specific areas.
- * Note that the kernel is located at virtual address 0x1000 == _start
- *   Enable cache memories
- *   Jump to kernel startup
- *
- * Register d6 contains the CPU flags and d4 the machine type
- * from the boot_info information for most of this file.
- * The upper word of d6 contains a bit for '040 or '060, since these two
- * are quite similar for initial mm setup. Another bit in d6 allows
- * distinction of the '060. The lower word of d6 contains the cache mode
- * that should be applied to pages containing descriptors. This mode is
- * non-cached/non-serialized for the '040 and cacheable/write-through for
- * the '060.
- *
- * General register usage:
- *   a6 - start of unused memory
- *	  new pages can be allocated from here
- *   a5 - mmu root table
- *   a4 - mmu pointer table
- *   a3 - mmu page tables
- *   a2 - points to the page table entry for a6
- *	  cache status can be changed (used for '0[46]0)
- *	  you must increase a2 if alloc a new page
- *   d7 - used for debug output and some macros
- *   d6 - cpu type and cache mode
- *   d5 - physical start address of kernel
- *   d4 - machine type
+ * .  Raise interrupt level
+ * .  Set up initial kernel memory mapping.
+ *    .  This sets up a mapping of the 4M of memory the kernel is located in.
+ *    .  It also does a mapping of any initial machine specific areas.
+ * .  Enable the MMU
+ * .  Enable cache memories
+ * .  Jump to kernel startup
+ *
+ * Much of the file restructuring was to accomplish:
+ * 1) Reduce register dependency through-out the file.
+ * 2) Increase use of subroutines to perform functions
+ * 3) Increase readability of the code
+ *
+ * Of course, readability is a subjective issue, so it will never be
+ * argued that that goal was accomplished.  It was merely a goal.
+ * A key way to help make code more readable is to give good 
+ * documentation.  So, the first thing you will find is exaustive
+ * write-ups on the structure of the file, and the features of the
+ * functional subroutines.
+ *
+ * General Structure:
+ * ------------------
+ *	Without a doubt the single largest chunk of head.S is spent
+ * mapping the kernel and I/O physical space into the logical range
+ * for the kernel.  
+ *	There are new subroutines and data structures to make MMU
+ * support cleaner and easier to understand.
+ * 	First, you will find a routine call "mmu_map" which maps
+ * a logical to a physical region for some length given a cache
+ * type on behalf of the caller.  This routine makes writing the
+ * actual per-machine specific code very simple.
+ *	A central part of the code, but not a subroutine in itself,
+ * is the mmu_init code which is broken down into mapping the kernel
+ * (the same for all machines) and mapping machine-specific I/O
+ * regions.
+ *	Also, there will be a description of engaging the MMU and
+ * caches.
+ *	You will notice that there is a chunk of code which
+ * can emit the entire MMU mapping of the machine.  This is present
+ * only in debug modes and can be very helpful.
+ *	Further, there is a new console driver in head.S that is
+ * also only engaged in debug mode.  Currently, it's only supported
+ * on the Macintosh class of machines.  However, it is hoped that
+ * others will plug-in support for specific machines.
+ * 
+ * ######################################################################
+ * 
+ * mmu_map
+ * -------
+ *	mmu_map was written for two key reasons.  First, it was clear
+ * that it was very difficult to read the previous code for mapping
+ * regions of memory.  Second, the Macintosh required such extensive
+ * memory allocations that it didn't make sense to propogate the 
+ * existing code any further.
+ *	mmu_map requires some parameters:
+ * 
+ *	mmu_map (logical, physical, length, cache_type)
+ * 
+ *	While this essentially describes the function in the abstract, you'll
+ * find more indepth description of other parameters at the implementation site.
+ * 
+ * mmu_get_page_table
+ * ------------------
+ * mmu_get_pointer_table
+ * ---------------------
+ *	These routines are used by mmu_map to get fresh tables.  They
+ * will allocate a new page of memory and consume page tables from that page
+ * until the page has been exausted.  Unfortunately, the kernel code uses
+ * a wacky and not very efficient mechanism for re-using pages of memory
+ * allocated for page tables.  Therefore, while this code does set the kpt
+ * global to a correct value upon initial usage, it doesn't help.
+ * 
+ * mmu_clear_root_table
+ * --------------------
+ * mmu_clear_pointer_table
+ * -----------------------
+ * mmu_clear_page_table
+ * --------------------
+ *	Given a pointer to a table, these routines will clear it.
+ * Sometimes writing well factored code can be a source of pride.
+ * 
+ * ######################################################################
+ * 
+ * mmu_init
+ * --------
+ *	Here is where the MMU is initialized for the various platforms.
+ * First, the kernel is mapped for all platforms at the address computed
+ * as the current address (which is known to be physical) and mapped down
+ * to logical 0x01000.  Then there is logic on a per-machine basis.
+ * 
+ * ######################################################################
+ * 
+ * mmu_engage
+ * ----------
+ *	The MMU engagement code is quite extensive and there is ample
+ * description of the algorithm in all it's gory detail at the site of the
+ * evil deed.  However, allow me to state that magic takes place there.
+ * 
+ * ######################################################################
+ * 
+ * mmu_print
+ * ---------
+ *	This algorithm will print out the page tables of the system as
+ * appropriate for an 030 or an 040.  This is useful for debugging purposes
+ * and as such is enclosed in #ifdef MMU_PRINT/#endif clauses.
+ * 
+ * ######################################################################
+ * 
+ * Lconsole_init
+ * -------------
+ *	The console is also able to be turned off.  The console in head.S
+ * is specifically for debugging and can be very useful.  It is surrounded by
+ * #ifdef CONSOLE/#endif clauses so it doesn't have to ship in known-good
+ * kernels.  It's basic algorithm is to determine the size of the screen
+ * (in height/width and bit depth) and then use that information for
+ * displaying an 8x8 font or an 8x16 (widthxheight).  I prefer the 8x8 for
+ * debugging so I can see more good data.  But it was trivial to add support
+ * for both fonts, so I included it.
+ *	Also, the algorithm for plotting pixels is abstracted so that in
+ * theory other platforms could add support for different kinds of frame
+ * buffers.  This could be very useful.
+ * 
+ * Lconsole_put_penguin
+ * --------------------
+ *	An important part of any Linux bring up is the penguin and there's
+ * nothing like getting the Penguin on the screen!  This algorithm will work
+ * on any machine for which there is a console_plot_pixel.
+ * 
+ * console_scroll
+ * --------------
+ *	My hope is that the scroll algorithm does the right thing on the
+ * various platforms, but it wouldn't be hard to add the test conditions
+ * and new code if it doesn't.
+ * 
+ * console_putc
+ * -------------
+ * 
+ * ######################################################################
+ * 
+ *	The only register that is passed through out the system are:
+ * .  A7 -- Stack Pointer (duh)
+ * .  A6 -- Top of Kernel,  available pages are taken from here
+ * .  A5 -- Ptr to Root Table
+ * .  D5 -- Ptr to __start (physical)
+ *	Many other registers are used as passed parameters into
+ * functions or used within functions.
+ *
+ *	Reducing the register usage from a dozen to a few greatly simplified
+ * head.S.
+ *
+ * ######################################################################
+ * 
+ * options
+ * -------
+ *	There are many options availble in a build of this file.  I've
+ * taken the time to describe them here to save you the time of searching
+ * for them and trying to understand what they mean.
+ * 
+ * CONFIG_xxx:	These are the obvious machine configuration defines created
+ * during configuration.  These are defined in include/linux/autoconf.h.
+ *
+ * CONSOLE:	There is support for head.S console in this file.  This
+ * console can talk to a Mac frame buffer, but could easily be extrapolated
+ * to extend it to support other platforms.
+ * 
+ * TEST_MMU:	This is a test harness for running on any given machine but
+ * getting an MMU dump for another class of machine.  The classes of machines
+ * that can be tested are any of the makes (Atari, Amiga, Mac, VME, etc.)
+ * and any of the models (030, 040, 060, etc.).
+ *
+ *	NOTE:	TEST_MMU is NOT permanent!  It is scheduled to be removed
+ *		When head.S boots on Atari, Amiga, Macintosh, and VME
+ *		machines.  At that point the underlying logic will be
+ *		believed to be solid enough to be trusted, and TEST_MMU
+ *		can be dropped.  Do note that that will clean up the
+ *		head.S code significantly as large blocks of #if/#else
+ *		clauses can be removed.
+ * 
+ * MMU_NOCACHE_KERNEL:	On the Macintosh platform there was an inquiry into
+ * determing why devices don't appear to work.  A test case was to remove
+ * the cacheability of the kernel bits.
+ * 
+ * MMU_PRINT:	There is a routine built into head.S that can display the
+ * MMU data structures.  It outputs its result through the Lserial_putc
+ * interface.  So where ever that winds up driving data, that's where the
+ * mmu struct will appear.  On the Macintosh that's typically the console.
+ * 
+ * SERIAL_DEBUG:	There are a series of putc() macro statements
+ * scattered through out the code to give progress of status to the
+ * person sitting at the console.  This constant determines whether those
+ * are used.
+ * 
+ * DEBUG:	This is the standard DEBUG flag that can be set for building
+ *		the kernel.  It has the effect adding additional tests into
+ *		the code.
+ * 
+ * MMU_PRINT_PAGE_USAGE:
+ *		Print the number of pages used by the MMU tables.
+ * 
+ * FONT_6x11:
+ * FONT_8x8:
+ * FONT_8x16:
+ *		In theory these could be determined at run time or handed
+ *		over by the booter.  But, let's be real, it's a fine hard
+ *		coded value.  (But, you will notice the code is run-time
+ *		flexible!)  A pointer to the font's struct fbcon_font_desc
+ *		is kept locally in Lconsole_font.  It is used to determine
+ *		font size information dynamically.
+ * 
+ * Atari constants:
+ * USE_PRINTER:	Use the printer port for serial debug.
+ * USE_SCC_B:	Use the SCC port A (Serial2) for serial debug.
+ * USE_SCC_A:	Use the SCC port B (Modem2) for serial debug.
+ * USE_MFP:	Use the ST-MFP port (Modem1) for serial debug. 
+ * 
+ * Macintosh constants:
+ * MAC_SERIAL_DEBUG:	Turns on serial debug output for the Macintosh.
+ * MAC_USE_SCC_A:	Use the SCC port A (modem) for serial debug.
+ * MAC_USE_SCC_B:	Use the SCC port B (printer) for serial debug (default).
  */
 
 #include <linux/config.h>
@@ -72,11 +264,67 @@
 #include <asm/bootinfo.h>
 #include <asm/setup.h>
 #include <asm/pgtable.h>
+#if defined(CONFIG_MAC)
+#include <video/font.h>		/* offsets for struct fbcon_font_desc */
+#endif
+
+#if defined(CONFIG_MAC)
+
+/*
+ * Macintosh console support
+ */
+#define CONSOLE
+
+/*
+ * Macintosh serial debug support; outputs boot info to the printer 
+ *   and/or modem serial ports
+ */
+#undef MAC_SERIAL_DEBUG
+
+/*
+ * Macintosh serial debug port selection; define one or both; 
+ *   requires MAC_SERIAL_DEBUG to be defined
+ */
+#undef  MAC_USE_SCC_A		/* Macintosh modem serial port */
+#define MAC_USE_SCC_B		/* Macintosh printer serial port */
 
-.globl SYMBOL_NAME(kernel_pg_dir), SYMBOL_NAME(kpt)
+#endif	/* CONFIG_MAC */
+
+#undef MMU_PRINT
+#undef MMU_NOCACHE_KERNEL
+#define SERIAL_DEBUG
+#undef DEBUG
+#undef MMU_PRINT_PAGE_USAGE
+
+/*
+ * For the head.S console, there are three supported fonts, 6x11, 8x16 and 8x8.
+ * The 8x8 font is harder to read but fits more on the screen.
+ */
+#define FONT_8x8 	/* default */
+/* #define FONT_8x16	/* 2nd choice */
+/* #define FONT_6x11	/* 3rd choice */
+	
+.globl SYMBOL_NAME(kernel_pg_dir)
+.globl SYMBOL_NAME(kpt)
 .globl SYMBOL_NAME(availmem)
 .globl SYMBOL_NAME(m68k_pgtable_cachemode)
-.globl SYMBOL_NAME(kernel_pmd_table), SYMBOL_NAME(swapper_pg_dir)
+.globl SYMBOL_NAME(kernel_pmd_table)
+.globl SYMBOL_NAME(swapper_pg_dir)
+
+#if defined(CONFIG_ATARI)
+.globl SYMBOL_NAME(atari_mch_type)
+#endif
+
+#if defined(CONFIG_MAC)
+.globl SYMBOL_NAME(mac_booter_data)
+.globl SYMBOL_NAME(compat_bi)
+.globl SYMBOL_NAME(mac_videobase)
+.globl SYMBOL_NAME(mac_videodepth)
+.globl SYMBOL_NAME(mac_rowbytes)
+#ifdef MAC_SERIAL_DEBUG
+.globl SYMBOL_NAME(mac_sccbase)
+#endif	/* MAC_SERIAL_DEBUG */
+#endif
 
 #if defined(CONFIG_MVME16x)
 .globl SYMBOL_NAME(mvme_bdid_ptr)
@@ -98,6 +346,10 @@
 D6F_040  = 1<<D6B_0460
 D6F_060  = (1<<D6B_0460)+(1<<D6B_060)
 
+CPUTYPE_040	= 1	/* indicates an 040 */
+CPUTYPE_060	= 2	/* indicates an 060 */
+CPUTYPE_0460	= 3	/* if either above are set, this is set */
+
 /* Translation control register */
 TC_ENABLE = 0x8000
 TC_PAGE8K = 0x4000
@@ -144,6 +396,7 @@
 
 /* Miscellaneous definitions */
 PAGESIZE	= 4096
+PAGESHIFT	= 12
 
 ROOT_TABLE_SIZE	= 128
 PTR_TABLE_SIZE	= 128
@@ -155,20 +408,99 @@
 TABLENR_4MB	= 16	/* # of page tables needed to page 4 MB */
 TABLENR_16MB	= 64	/* same for 16 MB */
 
-#define putc(ch) moveq &ch,%d7; jbsr Lserial_putc
-#define putr() putc(13); putc(10)
-#define putn(nr) movel nr,%d7; jbsr Lserial_putnum
-
-#define is_not_amiga(lab) moveq &MACH_AMIGA,%d7; cmpl %d4,%d7; jne lab
-#define is_not_atari(lab) moveq &MACH_ATARI,%d7; cmpl %d4,%d7; jne lab
-#define is_not_mvme16x(lab) moveq &MACH_MVME16x,%d7; cmpl %d4,%d7; jne lab
-#define is_not_bvme6000(lab) moveq &MACH_BVME6000,%d7; cmpl %d4,%d7; jne lab
-#define is_not_hp300(lab) moveq &MACH_HP300,%d7	;  cmpl %d4,%d7; jne lab
-
-#define is_040_or_060(lab) btst &D6B_0460,%d6; jne lab
-#define is_not_040_or_060(lab) btst &D6B_0460,%d6; jeq lab
-#define is_060(lab) btst &D6B_060,%d6; jne lab
-#define is_not_060(lab) btst &D6B_060,%d6; jeq lab
+#if !defined(CONSOLE) && !defined(DEBUG) && defined(SERIAL_DEBUG)
+#  define putc_trace(c)			  \
+		movel	%d7,%sp@-	; \
+		moveb	&c,%d7		; \
+		jbsr	Lserial_putc	; \
+		movel	%sp@+,%d7	;
+#  define putc(c)
+#  define puts(x)
+#  define putr()			  \
+		movel	%d7,%sp@-	; \
+		moveb	#13,%d7		; \
+		jbsr	Lserial_putc	; \
+		moveb	#10,%d7		; \
+		jbsr	Lserial_putc	; \
+		movel	%sp@+,%d7	;
+#  define putn(nr)
+#elif defined(DEBUG) || defined(CONSOLE)
+#  define putc_trace(c)			  \
+		movel	%d7,%sp@-	; \
+		moveb	&c,%d7		; \
+		jbsr	Lserial_putc	; \
+		movel	%sp@+,%d7	;
+#  define putc(c)	putc_trace(c)
+#  define puts(x)			  \
+		movel	%a0,%sp@-	; \
+		lea	%pc@(897f),%a0	; \
+		jbsr	Lserial_puts	; \
+		movel	%sp@+,%a0	; \
+		jbra	898f		; \
+	897:	.string	x		; \
+		.byte	0		; \
+		.even			; \
+	898:
+#  define putr()			  \
+		movel	%d7,%sp@-	; \
+		moveb	#13,%d7		; \
+		jbsr	Lserial_putc	; \
+		moveb	#10,%d7		; \
+		jbsr	Lserial_putc	; \
+		movel	%sp@+,%d7	;
+#  define putn(nr)			  \
+		movel	%d7,%sp@-	; \
+		movel	nr,%d7		; \
+		jbsr	Lserial_putnum	; \
+		movel	%sp@+,%d7	;
+#else /* ! DEBUG && ! SERIAL_DEBUG */
+#  define putc_trace(c)
+#  define putc(c)
+#  define puts(x)
+#  define putr()
+#  define putn(nr)	
+#endif
+
+/*
+ * mmu_map() register usage
+ *
+ * Here a symbolic names for the mmu_map() parameters.
+ */
+#define MAP_PHYS	%a1
+#define MAP_LOG		%a0
+#define MAP_CACHE	%d1
+#define MAP_LENGTH	%d0
+
+#define MMU_MAP(log,phys,leng,cache)	movel	log,MAP_LOG; \
+					movel	phys,MAP_PHYS; \
+					movel	leng,MAP_LENGTH; \
+					movel	cache,MAP_CACHE; \
+					jbsr	mmu_map
+	
+#define MMU_MAP_EQ(addr,leng,cache)	movel	addr,MAP_LOG; \
+					movel	MAP_LOG,MAP_PHYS; \
+					movel	leng,MAP_LENGTH; \
+					movel	cache,MAP_CACHE; \
+					jbsr	mmu_map
+	
+#define MMU_MAP_TT(addr,leng,cache)	movel	addr,MAP_LOG; \
+					movel	MAP_LOG,MAP_PHYS; \
+					movel	leng,MAP_LENGTH; \
+					movel	cache,MAP_CACHE; \
+					jbsr	mmu_map_tt
+	
+#define is_not_amiga(lab) cmpl &MACH_AMIGA,%pc@(m68k_machtype); jne lab
+#define is_not_atari(lab) cmpl &MACH_ATARI,%pc@(m68k_machtype); jne lab
+#define is_not_mac(lab) cmpl &MACH_MAC,%pc@(m68k_machtype); jne lab
+#define is_not_mvme16x(lab) cmpl &MACH_MVME16x,%pc@(m68k_machtype); jne lab
+#define is_not_bvme6000(lab) cmpl &MACH_BVME6000,%pc@(m68k_machtype); jne lab
+#define is_not_hp300(lab) cmpl &MACH_HP300,%pc@(m68k_machtype); jne lab
+	
+#define is_040_or_060(lab)	btst &CPUTYPE_0460,%pc@(Lcputype+3); jne lab
+#define is_not_040_or_060(lab)	btst &CPUTYPE_0460,%pc@(Lcputype+3); jeq lab
+#define is_040(lab)		btst &CPUTYPE_040,%pc@(Lcputype+3); jne lab
+#define is_060(lab)		btst &CPUTYPE_060,%pc@(Lcputype+3); jne lab
+#define is_not_060(lab)		btst &CPUTYPE_060,%pc@(Lcputype+3); jeq lab
 
 /* On the HP300 we use the on-board LEDs for debug output before
    the console is running.  Writing a 1 bit turns the corresponding LED
@@ -192,6 +524,7 @@
 	.long	MACH_ATARI, ATARI_BOOTI_VERSION
 	.long	MACH_MVME16x, MVME16x_BOOTI_VERSION
 	.long	MACH_BVME6000, BVME6000_BOOTI_VERSION
+	.long	MACH_MAC, MAC_BOOTI_VERSION
 	.long	0
 1:	jra	SYMBOL_NAME(_start)
 
@@ -207,17 +540,17 @@
 /*
  * Setup initial stack pointer
  */
-	lea	%pc@(SYMBOL_NAME(_stext):w),%sp
-
+	lea	%pc@(SYMBOL_NAME(_stext)),%sp
+	
 /*
  * Record the CPU and machine type.
  */
 
 	movew	#BI_MACHTYPE,%d0
 	jbsr	Lget_bi_record
-	movel	%a0@,%d4
+	movel	%a0@,%d0
 	lea	%pc@(SYMBOL_NAME(m68k_machtype)),%a0
-	movel	%d4,%a0@
+	movel	%d0,%a0@
 	movew	#BI_FPUTYPE,%d0
 	jbsr	Lget_bi_record
 	movel	%a0@,%d0
@@ -234,39 +567,165 @@
 	lea	%pc@(SYMBOL_NAME(m68k_cputype)),%a0
 	movel	%d0,%a0@
 
+#if defined(CONFIG_MAC)
+/*
+ * For Macintosh, we need to determine the display parameters early (at least 
+ * while debugging it).
+ */
+
+	is_not_mac(Ltest_notmac)
+
+	movew	#BI_MAC_VADDR,%d0
+	jbsr	Lget_bi_record
+	movel	%a0@,%d0
+	lea	%pc@(SYMBOL_NAME(mac_videobase)),%a0
+	movel	%d0,%a0@
+
+	movew	#BI_MAC_VDEPTH,%d0
+	jbsr	Lget_bi_record
+	movel	%a0@,%d0
+	lea	%pc@(SYMBOL_NAME(mac_videodepth)),%a0
+	movel	%d0,%a0@
+
+	movew	#BI_MAC_VDIM,%d0
+	jbsr	Lget_bi_record
+	movel	%a0@,%d0
+	lea	%pc@(SYMBOL_NAME(mac_dimensions)),%a0
+	movel	%d0,%a0@
+
+	movew	#BI_MAC_VROW,%d0
+	jbsr	Lget_bi_record
+	movel	%a0@,%d0
+	lea	%pc@(SYMBOL_NAME(mac_rowbytes)),%a0
+	movel	%d0,%a0@
+
+#ifdef MAC_SERIAL_DEBUG
+	movew	#BI_MAC_SCCBASE,%d0
+	jbsr	Lget_bi_record
+	movel	%a0@,%d0
+	lea	%pc@(SYMBOL_NAME(mac_sccbase)),%a0
+	movel	%d0,%a0@
+#endif /* MAC_SERIAL_DEBUG */
+
+#if 0
+	/*
+	 * Clear the screen
+	 */
+	lea	%pc@(SYMBOL_NAME(mac_videobase)),%a0
+	movel	%a0@,%a1
+	lea	%pc@(SYMBOL_NAME(mac_dimensions)),%a0
+	movel	%a0@,%d1
+	swap	%d1		/* #rows is high bytes */
+	andl	#0xFFFF,%d1	/* rows */
+	subl	#10,%d1
+	lea	%pc@(SYMBOL_NAME(mac_rowbytes)),%a0
+loopy2:
+	movel	%a0@,%d0
+	subql	#1,%d0
+loopx2:
+	moveb	#0x55, %a1@+
+	dbra	%d0,loopx2
+	dbra	%d1,loopy2
+#endif
+	/*
+	 * clobbered %d0,so restore it
+	 */
+	lea	%pc@(SYMBOL_NAME(m68k_cputype)),%a0
+	movel	%a0@,%d0
+
+Ltest_notmac:
+#endif /* CONFIG_MAC */
+
+
+/*
+ * There are ultimately two pieces of information we want for all kinds of
+ * processors CpuType and CacheBits.  The CPUTYPE was passed in from booter
+ * and is converted here from a booter type definition to a separate bit
+ * number which allows for the standard is_0x0 macro tests.
+ */
+	/*
+	 * Test the BootInfo cputype for 060
+	 */
+	/*
+	 * Assume it's an 020/030
+	 */
+	clrl	%d6
+	
 	btst	#CPUB_68060,%d0
 	jeq	1f
-	/* '060: d6 := BIT0460|BIT060, cache mode 0x60 (no-cache/non-ser) */
-	movel	#D6F_060+_PAGE_CACHE040W,%d6
-	jra	2f
-1:	btst	#CPUB_68040,%d0
-	jeq	1f
-	/* '040: d6 := BIT0460, cache mode 0x00 (write-through) */
-	movel	#D6F_040+_PAGE_CACHE040W,%d6
+	bset	#CPUTYPE_060,%d6
+	bset	#CPUTYPE_0460,%d6
 	jra	2f
-1:	/* '020 or '030: d6 := no CPU bit, cache mode unused */
-	moveq	#0,%d6
-
-2:	lea	%pc@(SYMBOL_NAME(m68k_pgtable_cachemode)),%a0
-	moveq	#0,%d0
-	movew	%d6,%d0
-	movel	%d0,%a0@		/* save cache mode for page tables */
+	
+1:	/*
+	 * Test the BootInfo cputype for 040
+	 */
+	btst	#CPUB_68040,%d0
+	jeq	2f
+	bset	#CPUTYPE_040,%d6
+	bset	#CPUTYPE_0460,%d6
+	
+2:
+	/*
+	 * Record the cpu type
+	 */
+	lea	%pc@(Lcputype),%a0
+	movel	%d6,%a0@
+	
+	/*
+	 * NOTE:
+	 *
+	 * Now the macros are valid:
+	 *	is_040_or_060
+	 *	is_not_040_or_060
+	 *	is_040
+	 *	is_060
+	 *	is_not_060
+	 */
+	
+	/*
+	 * Determine the cache mode for pages holding MMU tables
+	 */
+	is_not_040_or_060(Lcachetype020)
+	
+	/*
+	 * '040 or '060
+	 * d6 := cacheable write-through 
+	 * NOTE: The 68040 manual strongly recommends non-cached for MMU tables,
+	 * but we have been using write-through since at least 2.0.29 so I
+	 * guess it is OK.
+	 */
 
+#if defined(CONFIG_060_WRITETHROUGH)
 	/*
 	 * If this is a 68060 board using drivers with cache coherency
 	 * problems, then supervisor memory accesses need to be write-through
-         * also; otherwise, we want copyback.
+	 * also; otherwise, we want copyback.
 	 */
 
-#if defined(CONFIG_060_WRITETHROUGH)
-	is_not_060(Lset_norm)
-	jra	1f
-Lset_norm:
-	move.w	#_PAGE_CACHE040,%d0
-1:
+	movel	#_PAGE_CACHE040W,%d6
+	is_060(Lset_sup)
+	move.w	#_PAGE_CACHE040,%d6
+Lset_sup:
   	lea	%pc@(SYMBOL_NAME(m68k_supervisor_cachemode)),%a0
-	movel	%d0,%a0@
-#endif
+	movel	%d6,%a0@
+#endif /* CONFIG_060_WRITETHROUGH */
+
+	movel	#_PAGE_CACHE040W,%d6
+	jbra	Lsave_cachetype
+
+Lcachetype020:
+	/*
+	 * '020 or '030
+	 * d6 := cache bits unused (after mapping the kernel!)
+	 */
+	moveql	#0,%d6
+Lsave_cachetype:
+	/*
+	 * Save cache mode for page tables
+	 */
+	lea	%pc@(SYMBOL_NAME(m68k_pgtable_cachemode)),%a0
+	movel	%d6,%a0@
 
 /*
  * raise interrupt level
@@ -302,10 +761,9 @@
 	tstl	%d0
 	jbmi	1f
 	movel	%a0@,%d3
+	lea	%pc@(SYMBOL_NAME(atari_mch_type)),%a0
+	movel	%d3,%a0@
 1:	
-	/* %d3 is not clobbered until Atari page tables are set up,
-	 * where it is used again. */
-
 	/* On the Hades, the iobase must be set up before opening the
 	 * serial port. There are no I/O regs at 0x00ffxxxx at all. */
 	moveq	#0,%d0
@@ -314,20 +772,40 @@
 	movel	#0xff000000,%d0		/* Hades I/O base addr: 0xff000000 */
 1:	lea     %pc@(Liobase),%a0
 	movel   %d0,%a0@
+	
 Lnotypetest:
 #endif
 
 /*
  * Initialize serial port
  */
+	jbsr	Lserial_init
 
-	jbsr Lserial_init
+/*
+ * Initialize console
+ */
+#ifdef CONFIG_MAC
+	is_not_mac(Lnocon)
+#ifdef CONSOLE
+	jbsr	Lconsole_init
+#ifdef CONSOLE_PENGUIN
+	jbsr	Lconsole_put_penguin
+#endif	/* CONSOLE_PENGUIN */
+	jbsr	Lconsole_put_stats
+#endif	/* CONSOLE */
+Lnocon:
+#endif	/* CONFIG_MAC */
 
 	putr()
-	putc('A')
+	putc_trace('A')
 
 /*
- * Get address at end of bootinfo and mask off at a page boundary.
+ * Get address at end of bootinfo and
+ * round up to a page boundary.
+ * Note: This hack uses two 'features' of the bi_record:
+ *  (1)  When the item searched for isn't found, a0 points
+ *       to the end of the structure;
+ *  (2)  #0 is an invalid (and never present) bi_record element.
  */
 	moveq	#0,%d0
 	jbsr	Lget_bi_record
@@ -336,246 +814,121 @@
 	andl	#-PAGESIZE,%d0
 	movel	%d0,%a6
 
-	putc('B')
-
-/*
- * Save physical start address of kernel
- */
-	lea	%pc@(SYMBOL_NAME(_stext)-PAGESIZE:w),%a0
-	movel	%a0,%d5
-
 /*
- * initialize the kernel root table.
+ * %a6 now contains the address to the 
+ * next free block beyond the kernel
  */
-	lea	%pc@(SYMBOL_NAME(kernel_pg_dir):w),%a5
-	movel	%a5,%a0
-	moveq	#ROOT_TABLE_SIZE-1,%d1
-1:	clrl	%a0@+
-	dbra	%d1,1b
-
-	/*
-	 * Initialize root table descriptor pointing to the kernel pointer
-	 * table.
-	 */
-	lea	%pc@(Lavail_pmd_table:w),%a4
-	moveq	#_PAGE_TABLE,%d0
-	addl	%a4,%d0
-	movel	%d0,%a5@
 
-	putc('C')
+	putc_trace('B')
 
 /*
- * Initialize the pointer tables referred to above.  They either point
- * to page tables in the case of the 680[46]0 or contain early
- * termination page descriptors in the case of the 68851 or 68030.
- *
- * Each pointer table entry points to a 64 entry page table.  16 of these
- * page tables are grouped to form a single 1024 entry page table which
- * fits in a single 4096 byte page.
- *
- * Some register usages:
- *    a0 -> pointer table descriptor address
- *    a1 -> pointer table descriptor
- *    d1 -> counter
- *    d2 -> pointer table descriptor increment (varies according to CPU)
+ * Save physical start address of kernel
  */
+	lea	%pc@(SYMBOL_NAME(_stext)-PAGESIZE:w),%a0
+	movel	%a0,%d5
 
-	/* clear the kernel pointer table */
-	movel	%a4,%a0
-	moveq	#PTR_TABLE_SIZE-1,%d1
-1:	clrl	%a0@+
-	dbra	%d1,1b
-
-	movel	%a4,%a0
-	moveq	#15,%d1
-
-	/*
-	 * base value of pointer table descriptor is either
-	 * the address of the first page table (680[46]0)
-	 * or the base address of physical memory (68030).
-	 */
-	is_040_or_060(1f)
-
-	/* 680[23]0 */
-	movel	%d5,%a1				/* base address */
-	addql	#_PAGE_PRESENT,%a1		/* descriptor type */
-	movel	#PAGE_TABLE_SIZE*PAGESIZE,%d2	/* increment */
-	jra	2f
-
-1:	/* 680[46]0 */
-	movel	%a6,%a3			/* base address */
-	addw	#PAGESIZE,%a6		/* allocate page for 16 page tables */
-	lea	%pc@(SYMBOL_NAME(kpt)),%a1
-	movel	%a3,%a1@		/* save address of page table */
-	movel	%a3,%a1
-	addw	#_PAGE_TABLE+_PAGE_ACCESSED,%a1	/* descriptor type */
-	movel	#PAGE_TABLE_SIZE<<2,%d2 /* increment */
-
-2:	movel	%a1,%a0@+
-	addl	%d2,%a1
-	dbra	%d1,2b
+	putc_trace('C')
 
-	putc('D')
+	leds(0x4)
 
 /*
- * If we are running on a 680[46]0, we have a kernel page table and
- * must initialize it.	Make the entries point to the first
- * 4M of physical memory (the memory we are residing in).
- * Set the cache mode bits to Cacheable, Copyback.  Set the Global bits
- * in the descriptors also.
+ *	mmu_init
+ *	
+ *	This block of code does what's necessary to map in the various kinds
+ *	of machines for execution of Linux.  First, it's clear there
+ *	has to be a root table, so that is cleared.  Then, the kernel
+ *	has to be mapped, so the kernel is mapped low.  Then, it's on
+ *	to machine specific code where specific address ranges are
+ *	mapped depending on current I/O configurations.
+ *	
+ *	Begin:
+ *		%a6 is an input to this routine.  %a6 must point to
+ *			the first available byte of memory on a virgin page.
+ *		%d5 is the start of the kernel's physical address
+ *	
+ *	End:
+ *		%a5 will point to the root table.
+ *		%a6 will (likely) have been modified during this
+ *			call.
+ *	
+ *	
+ *	
  */
-	is_not_040_or_060(Lnot040)
-
-	putc('F')
-
-	movel	%a3,%a0
-	movel	%d5,%a1
-#if defined(CONFIG_060_WRITETHROUGH)
-	addw	#_PAGE_GLOBAL040+_PAGE_PRESENT+_PAGE_ACCESSED,%a1
-	addl	m68k_supervisor_cachemode,%a1
-#else
-	addw    #_PAGE_GLOBAL040+_PAGE_CACHE040+_PAGE_PRESENT+_PAGE_ACCESSED,%a1
-#endif
-	movew	#(PAGE_TABLE_SIZE*TABLENR_4MB)-1,%d1
-	movel	#PAGESIZE,%d2
-1:	movel	%a1,%a0@+
-	addl	%d2,%a1
-	dbra	%d1,1b
-
-	/*
-	 * on the 68040, pages used to hold mmu tables should
-	 * be initialized as noncachable; the '060 allows write-through.
-	 * Do this for the root table page (which also contains
-	 * all pointer tables utilized thus far) and the
-	 * kernel page table.
-	 */
-	movel	%a5,%d0
-	subl	%d5,%d0
-	moveq	#PAGE_INDEX_SHIFT,%d2
-	lsrl	%d2,%d0
-	lea	%a3@(%d0:l:4),%a2
-	movel	%a2@,%d1
-	andw	#_CACHEMASK040,%d1
-	orw	%d6,%d1
-	movel	%d1,%a2@
-
-	movel	%a3,%d0
-	subl	%d5,%d0
-	lsrl	%d2,%d0
-	lea	%a3@(%d0:l:4),%a2
-	movel	%a2@,%d1
-	andw	#_CACHEMASK040,%d1
-	orw	%d6,%d1
-	movel	%d1,%a2@+
-	/*
-	 * %a2 points now to the page table entry for available pages at %a6,
-	 * hence caching modes for new pages can easily set unless increasing
-	 * of %a2 are forgotten.
-	 */
-Lnot040:
+mmu_init:
 
-	leds(0x4)
+	putc_trace('D')
 	
 /*
- * Do any machine specific page table initializations.
+ * initialize the kernel root table.
  */
-#ifdef CONFIG_AMIGA
-	is_not_amiga(Lnotami)
+	lea	%pc@(SYMBOL_NAME(kernel_pg_dir)),%a5
+	jbsr	mmu_clear_root_table
+	
+	putc_trace('E')
+	
+	lea	%pc@(SYMBOL_NAME(Lavail_pmd_table)),%a4
+	jbsr	mmu_clear_pointer_table
 
+	putc_trace('F')
+	
 /*
- * Setup a mapping of the first 16M of physical address space at virtual
- * address 0x80000000, using early termination page descriptors for the
- * 68030, and proper page tables for the 680[46]0.  Set this area as
- * non-cacheable.
+ * map the first 4 MB of kernel code & data
  */
 
-	putc('H')
-
-	is_040_or_060(Lspami68040)
-
-	/*
-	 * for the 68030, just setup a translation to map in the first
-	 * 32M of physical address space at virtual address 0x80000000
-         * using an early termination page descriptor.
-	 */
-
-	putc('I')
-
-	movel	#_PAGE_NOCACHE030+_PAGE_PRESENT+_PAGE_ACCESSED,%d0
-	movel	%d0,%a5@(0x40<<2)
-
-	jra	Lmapphys
-
-Lspami68040:
+#if defined(CONFIG_060_WRITETHROUGH)
+	movel	%pc@(m68k_supervisor_cachemode),%d2
+	addil	#_PAGE_GLOBAL040+_PAGE_ACCESSED,%d2
+	MMU_MAP(#0,%d5,#4*1024*1024,%d2)
+#else
+	MMU_MAP(#0,%d5,#4*1024*1024,#_PAGE_GLOBAL040+_PAGE_CACHE040+_PAGE_ACCESSED)
+#endif
 
-	/*
-	 * for the 680[46]0, use another pointer table, and allocate 4 more
-	 * page tables.  Initialize the pointer table to point to the
-	 * page tables.  Then initialize the page tables to point to
-	 * the first 16M of memory, with no caching (noncachable/serialized).
-	 */
+	/* Clear the pointer table to use, and page table to use */
+	moveq	#0,%d0
+	movel	%d0,%a4
+	movel	%d0,%a3
 
-	/* clear the amiga pointer table */
-	lea	%a4@(PTR_TABLE_SIZE<<2),%a4
-	moveq	#PTR_TABLE_SIZE-1,%d1
-1:	clrl	%a0@+
-	dbra	%d1,1b
+	putc_trace('G')
 
-	/* allocate 4 pages for 64 page tables */
-	movel	%a6,%a3
-	addw	#4*PAGESIZE,%a6
+#if defined(CONFIG_AMIGA)
 
-	/* initialize the pointer table */
-	movel	%a4,%a0
-	movel	%a3,%a1
-	addw	#_PAGE_TABLE+_PAGE_ACCESSED,%a1	/* base descriptor */
-	movel	#PAGE_TABLE_SIZE<<2,%d2 /* increment */
-	moveq	#TABLENR_16MB-1,%d1
+mmu_init_amiga:
+	
+	is_not_amiga(mmu_init_not_amiga)
+/* 
+ * mmu_init_amiga
+ */
 
-1:	movel	%a1,%a0@+
-	addl	%d2,%a1
-	dbra	%d1,1b
+	putc_trace('H')
 
-	/* ensure that the root table points to the pointer table */
-	movel	%a4,%a0
-	addw	#_PAGE_TABLE+_PAGE_ACCESSED,%a0
-	movel	%a0,%a5@(0x40<<2)
+	is_not_040_or_060(1f)
 
 	/*
-	 * initialize the page tables
-	 * descriptor bits include noncachable/serialized and global bits.
+	 * 040: Map the 16Meg range physical 0x0 upto logical 0x8000.0000
 	 */
-	movel	%a3,%a0
-	movew	#_PAGE_GLOBAL040+_PAGE_NOCACHE_S+_PAGE_PRESENT+_PAGE_ACCESSED,%a1
-	movel	#PAGESIZE,%d2
-	movew	#(PAGE_TABLE_SIZE*TABLENR_16MB)-1,%d1
-
-1:	movel	%a1,%a0@+
-	addl	%d2,%a1
-	dbra	%d1,1b
+	MMU_MAP(#0x80000000,#0,#0x01000000,#_PAGE_GLOBAL040+_PAGE_NOCACHE_S+_PAGE_ACCESSED)
+	
+	jbra	mmu_init_done
 
+1:	
 	/*
-	 * Finally, since we just allocated 4 page tables, make sure that
-	 * the virtual mapping of the 4 page tables indicates
-	 * noncachable/serialized.
+	 * 030:	Map the 32Meg range physical 0x0 upto logical 0x8000.0000
 	 */
-	moveq	#3,%d0
-1:	movel	%a2@,%d1	/* a2 already points to root table offset */
-	andw	#_CACHEMASK040,%d1
-	orw	%d6,%d1
-	movel	%d1,%a2@+
-	dbra	%d0,1b
-
-	jra	Lmapphys
-
-Lnotami:
+	MMU_MAP(#0x80000000,#0,#0x02000000,#_PAGE_NOCACHE030+_PAGE_ACCESSED)
+	
+	jbra	mmu_init_done
+	
+mmu_init_not_amiga:
 #endif
 
-#ifdef CONFIG_ATARI
-	is_not_atari(Lnotatari)
+#if defined(CONFIG_ATARI)
 
-	move.w	#PAGESIZE,%sp
+mmu_init_atari:
 
+	is_not_atari(mmu_init_not_atari)
+	
+	putc_trace('I')
+	
 /* On the Atari, we map the I/O region (phys. 0x00ffxxxx) by mapping
    the last 16 MB of virtual address space to the first 16 MB (i.e.
    0xffxxxxxx -> 0x00xxxxxx). For this, an additional pointer table is
@@ -591,80 +944,33 @@
 
 	/* I/O base addr for non-Medusa, non-Hades: 0x00000000 */
 	moveq	#0,%d0
+	movel	%pc@(SYMBOL_NAME(atari_mch_type)),%d3
 	cmpl	#ATARI_MACH_MEDUSA,%d3
 	jbeq	2f
 	cmpl	#ATARI_MACH_HADES,%d3
 	jbne	1f
 2:	movel	#0xff000000,%d0 /* Medusa/Hades base addr: 0xff000000 */
 1:	movel	%d0,%d3
-	
-	/* Let the root table point to the new pointer table */
-	lea	%a4@(PTR_TABLE_SIZE<<2),%a4
-	movel	%a4,%a0
-	addw	#_PAGE_TABLE+_PAGE_ACCESSED,%a0
-	movel	%a0,%a5@(0x7f<<2)       /* 0xFE000000 - 0xFFFFFFFF */
-
-	/* clear lower half of the pointer table (0xfexxxxxx) */
-	movel	%a4,%a0
-	movel	#(PTR_TABLE_SIZE/2)-1,%d2
-1:	clrl	%a0@+
-	dbra	%d2,1b
 
 	is_040_or_060(Lspata68040)
 
-/* Mapping of the last 16M of virtual address space to the first 16M
-   for efficient addressing of hardware registers */
-	movel	#PAGE_TABLE_SIZE*PAGESIZE,%d1
-	movel	#(PTR_TABLE_SIZE/2)-1,%d2
-	movel	%d3,%d0
-	orw	#_PAGE_PRESENT+_PAGE_ACCESSED,%d0
-1:	movel	%d0,%a0@+
-	addl	%d1,%d0
-	dbra	%d2,1b
-	moveq	#_PAGE_NOCACHE030,%d0	/* make non-cachable */
-	addl	%d0,%a4@(0x7f<<2)	/* 0xFFFC0000-0xFFFFFFFF (I/O space) */
-/* GK: 0xFFF00000-0xFFF3FFFF (IDE-bus) has to be non-cachable too */
-	addl	%d0,%a4@(0x7c<<2)
-
-	jra	Lmapphys
+	/* Map everything non-cacheable, though not all parts really
+	 * need to disable caches (crucial only for 0xffc000..0xffffff
+	 * (standard I/O) and 0xf00000..0xf3ffff (IDE)). The remainder
+	 * isn't really used, except for sometimes peeking into the
+	 * ROMs (mirror at phys. 0x0), so caching isn't necessary for
+	 * this. */
+	MMU_MAP(#0xff000000,%d3,#0x01000000,#_PAGE_NOCACHE030+_PAGE_ACCESSED)
 
+	jbra	mmu_init_done
+	
 Lspata68040:
-	/* allocate 4 page tables */
-	movel	%a6,%a3
-	addw	#4*PAGESIZE,%a6
-
-	/* Initialize the upper half of the pointer table (a0 is still valid) */
-	movel	%a3,%a1
-	addw	#_PAGE_TABLE+_PAGE_ACCESSED,%a1
-	movel	#PAGE_TABLE_SIZE<<2,%d2
-	moveq	#TABLENR_16MB-1,%d1
-1:	movel	%a1,%a0@+
-	addl	%d2,%a1
-	dbra 	%d1,1b
-
-	/* Initialize the page tables as noncacheable/serialized! */
-	movel	%a3,%a0
-	movel	%d3,%a1
-	addw	#_PAGE_GLOBAL040+_PAGE_NOCACHE_S+_PAGE_PRESENT+_PAGE_ACCESSED,%a1
-	movel	#PAGESIZE,%d2
-	movew	#(PAGE_TABLE_SIZE*TABLENR_16MB)-1,%d1
-1:	movel	%a1,%a0@+
-	addl	%d2,%a1
-	dbra	%d1,1b
-
-	/*
-	 * Finally, since we just allocated 4 page tables, make sure that
-	 * the virtual mapping of the 4 page tables indicates
-	 * noncachable or write-through.
-	 */
-	moveq	#3,%d0
-1:	movel	%a2@,%d1	/* a2 already points to root table offset */
-	andw	#_CACHEMASK040,%d1
-	orw	%d6,%d1
-	movel	%d1,%a2@+
-	dbra	%d0,1b
+	
+	MMU_MAP(#0xff000000,%d3,#0x01000000,#_PAGE_GLOBAL040+_PAGE_NOCACHE_S+_PAGE_ACCESSED)
+	
+	jbra	mmu_init_done
 
-Lnotatari:
+mmu_init_not_atari:
 #endif
 
 #ifdef CONFIG_HP300
@@ -675,14 +981,19 @@
    termination page descriptor.  The ROM mapping is needed because the LEDs 
    are mapped there too.  */
 
+	MMU_MAP(#0xf0000000,#0,#0x01000000,#_PAGE_NOCACHE030+_PAGE_ACCESSED)
+
+#if 0
 	movel	#_PAGE_NOCACHE030+_PAGE_PRESENT+_PAGE_ACCESSED,%d0
 	movel	%d0,%a5@(0x78<<2)
+#endif
 
 Lnothp300:
-	
+
 #endif
 
 #if defined(CONFIG_MVME16x)
+	
 	is_not_mvme16x(Lnot16x)
 
 	/* Get pointer to board ID data */
@@ -696,272 +1007,506 @@
 	 * On MVME16x we have already created kernel page tables for
 	 * 4MB of RAM at address 0, so now need to do a transparent
 	 * mapping of the top of memory space.  Make it 0.5GByte for now.
+	 * Supervisor only access, so transparent mapping doesn't
+	 * clash with User code virtual address space.
+	 * this covers IO devices, PROM and SRAM.  The PROM and SRAM
+	 * mapping is needed to allow 167Bug to run.
+	 * IO is in the range 0xfff00000 to 0xfffeffff.
+	 * PROM is 0xff800000->0xffbfffff and SRAM is
+	 * 0xffe00000->0xffe1ffff.
 	 */
 
-	movel	#0xe01f0000,%d2		/* logical address base */
-	orw	#0xa040,%d2		/* add in magic bits */
-	.long	0x4e7b2005		/* movec d2,ittr1 */
-	.long	0x4e7b2007		/* movec d2,dttr1 */
-
+	MMU_MAP_TT(#0xe0000000,#0x20000000,#_PAGE_NOCACHE_S+_PAGE_ACCESSED)
+	
+	jbra	mmu_init_done
+	
 Lnot16x:
-#endif
+#endif	/* CONFIG_MVME162 | CONFIG_MVME167 */
 
 #if defined(CONFIG_BVME6000)
-	is_not_bvme6000(Lnotbvm)
+	
+	is_not_bvme6000(Lnot6000)
 
 	/*
 	 * On BVME6000 we have already created kernel page tables for
 	 * 4MB of RAM at address 0, so now need to do a transparent
-	 * mapping of the top of memory space.  Make it 0.5GByte for now.
+	 * mapping of the top of memory space.  Make it 0.5GByte for now,
+	 * so we can access on-board i/o areas.
+	 * Supervisor only access, so transparent mapping doesn't
+	 * clash with User code virtual address space.
 	 */
 
-	movel	#0xe01f0000,%d2		/* logical address base */
-	orw	#0xa040,%d2		/* add in magic bits */
-	.long	0x4e7b2005		/* movec d2,ittr1 */
-	.long	0x4e7b2007		/* movec d2,dttr1 */
-	.long	0x4e7b2004		/* movec d2,ittr0 */
-	.long	0x4e7b2006		/* movec d2,dttr0 */
+	MMU_MAP_TT(#0xe0000000,#0x20000000,#_PAGE_NOCACHE_S+_PAGE_ACCESSED)
+	
+	jbra	mmu_init_done
+	
+Lnot6000:
+#endif /* CONFIG_BVME6000 */
+
+/* 
+ * mmu_init_mac
+ * 
+ * The Macintosh mappings are less clear.
+ * 
+ * Even as of this writing, it is unclear how the
+ * Macintosh mappings will be done.  However, as
+ * the first author of this code I'm proposing the
+ * following model:
+ * 
+ * Map the kernel (that's already done),
+ * Map the I/O (on most machines that's the
+ * 0x5000.0000 ... 0x5200.0000 range,
+ * Map the video frame buffer using as few pages
+ * as absolutely (this requirement mostly stems from
+ * the fact that when the frame buffer is at
+ * 0x0000.0000 then we know there is valid RAM just
+ * above the screen that we don't want to waste!).
+ *
+ * By the way, if the frame buffer is at 0x0000.0000
+ * then the Macintosh is known as an RBV based Mac.
+ * 
+ * By the way 2, the code currently maps in a bunch of
+ * regions.  But I'd like to cut that out.  (And move most
+ * of the mappings up into the kernel proper ... or only
+ * map what's necessary.)
+ */
+
+#if defined(CONFIG_MAC)
+
+mmu_init_mac:
+	
+	is_not_mac(mmu_init_not_mac)
+
+	putc_trace('J')
+	
+	lea	%pc@(SYMBOL_NAME(mac_videobase)),%a0
+	lea	%pc@(Lconsole_video_virtual),%a1
+	movel	%a0@,%a1@
 
-Lnotbvm:
+	is_not_040_or_060(1f)
+	
+	movel	#_PAGE_GLOBAL040+_PAGE_NOCACHE_S+_PAGE_ACCESSED,MAP_CACHE
+	jbra	2f
+1:		
+	movel	#_PAGE_NOCACHE030+_PAGE_ACCESSED,MAP_CACHE
+2:	
+	/*
+	 * Mac Note: screen address of logical 0xF000.0000 -> <screen physical>
+	 */
+
+	/* Calculate screen size */
+	clrl	%d0
+	lea	%pc@(SYMBOL_NAME(mac_dimensions)),%a0
+	movew	%a0@,%d0 		/* d0 = screen height in pixels */
+
+	lea	%pc@(SYMBOL_NAME(mac_rowbytes)),%a0
+	mulul	%a0@,%d0		/* scan line bytes x num scan lines */
+	lea	%pc@(SYMBOL_NAME(mac_videobase)),%a0
+	movel	%a0@,%d2		/* grab screen offset from start of a page */
+	andl	#PAGESIZE-1,%d2		/* ... offset from start of page ... */
+	addl	%d2,%d0			/* add it to N bytes needed for screen for mapping purposes! */
+	addl	#PAGESIZE-1,%d0		/* Round up to page alignment */
+	andl	#-PAGESIZE,%d0		/* d0 is now the number of 4K pages for the screen */
+
+	movel	%a0@,%d2
+	andl	#PAGESIZE-1,%d2
+	addl	#0xF0000000,%d2
+	lea	%pc@(Lconsole_video_virtual),%a1
+	movel	%d2,%a1@		/* Update the console_video address */
+	movel	%a0@,%d2
+	andl	#-PAGESIZE,%d2
+
+	MMU_MAP(#0xF0000000,%d2,MAP_LENGTH,MAP_CACHE)
+	MMU_MAP_EQ(#0x40800000,#0x02000000,MAP_CACHE)	/* ROM ? */
+	MMU_MAP_EQ(#0x50000000,#0x02000000,MAP_CACHE)
+	MMU_MAP_EQ(#0x60000000,#0x00400000,MAP_CACHE)
+	MMU_MAP_EQ(#0x9C000000,#0x00400000,MAP_CACHE)
+	MMU_MAP_TT(#0xF8000000,#0x08000000,MAP_CACHE)
+	
+	jbra	mmu_init_done
+	
+mmu_init_not_mac:
 #endif
 
+mmu_init_done:		
+	
+	putc_trace('K')
+	leds(0x8)
+
 /*
- * Setup a transparent mapping of the physical memory we are executing in.
+ * mmu_fixup
+ * 
+ * On the 040 class machines, all pages that are used for the
+ * mmu have to be fixed up. According to Motorola, pages holding mmu
+ * tables should be non-cacheable on a '040 and write-through on a
+ * '060. But analysis of the reasons for this, and practical
+ * experience, showed that write-through also works on a '040.
  *
- * Only do this if the physical memory is not in the first 16M Meg, or not on
- * an Amiga since the first 16M is already identity mapped on the Amiga.
+ * So, we'll walk through the MMU table to determine which pages were
+ * allocated.  An alternative would be to "know" what pages were
+ * allocated above.  But that's fraught with maintenance problems.
+ * It's easier to walk the table.
+ * 
  */
-Lmapphys:
-	putc('J')
-	leds(0x8)
+#if defined(CONFIG_M68040) || defined(CONFIG_M68060)
 
-#ifdef CONFIG_AMIGA
-	is_not_amiga(Lmapphysnotamiga)
+mmu_fixup:
+	
+	is_not_040_or_060(mmu_fixup_done)
+	
+#if defined(MMU_NOCACHE_KERNEL)
+	jbra	mmu_fixup_done
+#endif
+	
+	moveml	%d0-%d5/%a0,%sp@-
+	
+	movel	%a5,%a0
+	jbsr	mmu_fixup_page_mmu_cache
+	
+	movel	#ROOT_TABLE_SIZE-1,%d5
+1:	
+	movel	%a5@(%d5*4),%d2
+	movel	%d2,%d0
+	andb	#_PAGE_TABLE,%d0
+	jbeq	4f
 
-/*
- * The virtual address of the start of the kernel is 0x1000. We transparently
- * translate the memory where we running in and can enable then the MMU. Hence
- * we have now two locations of the kernel in memory and can jump to the final
- * place. Except if the physical location is in the first 16MB, translation
- * will overlap later virtual location, but as we already mapped the first
- * 16MB to 0x80000000, we can jump there after translation and MMU is enabled
- * and then we can switch off translation and go to the final place.
- * On 020/030 we must emulate transparant translation, since 020 doesn't know
- * it, but due to early termination pointer this is easy to do.
- * When MMU is enabled, stack pointer and Lcustom will become again valid and
- * stack points to the unused first page.
- */
+	movel	%d2,%a0
+	jbsr	mmu_fixup_page_mmu_cache
+	
+	andl	#_TABLE_MASK,%d2
+	movel	%d2,%a4
+	movel	#PTR_TABLE_SIZE-1,%d4
 
-/*
- * Setup Supervisor Root Pointer register to point to page directory,
- * setup translation register contents and enable translation.
- */
-	putc('K')
+2:
+	movel	%a4@(%d4*4),%d2
+	movel	%d2,%d0
+	andb	#_PAGE_TABLE,%d0
+	jbeq	3f
 
-	movew	#PAGESIZE,%sp
+	movel	%d2,%a0
+	jbsr	mmu_fixup_page_mmu_cache
+	
+3:
+	dbra	%d4,2b
 
-	/* fixup the Amiga custom register location before printing */
-	lea	%pc@(Lcustom),%a0
-	movel	#0x80000000,%a0@
+4:
+	dbra	%d5,1b
 
-	is_040_or_060(Lamimmu68040)
+	moveml	%sp@+,%d0-%d5/%a0
 
-	moveq	#ROOT_INDEX_SHIFT,%d2
-	movel	%d5,%d0
-	lsrl	%d2,%d0
-	movel	%d0,%d1
-	lsll	%d2,%d1
-	orw	#_PAGE_PRESENT+_PAGE_ACCESSED,%d1
-	lsll	#2,%d0
-	movel	%a5@(%d0:w),%d2
-	movel	%d1,%a5@(%d0:w)
-	lea	%pc@(Lmmu),%a3
-	/* no limit, 4byte descriptors */
-	movel	#0x80000002,%a3@
-	movel	%a5,%a3@(4)
-	pmove	%a3@,%srp
-	pmove	%a3@,%crp
-	pflusha
-	/*
-	 * enable,super root enable,4096 byte pages,7 bit root index,
-	 * 7 bit pointer index, 6 bit page table index.
+	jbra	mmu_fixup_done
+
+mmu_fixup_page_mmu_cache:
+	moveml	%a0/%d0-%d5,%sp@-
+
+	/* Calculate the offset in the root table 
 	 */
-	movel	#0x82c07760,%a3@
-	pmove	%a3@,%tc	/* enable the MMU */
-	tstl	%d0
-	jne	1f
-	jmp	%pc@(2f+0x80000000)
-1:	jmp	2f:w
-2:	movel	%d2,%a5@(%d0:w)
-	pflusha
-	jmp	LdoneMMUenable:w
+	movel	%a0,%d5
+	andil	#0xfe000000,%d5
+	roll	#7,%d5
 
-Lamimmu68040:
+	/* Calculate the offset in the pointer table 
+	 */
+	movel	%a0,%d4
+	andil	#0x01fc0000,%d4
+	lsrl	#2,%d4
+	swap	%d4
+	
+	/* Calculate the offset in the page table
+	 */
+	movel	%a0,%d3
+	andil	#0x0003f000,%d3
+	lsll	#4,%d3
+	swap	%d3
 
-	.chip	68040
-	lea	2f:w,%a0
-	movel	%d5,%d0
-	andl	#0xff000000,%d0
-	jne	1f
-	lea	%pc@(2f+0x80000000),%a0
-1:	orw	#TTR_ENABLE+TTR_KERNELMODE+_PAGE_NOCACHE_S,%d0
-	movec	%d0,%itt0
-	movec	%a5,%urp
-	movec	%a5,%srp
-	pflusha
-	movel	#TC_ENABLE+TC_PAGE4K,%d0
 	/*
-	 * this value is also ok for the 68060, we don`t use the cache
-	 * mode/protection defaults
+	 * Find the page table entry (PTE) for the page
 	 */
-	movec	%d0,%tc		/* enable the MMU */
-	jmp	%a0@
-2:	moveq	#0,%d0
-	movec	%d0,%itt0
-	jmp	LdoneMMUenable:w
-	.chip	68k
-
-Lmapphysnotamiga:
+	movel	%a5@(%d5*4),%d0
+	andil	#_TABLE_MASK,%d0
+	movel	%d0,%a0
+	movel	%a0@(%d4*4),%d0
+	andil	#0xffffff00,%d0
+	movel	%d0,%a0
+	movel	%a0@(%d3*4),%d0
+	/*
+	 * Set cache mode to cacheable write through
+	 */
+	andil	#_CACHEMASK040,%d0
+	orl	%pc@(SYMBOL_NAME(m68k_pgtable_cachemode)),%d0
+	movel	%d0,%a0@(%d3*4)
+	
+	moveml	%sp@+,%a0/%d0-%d5
+	rts
+	
+mmu_fixup_done:
+#endif /* CONFIG_M68040 && CONFIG_M68060 */
+	
+#if defined(MMU_PRINT)
+	jbsr	mmu_print
 #endif
 
-#ifdef CONFIG_ATARI
-	is_not_atari(Lmapphysnotatari)
-
-/*
- * If the kernel physical address is different from its virtual address, we
- * will temporarily set up an identity mapping of the 16MB chunk with
- * transparent translation where the kernel is executing.
+/* 
+ * mmu_engage
+ * 
+ * This chunk of code performs the gruesome task of engaging the MMU.
+ * The reason its gruesome is because when the MMU becomes engaged it
+ * maps logical addresses to physical addresses.  The Program Counter
+ * register is then passed through the MMU before the next instruction
+ * is fetched (the instruction following the engage MMU instruction).
+ * This may mean one of two things:
+ * 1. The Program Counter falls within the logical address space of
+ *    the kernel of which there are two sub-possibilities:
+ *    A. The PC maps to the correct instruction (logical PC == physical
+ *       code location), or
+ *    B. The PC does not map through and the processor will read some
+ *       data (or instruction) which is not the logically next instr.
+ *    As you can imagine, A is good and B is bad.
+ * Alternatively,
+ * 2. The Program Counter does not map through the MMU.  The processor
+ *    will take a Bus Error.
+ * Clearly, 2 is bad.
+ * It doesn't take a wiz kid to figure you want 1.A.
+ * This code creates that possibility.
+ * There are two possible 1.A. states (we now ignore the other above states):
+ * A. The kernel is located at physical memory addressed the same as
+ *    the logical memory for the kernel, i.e., 0x01000.
+ * B. The kernel is located some where else.  e.g., 0x0400.0000
+ * 
+ *    Under some conditions the Macintosh can look like A or B.
+ * [A friend and I once noted that Apple hardware engineers should be
+ * wacked twice each day: once when they show up at work (as in, Whack!,
+ * "This is for the screwy hardware we know you're going to design today."),
+ * and also at the end of the day (as in, Whack! "I don't know what
+ * you designed today, but I'm sure it wasn't good."). -- rst]
+ * 
+ * This code works on the following premise:
+ * If the kernel start (%d5) is within the first 16 Meg of RAM,
+ * then create a mapping for the kernel at logical 0x8000.0000 to
+ * the physical location of the pc.  And, create a transparent
+ * translation register for the first 16 Meg.  Then, after the MMU
+ * is engaged, the PC can be moved up into the 0x8000.0000 range
+ * and then the transparent translation can be turned off and then
+ * the PC can jump to the correct logical location and it will be
+ * home (finally).  This is essentially the code that the Amiga used
+ * to use.  Now, it's generalized for all processors.  Which means
+ * that a fresh (but temporary) mapping has to be created.  The mapping
+ * is made in page 0 (an as of yet unused location -- except for the
+ * stack!).  This temporary mapping will only require 1 pointer table
+ * and a single page table (it can map 256K).
+ *
+ * OK, alternatively, imagine that the Program Counter is not within
+ * the first 16 Meg.  Then, just use Transparent Translation registers
+ * to do the right thing.
+ *
+ * Last, if _start is already at 0x01000, then there's nothing special
+ * to do (in other words, in a degenerate case of the first case above,
+ * do nothing).
+ *
+ * Let's do it.
+ * 
+ * 
  */
-	putc('L')
 
-	/* fixup the  Atari iobase register location before printing */
+	putc_trace('L')
+	
+#if defined(CONFIG_MAC)
+	is_not_mac(1f)
+	lea	%pc@(Lconsole_video_virtual),%a1
+	lea	%pc@(SYMBOL_NAME(mac_videobase)),%a3
+	movel	%a1@,%a3@
+1:
+#endif
+	
+#if defined(CONFIG_AMIGA)
+	is_not_amiga(1f)
+	/* fixup the Amiga custom register location before printing */
+	lea	%pc@(Lcustom),%a0
+	movel	#0x80000000,%a0@
+1:	
+#endif
+
+#if defined(CONFIG_ATARI)
+	is_not_atari(1f)
+	/* fixup the Atari iobase register location before printing */
 	lea	%pc@(Liobase),%a0
 	movel	#0xff000000,%a0@
+1:	
+#endif
+	
+#if defined(CONFIG_HP300)
+	is_not_hp300(1f)
+	/*
+	 * Fix up the custom register to point to the new location of the LEDs.
+	 */
+	lea	%pc@(Lcustom),%a1
+	movel	#0xf0000000,%a1@
+1:	
+#endif
+	
+	/*
+	 * Test for the simplest case:
+	 *    _start == 0x01000 
+	 *       %d5 == 0x00000
+	 */
+	lea	mmu_engage_done:w,%a0
+	tstl	%d5
+	jbeq	mmu_engage_core
 
-	is_040_or_060(Latarimmu68040)
-
-	.chip	68030
-	lea	%pc@(Lmmu),%a3
+	/*
+	 * Prepare a transparent translation register
+	 * for the region the kernel is in.
+	 */
 	movel	%d5,%d0
-	jne	1f
-	lea	LdoneMMUenable:w,%a0
-	jra	3f
-1:	lea	4f:w,%a0
-	andl	#0xff000000,%d0 /* logical address base */
-	jeq	2f
+	andl	#0xff000000,%d0
+
+#if defined(CONFIG_M68040) || defined(CONFIG_M68060)
+	is_not_040_or_060(1f)
+	lea	mmu_engage_040_disable_itt0,%a0
+	
+	orw	#TTR_ENABLE+TTR_KERNELMODE+_PAGE_NOCACHE_S,%d0
+	.chip	68040
+	movec	%d0,%itt0
+	.chip	68k
+	jbra	2f
+1:
+#endif
+#if defined(CONFIG_M68020) || defined(CONFIG_M68030)
+	lea	mmu_engage_030_disable_tt0,%a0
+	
 	orw	#TTR_ENABLE+TTR_CI+TTR_RWM+TTR_FCB2+TTR_FCM1+TTR_FCM0,%d0
+	lea	%pc@(Lmmu),%a3
 	movel	%d0,%a3@
+	.chip	68030
 	pmove	%a3@,%tt0
-	jra	3f
-	/* tt0 doesn't work if physical and virtual address of kernel is in
-	 * the same 16M area (Falcon with Magnum/FX, kernel in alternate ram)
-	 * Transparent translation through kernel pointer table
-	 * Requires that this code until after MMU enabling lies in
-	 * the 256K page around %d5
-	 */
-2:	movel	%a5@,%d1
-	andw	#0xfff0,%d1
-	movel	%d1,%a1
-	movel	%d5,%d1
-	moveq	#PTR_INDEX_SHIFT,%d0
-	lsrl	%d0,%d1
-	lea	%a1@(%d1:l:4),%a1
-	movel	%d5,%d1
-	orw	#_PAGE_PRESENT+_PAGE_ACCESSED,%d1
-	movel	%a1@,%d2
-	movel	%d1,%a1@
-	lea	5f:w,%a0
-	/* no limit, 4byte descriptors */
-3:	movel	#0x80000002,%a3@
-	movel	%a5,%a3@(4)
-	pmove	%a3@,%srp
-	pmove	%a3@,%crp
-	pflusha
-	/*
-	 * enable,super root enable,4096 byte pages,7 bit root index,
-	 * 7 bit pointer index, 6 bit page table index.
-	 */
-	movel	#0x82c07760,%a3@
-	pmove	%a3@,%tc	/* enable the MMU */
-	jmp	%a0@
-4:	clrl	%a3@
-	pmove	%a3@,%tt0
-	jra	LdoneMMUenable
-5:	movel	%d2,%a1@
-	jra	LdoneMMUenable
 	.chip	68k
+#endif
 
-Latarimmu68040:
-	.chip	68040
+	/*
+	 * Test for being able to use just a
+	 * transparent translation register:
+	 *    _start >= 0x0100.1000
+	 *       %d5 >= 0x0100.0000
+	 */
+2:
 	movel	%d5,%d0
-	jne	1f
-	lea	LdoneMMUenable:w,%a0
-	jra	2f
-1:	lea	3f:w,%a0
-	andl	#0xff000000,%d0 /* logical address base */
-	orw	#TTR_ENABLE+TTR_KERNELMODE+_PAGE_NOCACHE_S,%d0
-	movec	%d0,%itt0
-2:	nop
-	pflusha
-	movec	%a5,%srp
-	movec	%a5,%urp
-	movel	#TC_ENABLE+TC_PAGE4K,%d0
+	andil	#0xff000000,%d0
+	jbne	mmu_engage_core
+
 	/*
-	 * this value is also ok for the 68060, we don`t use the cache
-	 * mode/protection defaults
+	 * I hate this case: 
+	 *   %d5 > 0, and
+	 *   %d5 < 0x0100.0000
+	 * Here's where we have to create a temporary mapping
+	 * at 0x8000.0000 and do all the right stuff magic.
+	 * This bites.  -- rst
 	 */
-	movec	%d0,%tc		/* enable the MMU */
-	jmp	%a0@
-3:	moveq	#0,%d0
-	movec	%d0,%itt0
-	jra	LdoneMMUenable
-	.chip	68k
 
-Lmapphysnotatari:
-#endif
+#define TMP_MAP		0x80000000
+#define TMP_MAP_OFFS	(TMP_MAP>>(ROOT_INDEX_SHIFT-2))
 
-#if defined(CONFIG_MVME16x)
-	is_not_mvme16x(Lmapphysnot16x)
 	/*
-	 * save physaddr of phys mem in register a3
+	 * Build a really small Ptr table at %d5
 	 */
-	moveq	#'L',%d7
-	jbsr	Lserial_putc
-
-	.word	0xf4d8		/* CINVA I/D    */
-	.word	0xf518		/* pflusha      */
-	.long	0x4e7bd807	/* movec a5,srp */
-	.long	0x4e7bd806	/* movec a5,urp */
-	movel	#(TC_ENABLE+TC_PAGE4K),%d0
-	.long	0x4e7b0003	/* movec d0,tc  (enable the MMU) */
-	jra	LdoneMMUenable	/* branch to continuation of startup */
+	movel	%d5,%a4
+	jbsr	mmu_clear_pointer_table
+	
+	movel	%d5,%d0
+	addl	#0x100,%d0
+	orw	#_PAGE_TABLE+_PAGE_ACCESSED,%d0
+	movel	%d0,%a4@
+	
+	/*
+	 * Build a really small Page table at %d5 + 0x100
+	 * (Maps the first 16K of the kernel @ 0x8000.0000)
+	 */
+	movel	%d5,%a3
+	addaw	#0x100,%a3
+	jbsr	mmu_clear_page_table
+	
+	movel	#PAGESIZE,%d1
+	movel	%d5,%d0
+	orw	#_PAGE_PRESENT+_PAGE_ACCESSED,%d0
+	movel	%d0,%a3@+
+	addl	%d1,%d0
+	movel	%d0,%a3@+
+	addl	%d1,%d0
+	movel	%d0,%a3@+
+	addl	%d1,%d0
+	movel	%d0,%a3@
 
-Lmapphysnot16x:
+	/*
+	 * Alter the Root table to use our really small entries
+	 */
+	lea	%a5@(TMP_MAP_OFFS),%a0
+	movel	%a0@,%d2		/* save entry */
+	movel	%d5,%d0
+	orw	#_PAGE_TABLE+_PAGE_ACCESSED,%d0
+	movel	%d0,%a0@		/* insert temp. entry */
 
+#if defined(CONFIG_M68040) || defined(CONFIG_M68060)
+	is_not_040_or_060(1f)
+	lea	mmu_engage_040_disable_8000,%a0
+	addal	#TMP_MAP,%a0
+	jbra	mmu_engage_core
+1:
 #endif
+#if defined(CONFIG_M68020) || defined(CONFIG_M68030)
+	lea	mmu_engage_030_disable_8000,%a0
+	addal	#TMP_MAP,%a0
+#endif
+	
+mmu_engage_core:
+	
+#if defined(CONFIG_M68040) || defined(CONFIG_M68060)
+	is_not_040_or_060(2f)
 
-#if defined(CONFIG_HP300)
-	is_not_hp300(Lmapphysnothp300)
+mmu_engage_040:
+	.chip	68040
+	nop
+	cinva	%bc
+	nop
+	pflusha
+	nop
+	movec	%a5,%srp
+	movec	%a5,%urp
+	movel	#TC_ENABLE+TC_PAGE4K,%d0
+	movec	%d0,%tc		/* enable the MMU */
+	lea	SYMBOL_NAME(kernel_pg_dir),%a5
+	jmp	%a0@		/* Go to clean up code */
 
-/*
- * Physical RAM is at 0xff000000.  We want to map the kernel at 0x00000000.
- * In order to avoid disaster when we enable the MMU we need to make a
- * transparent mapping of the RAM we're executing out of as well.
- */
+mmu_engage_040_disable_itt0:
+	moveq	#0,%d0
+	movec	%d0,%itt0
+	jmp	mmu_engage_done:w
+
+mmu_engage_040_disable_8000:
 	/*
-	 * save physaddr of phys mem in register a3
+	 * This code is running at 0x8000.0000+ right now
 	 */
+	moveq	#0,%d0
+	movec	%d0,%itt0
+	jmp	1f:w	/* Jump down into logical space into the kernel! */
+1:
+	/* Now we're back on the ground! */
+	movel	%d2,%a5@(TMP_MAP_OFFS) /* Restore the old 0x8000.0000 mapping */
+	nop
+	pflusha
+	nop
+	jmp	mmu_engage_done:w
+	.chip	68k
+
+2:
+#endif
 
+#if defined(CONFIG_M68020) || defined(CONFIG_M68030)
+mmu_engage_030:
 	.chip	68030
 	lea	%pc@(Lmmu),%a3
-	movel	%d5,%d0
-	andl	#0xff000000,%d0 /* logical address base */
-	orw	#TTR_ENABLE+TTR_CI+TTR_RWM+TTR_FCB2+TTR_FCM1+TTR_FCM0,%d0
-	movel	%d0,%a3@
-	pmove	%a3@,%tt0
-	/* no limit, 4byte descriptors */
 	movel	#0x80000002,%a3@
 	movel	%a5,%a3@(4)
+	movel	#0x0808,%d1
+	movec	%d1,%cacr
 	pmove	%a3@,%srp
 	pmove	%a3@,%crp
 	pflusha
@@ -971,117 +1516,171 @@
 	 */
 	movel	#0x82c07760,%a3@
 	pmove	%a3@,%tc	/* enable the MMU */
-	jmp	1f
-1:	
-	.chip	68k
+	lea	SYMBOL_NAME(kernel_pg_dir),%a5
+	jmp	%a0@		/* Go to the appropriate clean up code */
 
-	/*
-	 * Fix up the custom register to point to the new location of the LEDs.
-	 */
-	lea	%pc@(Lcustom),%a1
-	movel	#0xf0000000,%a1@
-
-	/*
-	 * Energise the FPU and caches.
-	 */
-	orl	#0x64, 0xf05f400c 
+mmu_engage_030_disable_tt0:
+	clrl	%a3@
+	pmove	%a3@,%tt0
+	jmp	mmu_engage_done:w
 	
-Lmapphysnothp300:
-
+mmu_engage_030_disable_8000:
+	clrl	%a3@
+	pmove	%a3@,%tt0
+	jmp	1f:w	/* Jump down into logical space into the kernel! */
+1:
+	/* Now we're back on the ground! */
+	movel	%d2,%a5@(TMP_MAP_OFFS)	/* Restore the old 0x8000.0000 mapping */
+	pflusha
+	jmp	mmu_engage_done:w
+	.chip	68k
 #endif
+	
+mmu_engage_done:
 
-#if defined(CONFIG_BVME6000)
-	is_not_bvme6000(Lmapphysnotbvm)
-	/*
-	 * save physaddr of phys mem in register a3
-	 */
-	moveq	#'L',%d7
-	jbsr	Lserial_putc
-
-	.word	0xf4d8		/* CINVA I/D    */
-	.word	0xf518		/* pflusha      */
-	.long	0x4e7bd807	/* movec a5,srp */
-	.long	0x4e7bd806	/* movec a5,urp */
-	movel	#(TC_ENABLE+TC_PAGE4K),%d0
+#if defined(CONFIG_HP300)
+	is_not_hp300(1f)
 	/*
-	 * this value is also ok for the 68060, we don`t use the cache
-	 * mode/protection defaults
+	 * Energise the FPU and caches.
 	 */
-	.long	0x4e7b0003	/* movec d0,tc  (enable the MMU) */
-	jra	LdoneMMUenable	/* branch to continuation of startup */
-
-Lmapphysnotbvm:
-
+	movel	#0x60, 0xf05f400c
+1:	
 #endif
-
-LdoneMMUenable:
-
+	movew	#PAGESIZE,%sp
+	
 /*
  * Fixup the addresses for the kernel pointer table and availmem.
  * Convert them from physical addresses to virtual addresses.
  */
 
-	putc('M')
+	putc_trace('M')
 	leds(0x10)
 
-	/*
-	 * d5 contains physaddr of kernel start
+	/* d5 contains physaddr of kernel start
 	 */
-	subl	%d5,SYMBOL_NAME(kpt)
+	lea	SYMBOL_NAME(kpt),%a0
+	subl	%d5,%a0@
 
-	/*
-	 * do the same conversion on the first available memory
+	/* do the same conversion on the first available memory
 	 * address (in a6).
 	 */
+	lea	SYMBOL_NAME(availmem),%a0
 	subl	%d5,%a6
-	movel	%a6,SYMBOL_NAME(availmem) /* first available memory address */
-
-	putc('N')
-
+	movel	%a6,%a0@
+	
 /*
  * Enable caches
  */
-	is_040_or_060(Lcache680460)
 
-	movel	#CC3_ENABLE_DB+CC3_CLR_D+CC3_ENABLE_D+CC3_ENABLE_IB+CC3_CLR_I+CC3_ENABLE_I,%d0
-	movec	%d0,%cacr
-	jra	1f
+#if defined(CONFIG_M68040) || defined(CONFIG_M68060)
+	is_not_040_or_060(Lcache_not_680460)
 
 Lcache680460:
 	.chip	68040
+	nop
 	cpusha	%bc
-	.chip	68k
-
+	nop
+	
 	is_060(Lcache68060)
 
 	movel	#CC6_ENABLE_D+CC6_ENABLE_I,%d0
 	/* MMU stuff works in copyback mode now, so enable the cache */
 	movec	%d0,%cacr
-	jra	1f
+	jra	Lcache_done
 
 Lcache68060:
-	.chip	68060
 	movel	#CC6_ENABLE_D+CC6_ENABLE_I+CC6_ENABLE_SB+CC6_PUSH_DPI+CC6_ENABLE_B+CC6_CLRA_B,%d0
 	/* MMU stuff works in copyback mode now, so enable the cache */
 	movec	%d0,%cacr
 	/* enable superscalar dispatch in PCR */
 	moveq	#1,%d0
+	.chip	68060
 	movec	%d0,%pcr
+
+	jbra	Lcache_done
+Lcache_not_680460:
+#endif
+#if defined(CONFIG_M68020) || defined(CONFIG_M68030)
+Lcache68030:
+	.chip	68030
+	movel	#CC3_ENABLE_DB+CC3_CLR_D+CC3_ENABLE_D+CC3_ENABLE_IB+CC3_CLR_I+CC3_ENABLE_I,%d0
+	movec	%d0,%cacr
+
+	jra	Lcache_done
+#endif
 	.chip	68k
-1:
+Lcache_done:
 
+	putc_trace('P')
+
+#if defined(MMU_PRINT_PAGE_USAGE)
+	/*
+	 * Print out the number of pages used by MMU above the kernel
+	 */
+	puts("MMU #")
+	lea	%pc@(SYMBOL_NAME(_end)),%a0
+	addw	#PAGESIZE-1,%a0
+	movel	%a0,%d0
+	andl	#-PAGESIZE,%d0
+	movel	%a6,%d1
+	subl	%d0,%d1		/* d1 :	= d1 - d0 */
+	putn(%d1)
+	putr()
+
+	puts("Page #")
+	putn(%pc@(Lmmu_num_page_tables))
+	putr()
+	
+
+	puts("Ptr #")
+	putn(%pc@(Lmmu_num_pointer_tables))
+	putr()
+
+	puts("Total #")
+	movel	%pc@(Lmmu_num_page_tables),%d0
+	addl	%pc@(Lmmu_num_pointer_tables),%d0
+	putn(%d0)
+	putr()
+
+	puts("Halting.")	
+1:
+	jbra	1b
+#endif /* MMU_PRINT_PAGE_USAGE */
+	
 /*
  * Setup initial stack pointer
- * We need to get current loaded up with our first task...
  */
 	lea	SYMBOL_NAME(init_task_union),%a2
-	lea	8192(%a2),%sp
+	lea	0x2000(%a2),%sp
 
 /* jump to the kernel start */
 	putr()
 	leds(0x55)
 
-	subl	%a6,%a6 /* clear a6 for gdb */
+#if defined(DEBUG)
+	puts("     kpt:")
+	lea	%pc@(SYMBOL_NAME(kpt)),%a0
+	movel	%a0,%d7		/* get start addr. */
+	jbsr	Lserial_putnum
+	putr()
+
+	puts("    *kpt:")
+	lea	%pc@(SYMBOL_NAME(kpt)),%a0
+	movel	%a0@,%d7	/* get start addr. */
+	jbsr	Lserial_putnum
+	putr()
+#endif
+
+#if 0
+	movel	#0xFFFF,%d1
+2:
+	movel	#0xFFFFFFFF,%d0
+1:
+	dbra	%d0,1b
+	dbra	%d1,2b
+#endif
+
+	subl	%a6,%a6		/* clear a6 for gdb */
 	jbsr	SYMBOL_NAME(start_kernel)
 
 /*
@@ -1106,18 +1705,1093 @@
 	lea	%a0@(BIR_size),%a0
 	rts
 
+
+/*
+ *	MMU Initialization Begins Here
+ *
+ *	The structure of the MMU tables on the 68k machines
+ *	is thus:
+ *	Root Table
+ *		Logical addresses are translated through
+ *	a hierarchical translation mechanism where the high-order
+ *	seven bits of the logical address (LA) are used as an
+ *	index into the "root table."  Each entry in the root
+ *	table has a bit which specifies if it's a valid pointer to a
+ *	pointer table.  Each entry defines a 32KMeg range of memory.
+ *	If an entry is invalid then that logical range of 32M is
+ *	invalid and references to that range of memory (when the MMU
+ *	is enabled) will fault.  If the entry is valid, then it does
+ *	one of two things.  On 040/060 class machines, it points to
+ *	a pointer table which then describes more finely the memory
+ *	within that 32M range.  On 020/030 class machines, a technique
+ *	called "early terminating descriptors" are used.  This technique
+ *	allows an entire 32Meg to be described by a single entry in the
+ *	root table.  Thus, this entry in the root table, contains the
+ *	physical address of the memory or I/O at the logical address
+ *	which the entry represents and it also contains the necessary
+ *	cache bits for this region.
+ *
+ *	Pointer Tables
+ *		Per the Root Table, there will be one or more
+ *	pointer tables.  Each pointer table defines a 32M range.
+ *	Not all of the 32M range need be defined.  Again, the next
+ *	seven bits of the logical address are used an index into
+ *	the pointer table to point to page tables (if the pointer
+ *	is valid).  There will undoubtedly be more than one
+ *	pointer table for the kernel because each pointer table
+ *	defines a range of only 32M.  Valid pointer table entries
+ *	point to page tables, or are early terminating entries
+ *	themselves.
+ *
+ *	Page Tables
+ *		Per the Pointer Tables, each page table entry points
+ *	to the physical page in memory that supports the logical
+ *	address that translates to the particular index.
+ *
+ *	In short, the Logical Address gets translated as follows:
+ *		bits 31..26 - index into the Root Table
+ *		bits 25..18 - index into the Pointer Table
+ *		bits 17..12 - index into the Page Table
+ *		bits 11..0  - offset into a particular 4K page
+ *	
+ *	The algorithms which follows do one thing: they abstract
+ *	the MMU hardware.  For example, there are three kinds of
+ *	cache settings that are relevant.  Either, memory is
+ *	being mapped in which case it is either Kernel Code (or
+ *	the RamDisk) or it is MMU data.  On the 030, the MMU data
+ *	option also describes the kernel.  Or, I/O is being mapped
+ *	in which case it has its own kind of cache bits.  There
+ *	are constants which abstract these notions from the code that
+ *	actually makes the call to map some range of memory.
+ *	
+ *	
+ *	
+ */
+
+#if defined(MMU_PRINT)
+/*
+ *	mmu_print
+ *	
+ *	This algorithm will print out the current MMU mappings.
+ *	
+ *	Input:
+ *		%a5 points to the root table.  Everything else is calculated
+ *			from this.
+ */
+
+#define mmu_next_valid		0
+#define mmu_start_logical	4
+#define mmu_next_logical	8
+#define mmu_start_physical	12
+#define mmu_next_physical	16
+
+#define MMU_PRINT_INVALID		-1
+#define MMU_PRINT_VALID			1
+#define MMU_PRINT_UNINITED		0
+
+#define	putZc(z,n)		jbne 1f; putc(z); jbra 2f ; 1: putc(n); 2:
+
+mmu_print:
+	moveml	%a0-%a6/%d0-%d7,%sp@-
+
+	lea	%pc@(Lmmu_print_data),%a0
+	movel	#MMU_PRINT_UNINITED,%a0@(mmu_next_valid)
+	
+	is_not_040_or_060(mmu_030_print)
+	
+mmu_040_print:
+	putr()
+	puts("MMU040")
+	putr()
+	putr()
+	puts("rp:")
+	movel	%a5,%d7
+	jbsr	Lserial_putnum
+	putr()
+	puts("tc:")
+	movel	%d5,%d7
+	jbsr	Lserial_putnum
+	putr()
+	putr()
+#if 0
+	/*
+	 * The following #if/#endif block is a tight algorithm for dumping the 040
+	 * MMU Map in gory detail.  It really isn't that practical unless the
+	 * MMU Map algorithm appears to go awry and you need to debug it at the
+	 * entry per entry level.
+	 */
+	movel	#ROOT_TABLE_SIZE-1,%d5
+	movel	%a5@+,%d7		/* Burn an entry to skip the kernel mappings, they work */
+1:	tstl	%d5
+	jbeq	mmu_print_done
+	subq	#1,%d5
+	movel	%a5@+,%d7
+	btst	#1,%d7
+	jbeq	1b
+
+2:	jbsr	Lserial_putnum
+	andil	#0xFFFFFE00,%d7
+	movel	%d7,%a4
+	movel	#PTR_TABLE_SIZE,%d4
+	putc(' ')
+3:	tstl	%d4
+	jbeq	11f
+	subq	#1,%d4
+	movel	%a4@+,%d7
+	btst	#1,%d7
+	jbeq	3b
+
+4:	jbsr	Lserial_putnum
+	andil	#0xFFFFFF00,%d7
+	movel	%d7,%a3
+	movel	#PAGE_TABLE_SIZE,%d3
+5:	movel	#8,%d2
+6:	tstl	%d3
+	jbeq	31f
+	subq	#1,%d3
+	movel	%a3@+,%d6
+	btst	#0,%d6
+	jbeq	6b
+7:	tstl	%d2
+	jbeq	8f
+	subq	#1,%d2
+	putc(' ')
+	jbra	91f
+8:	putr()
+	movel	#8+1+8+1+1,%d2
+9:	putc(' ')
+	dbra	%d2,9b
+	movel	#7,%d2
+91:	movel	%d6,%d7
+	jbsr	Lserial_putnum
+	jbra	6b
+
+31:	putr()
+	movel	#8+1,%d2
+32:	putc(' ')
+	dbra	%d2,32b
+	jbra	3b
+
+11:	putr()
+	jbra	1b
+#endif /* MMU 040 Dumping code that's gory and detailed */
+			
+	movel	%a5,%d0			/* a5 -> root table ptr */
+	andil	#0xfffffe00,%d0		/* I forget why this is here ? */
+	movel	%d0,%a0			/* a0 has the address of the root table ptr */
+	movel	#0x00000000,%a4		/* logical address */
+	moveql	#0,%d0
+40:
+	/* Increment the logical address and preserve in d5 */
+	movel	%a4,%d5
+	addil	#PAGESIZE<<13,%d5
+	movel	%a0@+,%d6
+	btst	#1,%d6
+	jbne	41f
+	jbsr	mmu_print_tuple_invalidate
+	jbra	48f
+41:	
+	movel	#0,%d1
+	andil	#0xfffffe00,%d6
+	movel	%d6,%a1
+42:
+	movel	%a4,%d5
+	addil	#PAGESIZE<<6,%d5
+	movel	%a1@+,%d6
+	btst	#1,%d6
+	jbne	43f
+	jbsr	mmu_print_tuple_invalidate
+	jbra	47f
+43:		
+	movel	#0,%d2
+	andil	#0xffffff00,%d6
+	movel	%d6,%a2
+44:	
+	movel	%a4,%d5
+	addil	#PAGESIZE,%d5
+	movel	%a2@+,%d6
+	btst	#0,%d6
+	jbne	45f
+	jbsr	mmu_print_tuple_invalidate
+	jbra	46f
+45:
+	moveml	%d0-%d1,%sp@-
+	movel	%a4,%d0
+	movel	%d6,%d1
+	andil	#0xfffff4e0,%d1
+	lea	%pc@(mmu_040_print_flags),%a6
+	jbsr	mmu_print_tuple
+	moveml	%sp@+,%d0-%d1
+46:
+	movel	%d5,%a4
+	addq	#1,%d2
+	cmpib	#64,%d2
+	jbne	44b
+47:
+	movel	%d5,%a4
+	addq	#1,%d1
+	cmpib	#128,%d1
+	jbne	42b
+48:
+	movel	%d5,%a4			/* move to the next logical address */	
+	addq	#1,%d0
+	cmpib	#128,%d0
+	jbne	40b
+
+	.long	0x4e7a0007		/* movec dtt1,%d0 */
+	movel	%d0,%d1
+	andiw	#0x8000,%d1		/* is it valid ? */
+	jbeq	49f			/* No, bail out */
+
+	movel	%d0,%d1
+	andil	#0xff000000,%d1		/* Get the address */
+	putn(%d1)
+	puts("==")
+	putn(%d1)
+
+	movel	%d0,%d6
+	jbsr	mmu_040_print_flags_tt
+	
+49:
+	jbra	mmu_print_done
+
+mmu_040_print_flags:
+	btstl	#10,%d6
+	putZc(' ','G')	/* global bit */
+	btstl	#7,%d6
+	putZc(' ','S')	/* supervisor bit */
+mmu_040_print_flags_tt:	
+	btstl	#6,%d6
+	jbne	3f
+	putc('C')
+	btstl	#5,%d6
+	putZc('w','c')	/* write through or copy-back */
+	jbra	4f
+3:
+	putc('N')
+	btstl	#5,%d6
+	putZc('s',' ')	/* serialized non-cacheable, or non-cacheable */
+4:		
+	rts
+	
+mmu_030_print_flags:
+	btstl	#6,%d6
+	putZc('C','I')	/* write through or copy-back */
+	rts
+	
+mmu_030_print:	
+	putr()
+	puts("rp:")
+	movel	%a5,%d7
+	jbsr	Lserial_putnum
+	putr()
+	puts("tc:")
+	movel	%d5,%d7
+	jbsr	Lserial_putnum
+	putr()
+	putr()
+	puts("MMU030")
+	putr()
+	movel	%a5,%d0
+	andil	#0xfffffff0,%d0
+	movel	%d0,%a0
+	movel	#0x00000000,%a4		/* logical address */
+	movel	#0,%d0
+30:
+	movel	%a4,%d5
+	addil	#PAGESIZE<<13,%d5
+	movel	%a0@+,%d6
+	btst	#1,%d6			/* is it a ptr? */
+	jbne	31f			/* yes */
+	btst	#0,%d6			/* is it early terminating? */
+	jbeq	1f			/* no */
+	jbsr	mmu_030_print_helper
+	jbra	38f
+1:	
+	jbsr	mmu_print_tuple_invalidate
+	jbra	38f
+31:	
+	movel	#0,%d1
+	andil	#0xfffffff0,%d6
+	movel	%d6,%a1
+32:
+	movel	%a4,%d5
+	addil	#PAGESIZE<<6,%d5
+	movel	%a1@+,%d6
+	btst	#1,%d6
+	jbne	33f
+	btst	#0,%d6
+	jbeq	1f			/* no */
+	jbsr	mmu_030_print_helper
+	jbra	37f
+1:	
+	jbsr	mmu_print_tuple_invalidate
+	jbra	37f
+33:		
+	movel	#0,%d2
+	andil	#0xfffffff0,%d6
+	movel	%d6,%a2
+34:	
+	movel	%a4,%d5
+	addil	#PAGESIZE,%d5
+	movel	%a2@+,%d6
+	btst	#0,%d6
+	jbne	35f
+	jbsr	mmu_print_tuple_invalidate
+	jbra	36f
+35:
+	jbsr	mmu_030_print_helper
+36:
+	movel	%d5,%a4
+	addq	#1,%d2
+	cmpib	#64,%d2
+	jbne	34b
+37:
+	movel	%d5,%a4
+	addq	#1,%d1
+	cmpib	#128,%d1
+	jbne	32b
+38:
+	movel	%d5,%a4			/* move to the next logical address */	
+	addq	#1,%d0
+	cmpib	#128,%d0
+	jbne	30b
+
+mmu_print_done:
+	putr()
+	putr()
+	
+	moveml	%sp@+,%a0-%a6/%d0-%d7
+	rts
+
+mmu_030_print_helper:
+	moveml	%d0-%d1,%sp@-
+	movel	%a4,%d0
+	movel	%d6,%d1
+	lea	%pc@(mmu_030_print_flags),%a6
+	jbsr	mmu_print_tuple
+	moveml	%sp@+,%d0-%d1
+	rts
+	
+mmu_print_tuple_invalidate:
+	moveml	%a0/%d7,%sp@-
+
+	lea	%pc@(Lmmu_print_data),%a0
+	tstl	%a0@(mmu_next_valid)
+	jbmi	mmu_print_tuple_invalidate_exit
+	
+	movel	#MMU_PRINT_INVALID,%a0@(mmu_next_valid)
+
+	movel	%a4,%d7
+	jbsr	Lserial_putnum
+	
+	puts("##")
+	putr()
+	
+mmu_print_tuple_invalidate_exit:
+	moveml	%sp@+,%a0/%d7
+	rts
+
+		
+mmu_print_tuple:
+	moveml	%d0-%d7/%a0,%sp@-
+
+	lea	%pc@(Lmmu_print_data),%a0
+	
+	tstl	%a0@(mmu_next_valid)
+	jbmi	mmu_print_tuple_print
+	jbeq	mmu_print_tuple_print
+	jbpl	mmu_print_tuple_test
+
+mmu_print_tuple_test:
+	cmpl	%a0@(mmu_next_physical),%d1
+	jbeq	mmu_print_tuple_increment
+	
+mmu_print_tuple_print:
+	movel	%d0,%d7
+	jbsr	Lserial_putnum
+	
+	puts("->")
+	
+	movel	%d1,%d7
+	jbsr	Lserial_putnum
+
+	movel	%d1,%d6
+	jbsr	%a6@
+	
+mmu_print_tuple_record:
+	movel	#MMU_PRINT_VALID,%a0@(mmu_next_valid)
+	
+	movel	%d1,%a0@(mmu_next_physical)
+
+mmu_print_tuple_increment:
+	movel	%d5,%d7
+	subl	%a4,%d7
+	addl	%d7,%a0@(mmu_next_physical)
+	
+mmu_print_tuple_exit:	
+	moveml	%sp@+,%d0-%d7/%a0
+	rts
+
+mmu_print_machine_cpu_types:
+	puts("machine: ")
+	
+	is_not_amiga(1f)
+	puts("amiga")
+	jbra	9f
+1:	
+	is_not_atari(2f)
+	puts("atari")
+	jbra	9f
+2:	
+	is_not_mac(3f)
+	puts("macintosh")
+	jbra	9f
+3:	puts("unknown")
+9:	putr()
+
+	puts("cputype: 0")		
+	is_not_060(1f)
+	putc('6')
+	jbra	9f
+1:	
+	is_not_040_or_060(2f)
+	putc('4')
+	jbra	9f
+2:	putc('3')
+9:	putc('0')
+	putr()
+		
+	rts
+#endif /* MMU_PRINT */
+
+/*
+ *	mmu_clear_root_table
+ *
+ *	%a5 = pointer to the root table
+ *	
+ *	This routine will clear out the kernel root table
+ *
+ *	The root table points to 128 pointer tables.  Because the
+ *	root table describes 32 bits of logical memory, (and there
+ *	are 7 bits of indexing in the root table) there is 25 bits
+ *	of logical address space described by each entry in the
+ *	root table.  2^25 is 32Meg, another way to look at that is
+ *	4Gig / 128 = 32Meg.  Any entry which does not have bit 1 set
+ *	is not a valid entry.  In that case, a reference into that
+ *	memory range will cause a memory exception (bus error).
+ *
+ */
+mmu_clear_root_table:
+	movel	%d0,%sp@-
+	
+	moveq	#ROOT_TABLE_SIZE-1,%d0
+1:	clrl	%a5@(%d0*4)
+	dbra	%d0,1b
+
+	movel	%sp@+,%d0
+	rts
+
+/*
+ *	mmu_clear_pointer_table
+ *
+ *	%a4 = pointer to a pointer table
+ *
+ *	This routine will clear out a pointer table.
+ *	It does NOT link the pointer table into the root table
+ *	(that linkage is done by mapping memory!)
+ */
+mmu_clear_pointer_table:	
+	movel	%d0,%sp@-
+	
+	moveq	#PTR_TABLE_SIZE-1,%d0
+1:	clrl	%a4@(%d0*4)
+	dbra	%d0,1b
+
+	movel	%sp@+,%d0
+	rts
+
+/*
+ *	mmu_clear_page_table
+ *
+ *	%a3 = pointer to a page table
+ *
+ *	This routine will clear out a page table.
+ *	It does NOT link the page table into the pointer table
+ *	(that linkage is done by mapping memory!)
+ */
+mmu_clear_page_table:	
+	movel	%d0,%sp@-
+	
+	moveq	#PAGE_TABLE_SIZE-1,%d0
+1:	clrl	%a3@(%d0*4)
+	dbra	%d0,1b
+
+	movel	%sp@+,%d0
+	rts
+
+/*
+ *	mmu_map
+ *
+ *	%a6 = address of free memory above kernel (page aligned)
+ *	%a5 = pointer to the root table
+ *	%a4 = pointer to a pointer table
+ *	%a1 = physical address of mapping
+ *	%a0 = logical address to map
+ *	%d1 = memory type
+ *	%d0 = length of the mapping
+ *
+ *	This routine will map a range of memory using a pointer
+ *	table and allocating the pages on the fly from the kernel.
+ *	The pointer table does not have to be already linked into
+ *	the root table, this routine will do that if necessary.
+ *
+ *	NOTE
+ *	This routine will assert failure and use the Lserial_putc
+ *	routines in the case of a run-time error.  For example,
+ *	if the address to be mapped requires two pointer tables
+ *	this routine will fail and the boot process will terminate.
+ *	A higher level routine would have to be written to call
+ *	this routine multiple times (with different parameters)
+ *	if a single mapping might straddle multiple pointer tables.
+ *
+ *	NOTE-2
+ *	This routine will use early terminating descriptors
+ *	where possible for the 68020+68851 and 68030 type
+ *	processors.
+ */
+mmu_map:
+	moveml	%d0-%d7/%a0-%a5,%sp@-
+
+	/* Calculate the offset in the root table 
+	 */
+	movel	MAP_LOG,%d5
+	andil	#0xfe000000,%d5
+	roll	#7,%d5
+
+	/* Calculate the offset in the pointer table 
+	 */
+	movel	MAP_LOG,%d4
+	andil	#0x01fc0000,%d4
+	lsrl	#2,%d4
+	swap	%d4
+	
+	/* Calculate the offset in the page table (used on 040's + 060's)
+	 */
+	movel	MAP_LOG,%d3
+	andil	#0x0003f000,%d3
+	lsll	#4,%d3
+	swap	%d3
+
+	/*
+	 *	The code that follows implements the following rules
+	 *	with respect to the pointer table for this memory mapping
+	 *	1) If the memory to be mapped lies within an already
+	 *	   mapped region, there will be a pointer table listed
+	 *	   in the root table.  This pointer table must be used.
+	 *	2) If the caller does not supply a pointer table, a table
+	 *	   will be allocated from above the kernel.
+	 *	3) Else, the caller must have passed the address to memory
+	 *	   that will be used as the pointer table for this mapping.
+	 */
+mmu_map_check_root_entry:
+	/* Is another pointer table already mapped into this root entry?
+	 */
+	movel	%a5@(%d5*4),%d2
+	jbeq	mmu_map_check_make_new_pointer_table
+
+	/* If there is an entry already, we must use it
+	 * to preserve existing MMU mapping data!
+	 */
+	andil	#_TABLE_MASK,%d2
+	movel	%d2,%a4
+	jbra	3f
+	
+mmu_map_check_make_new_pointer_table:	
+1:
+	/* Should we get a pointer table from memory on behalf of the caller?
+	 */
+	tstl	%a4
+	jbne	2f
+
+	jbsr	mmu_get_pointer_table
+
+2:
+	/* Put the pointer table into the root table
+	 */	
+	movel	%a4,%d2
+	orw	#_PAGE_TABLE+_PAGE_ACCESSED,%d2
+	movel	%d2,%a5@(%d5*4)
+
+3:
+#if defined(CONFIG_M68020) || defined(CONFIG_M68030)
+	/* Split up here, 030's have different logic than 040's
+	 */
+	
+	is_not_040_or_060(mmu_map_030)
+	
+#endif /* CONFIG_M68020 || CONFIG_M68030 */
+
+/*
+ *	MMU 040 & 060 Support
+ *
+ *	The MMU usage for the 040 and 060 is different enough from
+ *	the 030 and 68851 that there is separate code.  This comment
+ *	block describes the data structures and algorithms built by
+ *	this code.
+ *	
+ *	The 040 does not support early terminating descriptors, as
+ *	the 030 does.  Therefore, a third level of table is needed
+ *	for the 040, and that would be the page table.  In Linux,
+ *	page tables are allocated directly from the memory above the
+ *	kernel.  Register A6 points to the memory above kernel and
+ *	it is from that pool that page tables are allocated.
+ *	
+ *	For each page table that is allocated from above the kernel,
+ *	that page table's address has to be put into the pointer table.
+ *	Then, each page table has to be fully prepared.  Page tables,
+ *	by the way, describe a full 256K of memory.  That coincides with
+ *	the fact that a single entry in the pointer table describes
+ *	a 256K of memory because a pointer table entry points to a
+ *	complete page table.  There are 64 entries in the page table,
+ *	and each entry in the page table points to a physical page of
+ *	memory.  Each page is 4K.
+ *	
+ *	Also, there is a label "kpt" which holds the pointer to the
+ *	page table that describes the kernel.  This is only true on
+ *	the 040 and 060 cpu's.  This algorithm, because it's general
+ *	and allows the mapping of arbitrary regions of memory, assumes
+ *	that the first memory mapping is the one which maps the kernel.
+ *	So it's that page table that gets stored at kpt.
+ *	
+ *	Also, it is an error to attempt to map two regions that
+ *	fall within the same 256K range.  For that to work, this routine
+ *	would need to be modified.
+ *	
+ *	
+ *	Last:
+ *	This body of code is present even on 030 systems as this logic
+ *	is used when a block on an 030 machine is not large enough
+ *	to use an entire early terminating page descriptor.  (This
+ *	can happen on the Macintosh when the video begins life at
+ *	physical address 0.)
+ */
+mmu_map_040:
+	/* Enhance the physical address to make a valid page descriptor
+	 */
+	movel	MAP_PHYS,%d2
+	orw	#_PAGE_PRESENT,%d2
+	orw	MAP_CACHE,%d2
+	movel	%d2,MAP_PHYS
+
+	/* Convert address range length into # of pages
+	 */
+	movel	#PAGESHIFT,%d2
+	lsrl	%d2,MAP_LENGTH
+
+mmu_040_loop:
+	/* See if there is an existing page table pointer to use
+	 */
+	movel	%a4@(%d4*4),%d2
+	andil	#_TABLE_MASK,%d2
+	movel	%d2,%a3
+	tstl	%a3
+	jbne	mmu_fill_040_pagetable
+
+	jbsr	mmu_get_page_table
+
+	/* Now, begin assigning physical pages into the page table
+	 */
+mmu_fill_040_pagetable:
+	movel	MAP_PHYS,%a3@(%d3*4)
+
+	/* Decrement page count
+	 */
+	subq	#1,MAP_LENGTH
+	jbeq	mmu_map_done
+
+	/* Increase mapping addresses
+	 */
+	addl	#PAGESIZE,MAP_PHYS
+	addl	#PAGESIZE,MAP_LOG
+
+	/* Have we exhausted this page table?
+	 */
+	addq	#1,%d3
+	cmpil	#PAGE_TABLE_SIZE,%d3
+	jbne	mmu_fill_040_pagetable
+
+	/* Have we exhausted this pointer table?
+	 */
+	clrl	%d3
+	addq	#1,%d4
+	cmpil	#PTR_TABLE_SIZE,%d4
+	jbne	mmu_040_loop
+
+	/* We've exhausted this pointer table... get a new one
+	 */
+	jbsr	mmu_get_pointer_table
+	clrl	%d4	/* %d4 is ptr table index */
+	
+	jbra	mmu_040_loop
+
+/*
+ * mmu_map_revert
+ *
+ * Control gets here if mmu_map_040_tt is called and the conditions
+ * are not correct to employ tt translations.
+ */
+mmu_map_revert:
+	puts("MMU Note- attempting to use mmu_map_tt when not appropriate")
+	putr()
+	jbra	mmu_map
+
+/*
+ * mmu_map_tt
+ * 
+ * This is a specific function which works on all 680x0 machines.
+ * On 040 & 060 it will attempt to use Transparent Translation registers (tt1).
+ * On 020 & 030 it will call the standard mmu_map which will use early
+ * terminating descriptors.
+ */
+mmu_map_tt:
+	is_not_040_or_060(mmu_map)
+
+#if defined(CONFIG_M68040) || defined(CONFIG_M68060)
+mmu_map_040_tt:
+	moveml	%d0-%d7/%a0-%a4,%sp@-
+#if defined(DEBUG)
+	/*
+	 * Test for Transparent Translation working conditions
+	 */
+	cmpl	MAP_PHYS,MAP_LOG
+	jbne	mmu_map_revert
+
+	movel	MAP_PHYS,%d2
+	andil	#0x00ffffff,%d2
+	jbne	mmu_map_revert
+
+	/* Length must be a power of two
+	 */
+	movel	#0x01000000,%d2
+3:	
+	cmpl	%d2,MAP_LENGTH
+	jbeq	5f
+	lsll	#1,%d2
+	jbne	3b		/* Will terminate when %d2 == 0 */
+	
+	jbra	mmu_map_revert
+5:	
+#endif /* DEBUG */
+
+	subil	#0x01000000,MAP_LENGTH
+	lsrl	#8,MAP_LENGTH
+	movel	MAP_PHYS,%d2
+	orl	MAP_LENGTH,%d2
+	oriw	#0xa000,%d2	/* Enable | Supervisor Only */
+	orb	MAP_CACHE,%d2
+
+	.chip	68040
+	movec	%d2,%itt1
+	movec	%d2,%dtt1
+	.chip	68k
+
+	moveml	%sp@+,%d0-%d7/%a0-%a4
+	rts
+#endif /* CONFIG_M68040 || CONFIG_M68060) */
+
+#if defined(CONFIG_M68020) || defined(CONFIG_M68030)		
+mmu_map_030:
+	/*
+	 * If not a multiple of 256K, use page descriptors.
+	 */
+	movel	MAP_LENGTH,%d2
+	andl	#(PAGE_TABLE_SIZE*PAGESIZE)-1,%d2
+	jbne	mmu_map_040
+
+	/* Enhance the MMU mode to make an early terminating descriptor
+	 */
+	movel	MAP_PHYS,%d2
+	orw	#_PAGE_PRESENT,%d2
+	orw	MAP_CACHE,%d2
+	movel	%d2,MAP_PHYS
+
+	/* Convert # of pages into # of 256K entries
+	 */
+	movel	#PTR_INDEX_SHIFT,%d2
+	lsrl	%d2,MAP_LENGTH
+
+	cmpil	#PTR_TABLE_SIZE,MAP_LENGTH
+	jbcc	mmu_030_root_loop
+		
+	/* Since %a5 and %a4 point to a valid root table and
+	 * a valid pointer table, all we need to do is map.
+	 */
+mmu_030_ptr_loop:
+	/* Map logical to physical
+	 */
+	movel	MAP_PHYS,%a4@(%d4*4)
+
+	/* Decrement number of 256K chunks to map
+	 */
+	subq	#1,MAP_LENGTH
+	jbeq	mmu_map_done
+
+	/* Increment mapping addresses
+	 */
+	addl	#PAGE_TABLE_SIZE*PAGESIZE,MAP_LOG
+	addl	#PAGE_TABLE_SIZE*PAGESIZE,MAP_PHYS
+
+	/* Increment pointer table offset
+	 */
+	addq	#1,%d4
+	cmpl	#PTR_TABLE_SIZE,%d4
+	jbne	mmu_030_ptr_loop
+	
+	/* We've exhausted this pointer table... get a new one
+	 */
+	jbsr	mmu_get_pointer_table
+	clrl	%d4	/* ptr table index */
+	
+	jbra	mmu_030_ptr_loop
+
+mmu_030_root_loop:
+	/* Early terminating descriptor 32M entry
+	 */
+	movel	MAP_PHYS,%a5@(%d5*4)
+
+	/* Decrement number of 32M chunks to map
+	 */
+	subl	#PTR_TABLE_SIZE,MAP_LENGTH
+	jbeq	mmu_map_done
+	cmpl	#PTR_TABLE_SIZE,MAP_LENGTH
+	jbcs	mmu_030_ptr_loop
+
+	/* Increment mapping addresses
+	 */
+	addl	#PTR_TABLE_SIZE*PAGE_TABLE_SIZE*PAGESIZE,MAP_LOG
+	addl	#PTR_TABLE_SIZE*PAGE_TABLE_SIZE*PAGESIZE,MAP_PHYS
+	
+	/* Increment root table offset
+	 */
+	addq	#1,%d5
+	cmpl	#ROOT_TABLE_SIZE,%d5
+	jbne	mmu_030_root_loop
+#if defined(DEBUG)
+	/* We're trying to map past 0xFFFF.FFFF
+	 */
+	moveq	#7,%d7
+	jbra	mmu_err
+#endif /* DEBUG */
+#endif /* CONFIG_M68020 || CONFIG_M68030 */
+	
+mmu_map_done:
+	moveml	%sp@+,%d0-%d7/%a0-%a5
+	rts
+
+#if defined(DEBUG)
+mmu_err:
+	movel	%d7,%d3
+	putr()
+	puts("Error: ")
+
+	movel	%d3,%d7
+	jbsr	Lserial_putnum
+
+	puts("Logical Address #0x")
+	putn(MAP_LOG)
+	putr()
+
+	puts("Physical Address #0x")
+	putn(MAP_PHYS)
+	putr()
+
+	puts("Length #0x")
+	putn(MAP_LENGTH)
+	putr()
+
+
+	puts("Cache bits #0x")
+	putn(MAP_CACHE)
+	putr()
+
+#if defined(MMU_PRINT)
+	jbsr	mmu_print
+#endif
+	
+1:
+	jbra	1b
+#endif	/* DEBUG */
+
+/*
+ *	mmu_get_page_table
+ *	
+ *	This routine will get page table from above the kernel.
+ *	What's most interesting about this routine is that it is
+ *	capable of getting up to 16 page tables out of a page of
+ *	memory.  While this is the same algorithm used by the kernel
+ *	later on, it is also what is used down here.
+ */
+mmu_get_page_table:
+	moveml	%a0-%a2/%d0-%d2,%sp@-
+
+	/* Keep track of the number of pointer tables we use
+	 */
+	lea	%pc@(Lmmu_num_page_tables),%a2
+	addql	#1,%a2@
+	
+	/* See if there is a page table in our cache of page tables
+	 */
+	lea	%pc@(SYMBOL_NAME(Lmmu_cached_page_tables)),%a2
+	movel	%a2@,%d2
+	jbne	1f
+
+	/* The first time through this algorithm, we've got to get a page
+	 */
+	movel	%a6,%d2
+	addw	#PAGESIZE,%a6	/* allocate page for 16 page tables */
+
+1:	/* There is an unused page table in our cache... use it
+	 */
+	movel	%d2,%a3
+	addil	#PAGE_TABLE_SIZE*4,%d2
+	movel	%d2,%a2@
+
+	/* Basically this is (PAGESIZE-1)-(PAGE_TABLE_SIZE*4-1), but
+	 * the two -1 can be eliminated.
+	 * The condition is true if the current page table is at the
+	 * start of the next page. */
+	andil	#PAGESIZE-PAGE_TABLE_SIZE*4,%d2
+	jbne	2f
+
+	/* Get the page table from above the kernel memory
+	 */	
+	movel	%a6,%a2@
+	addw	#PAGESIZE,%a6	/* allocate page for 16 page tables */
+	
+2:
+	lea	%pc@(SYMBOL_NAME(kpt)),%a2
+	tstl	%a2@
+	jbne	3f
+	movel	%a3,%a2@
+	
+3:	jbsr	mmu_clear_page_table
+
+	/* Log this page table (%a3) in the pointer table (%a4)
+	 */
+	movel	%a3,%d2
+	orw	#_PAGE_TABLE+_PAGE_ACCESSED,%d2
+	movel	%d2,%a4@(%d4*4)
+	
+	moveml	%sp@+,%a0-%a2/%d0-%d2
+	rts
+	
+/*
+ *	mmu_get_pointer_table
+ *	
+ *	This routine will get page table from above the kernel.
+ *	What's most interesting about this routine is that it is
+ *	capable of getting up to 8 page tables out of a page of
+ *	memory.  While this is the same algorithm used by the kernel
+ *	later on, it is also what is used down here.
+ */
+mmu_get_pointer_table:
+	moveml	%a0-%a2/%d0-%d2,%sp@-
+
+	/* Keep track of the number of pointer tables we use
+	 */
+	lea	%pc@(Lmmu_num_pointer_tables),%a2
+	addql	#1,%a2@
+	
+	/* See if there is a pointer table in our cache of pointer tables
+	 */
+	lea	%pc@(Lmmu_cached_pointer_tables),%a2
+	movel	%a2@,%d2
+	jbne	1f
+
+	/* The first time through this algorithm, we've got to get a page
+	 */
+	movel	%a6,%d2
+	addw	#PAGESIZE,%a6	/* allocate page for 8 ptr tables */
+
+1:	/* There is an unused pointer table in our cache... use it
+	 */
+	movel	%d2,%a4
+	addil	#PTR_TABLE_SIZE*4,%d2
+	movel	%d2,%a2@
+
+	/* Did we just hand out the last ptr table in the cache page?
+	 */
+	andil	#PAGESIZE-PTR_TABLE_SIZE*4,%d2
+	jbne	2f
+
+	/* Get a new cache-of-ptr-tables page from above the kernel memory
+	 */	
+	movel	%a6,%a2@
+	addw	#PAGESIZE,%a6	/* allocate page for 8 ptr tables */
+2:
+	jbsr	mmu_clear_pointer_table
+
+	/* Log this pointer table (%a4) in the root table (%a5)
+	 */
+	movel	%a4,%d2
+	orw	#_PAGE_TABLE+_PAGE_ACCESSED,%d2
+	movel	%d2,%a5@(%d5*4)
+	
+	moveml	%sp@+,%a0-%a2/%d0-%d2
+	rts
+	
+
 /*
  * Debug output support
  * Atarians have a choice between the parallel port, the serial port
  * from the MFP or a serial port of the SCC
  */
 
-#ifdef CONFIG_ATARI
+#if defined(CONFIG_MAC)
+
+scc_initable_mac:
+	.byte	9,12		/* Reset */
+	.byte	4,0x44		/* x16, 1 stopbit, no parity */
+	.byte	3,0xc0		/* receiver: 8 bpc */
+	.byte	5,0xe2		/* transmitter: 8 bpc, assert dtr/rts */
+	.byte	9,0		/* no interrupts */
+	.byte	10,0		/* NRZ */
+	.byte	11,0x50		/* use baud rate generator */
+	.byte	12,10,13,0	/* 9600 baud */
+	.byte	14,1		/* Baud rate generator enable */
+	.byte	3,0xc1		/* enable receiver */
+	.byte	5,0xea		/* enable transmitter */
+	.byte	-1
+	.even
+#endif
+
+#if defined(CONFIG_ATARI)
 /* #define USE_PRINTER */
-/* #define USE_SCC */
+/* #define USE_SCC_B */
+/* #define USE_SCC_A */
 #define USE_MFP
 
-#ifdef USE_PRINTER
+#if defined(USE_SCC_A) || defined(USE_SCC_B)
+#define USE_SCC
+/* Initialisation table for SCC */
+scc_initable:
+	.byte	9,12		/* Reset */
+	.byte	4,0x44		/* x16, 1 stopbit, no parity */
+	.byte	3,0xc0		/* receiver: 8 bpc */
+	.byte	5,0xe2		/* transmitter: 8 bpc, assert dtr/rts */
+	.byte	9,0		/* no interrupts */
+	.byte	10,0		/* NRZ */
+	.byte	11,0x50		/* use baud rate generator */
+	.byte	12,24,13,0	/* 9600 baud */
+	.byte	14,2,14,3	/* use master clock for BRG, enable */
+	.byte	3,0xc1		/* enable receiver */
+	.byte	5,0xea		/* enable transmitter */
+	.byte	-1
+	.even
+#endif
+
+#if defined(USE_PRINTER)
 
 LPSG_SELECT	= 0xff8800
 LPSG_READ	= 0xff8800
@@ -1129,10 +2803,15 @@
 LSTMFP_DDR	= 0xfffa05
 LSTMFP_IERB	= 0xfffa09
 
-#elif defined(USE_SCC)
+#elif defined(USE_SCC_B)
  
-LSCC_CTRL_B	= 0xff8c85
-LSCC_DATA_B	= 0xff8c87
+LSCC_CTRL	= 0xff8c85
+LSCC_DATA	= 0xff8c87
+
+#elif defined(USE_SCC_A)
+
+LSCC_CTRL	= 0xff8c81
+LSCC_DATA	= 0xff8c83
 
 /* Initialisation table for SCC */
 scc_initable:
@@ -1159,45 +2838,54 @@
 LMFP_UDR     = 0xfffa2f
 
 #endif
-#endif
-
-#if defined (CONFIG_BVME6000)
-BVME_SCC_CTRL_A = 0xffb0000b
-BVME_SCC_DATA_A = 0xffb0000f
-#endif
+#endif	/* CONFIG_ATARI */
 
 /*
  * Serial port output support.
  */
-LSERPER		= 0xdff032
-LSERDAT		= 0xdff030
-LSERDATR	= 0xdff018
-LSERIAL_CNTRL	= 0xbfd000
-LSERIAL_DTR	= 7
+LSERPER      = 0xdff032
+LSERDAT      = 0xdff030
+LSERDATR     = 0xdff018
+LNTSC_PERIOD = 371
+LPAL_PERIOD  = 368
+LNTSC_ECLOCK = 7159090
+LSERIAL_CNTRL = 0xbfd000
+LSERIAL_DTR   = 7
 
 /*
  * Initialize serial port hardware for 9600/8/1
- * a0 thrashed
- * Amiga d0 trashed
- * Atari d0 trashed (a1 in case of SCC)
  */
 	.even
 Lserial_init:
+	/*
+ 	 *	Some of the register usage that follows
+	 *	CONFIG_AMIGA
+	 *		a0 = pointer to boot info record
+	 *		d0 = boot info offset
+	 *	CONFIG_ATARI
+	 *		a0 = address of SCC
+	 *		a1 = Liobase address/address of scc_initable
+	 *		d0 = init data for serial port
+	 *	CONFIG_MAC
+	 *		a0 = address of SCC
+	 *		a1 = address of scc_initable_mac
+	 *		d0 = init data for serial port
+	 */
+	moveml	%a0-%a1/%d0,%sp@-
+
 #ifdef CONFIG_AMIGA
-	cmpil	#MACH_AMIGA,%d4
-	jne	1f
-	bclr	#LSERIAL_DTR,LSERIAL_CNTRL
-	movew	#BI_AMIGA_SERPER,%d0
-	jbsr	Lget_bi_record
-	movew	%a0@,LSERPER
-	jra	9f
+	is_not_amiga(1f)
+        bclr    #LSERIAL_DTR,LSERIAL_CNTRL
+        movew   #BI_AMIGA_SERPER,%d0
+        jbsr    Lget_bi_record
+        movew   %a0@,LSERPER
+        jra     9f
 1:
 #endif
-#ifdef CONFIG_ATARI
-	cmpil   #MACH_ATARI,%d4
-	jne	4f
+#if defined(CONFIG_ATARI)
+	is_not_atari(4f)
 	movel	%pc@(Liobase),%a1
-#ifdef USE_PRINTER
+#if defined(USE_PRINTER)
 	bclr	#0,%a1@(LSTMFP_IERB)
 	bclr	#0,%a1@(LSTMFP_DDR)
 	moveb	#LPSG_CONTROL,%a1@(LPSG_SELECT)
@@ -1209,7 +2897,7 @@
 	bset	#5,%d0
 	moveb	%d0,%a1@(LPSG_WRITE)
 #elif defined(USE_SCC)
-	lea	%a1@(LSCC_CTRL_B),%a0
+	lea	%a1@(LSCC_CTRL),%a0
 	lea	%pc@(scc_initable:w),%a1
 2:	moveb	%a1@+,%d0
 	jmi	3f
@@ -1225,48 +2913,70 @@
 	orb	#1,%a1@(LMFP_TDCDR)
 	bset	#1,%a1@(LMFP_TSR)
 #endif
-4:
+	jra	9f
+4:	
 #endif
+#if defined(CONFIG_MAC)
+	is_not_mac(Lserial_init_not_mac)
+#ifdef MAC_SERIAL_DEBUG
+#if !defined(MAC_USE_SCC_A) && !defined(MAC_USE_SCC_B)
+#define MAC_USE_SCC_B
+#endif
+#define mac_scc_cha_b_ctrl_offset	0x0
+#define mac_scc_cha_a_ctrl_offset	0x2
+#define mac_scc_cha_b_data_offset	0x4
+#define mac_scc_cha_a_data_offset	0x6
+
+#ifdef MAC_USE_SCC_A
+	/* Initialize channel A */
+	movel	%pc@(SYMBOL_NAME(mac_sccbase)),%a0
+	lea	%pc@(scc_initable_mac:w),%a1
+5:	moveb	%a1@+,%d0
+	jmi	6f
+	moveb	%d0,%a0@(mac_scc_cha_a_ctrl_offset)
+	moveb	%a1@+,%a0@(mac_scc_cha_a_ctrl_offset)
+	jra	5b
+6:
+#endif	/* MAC_USE_SCC_A */
+
+#ifdef MAC_USE_SCC_B
+	/* Initialize channel B */
+#ifndef MAC_USE_SCC_A	/* Load mac_sccbase only if needed */
+	movel	%pc@(SYMBOL_NAME(mac_sccbase)),%a0
+#endif	/* MAC_USE_SCC_A */
+	lea	%pc@(scc_initable_mac:w),%a1
+7:	moveb	%a1@+,%d0
+	jmi	8f
+	moveb	%d0,%a0@(mac_scc_cha_b_ctrl_offset)
+	moveb	%a1@+,%a0@(mac_scc_cha_b_ctrl_offset)
+	jra	7b
+8:
+#endif	/* MAC_USE_SCC_B */
+#endif	/* MAC_SERIAL_DEBUG */
+
+	jra	9f
+Lserial_init_not_mac:
+#endif	/* CONFIG_MAC */
+
 9:
+ 	moveml	%sp@+,%a0-%a1/%d0
 	rts
 
-#ifdef CONFIG_HP300
-/* Set LEDs to %d7 */
-	.even
-Lset_leds:
-	moveml	%a0/%a1,%sp@-
-	movel	%pc@(Lcustom),%a1
-	moveb	%d7,%a1@(0x1ffff)
-	moveml	%sp@+,%a0/%a1
-	rts
-#endif
-	
 /*
  * Output character in d7 on serial port.
  * d7 thrashed.
  */
 Lserial_putc:
+	cmpib	#'\n',%d7
+	jbne	1f
+	
+	putc(13)	/* A little safe recursion is good for the soul */
+	moveb	#'\n',%d7
+1:	
 	moveml	%a0/%a1,%sp@-
-#if defined(CONFIG_MVME16x)
-	cmpil	#MACH_MVME16x,%d4
-	jne	2f
-	moveb	%d7,%sp@-
-	.long	0x4e4f0020
-	jra	9f
-2:
-#endif
-#ifdef CONFIG_BVME6000
-	cmpil	#MACH_BVME6000,%d4
-	jne	2f
-1:	btst	#2,BVME_SCC_CTRL_A
-	jeq	1b
-	moveb	%d7,BVME_SCC_DATA_A
-	jra	9f
-2:
-#endif
-#ifdef CONFIG_AMIGA
-	cmpil	#MACH_AMIGA,%d4
-	jne	2f
+
+#if defined(CONFIG_AMIGA)
+	is_not_amiga(2f)
 	andw	#0x00ff,%d7
 	oriw	#0x0100,%d7
 	movel	%pc@(Lcustom),%a1
@@ -1274,14 +2984,45 @@
 1:	movew	%a1@(LSERDATR),%d7
 	andw	#0x2000,%d7
 	jeq	1b
-	jra	9f
+	jra	Lserial_putc_done
 2:
 #endif
-#ifdef CONFIG_ATARI
-	cmpil   #MACH_ATARI,%d4
-	jne	4f
+
+#if defined(CONFIG_MAC)
+	is_not_mac(5f)
+
+#if defined(CONSOLE)
+	jbsr	Lconsole_putc
+#endif /* CONSOLE */
+
+#if defined(MAC_SERIAL_DEBUG)
+
+#ifdef MAC_USE_SCC_A
+	movel	%pc@(SYMBOL_NAME(mac_sccbase)),%a1
+3:	btst	#2,%a1@(mac_scc_cha_a_ctrl_offset)
+	jeq	3b
+	moveb	%d7,%a1@(mac_scc_cha_a_data_offset)
+#endif	/* MAC_USE_SCC_A */
+
+#ifdef MAC_USE_SCC_B
+#ifndef MAC_USE_SCC_A	/* Load mac_sccbase only if needed */
+	movel	%pc@(SYMBOL_NAME(mac_sccbase)),%a1
+#endif	/* MAC_USE_SCC_A */
+4:	btst	#2,%a1@(mac_scc_cha_b_ctrl_offset)
+	jeq	4b
+	moveb	%d7,%a1@(mac_scc_cha_b_data_offset)
+#endif	/* MAC_USE_SCC_B */
+
+#endif	/* MAC_SERIAL_DEBUG */
+
+	jra	Lserial_putc_done
+5:	
+#endif	/* CONFIG_MAC */
+
+#if defined(CONFIG_ATARI)
+	is_not_atari(4f)
 	movel	%pc@(Liobase),%a1
-#ifdef USE_PRINTER
+#if defined(USE_PRINTER)
 3:	btst	#0,%a1@(LSTMFP_GPIP)
 	jne	3b
 	moveb	#LPSG_IO_B,%a1@(LPSG_SELECT)
@@ -1295,17 +3036,45 @@
 	bset	#5,%d7
 	moveb	%d7,%a1@(LPSG_WRITE)
 #elif defined(USE_SCC)
-3:	btst	#2,%a1@(LSCC_CTRL_B)
+3:	btst	#2,%a1@(LSCC_CTRL)
 	jeq	3b
-	moveb	%d7,%a1@(LSCC_DATA_B)
+	moveb	%d7,%a1@(LSCC_DATA)
 #elif defined(USE_MFP)
 3:	btst	#7,%a1@(LMFP_TSR)
 	jeq	3b
 	moveb	%d7,%a1@(LMFP_UDR)
 #endif
+	jra	Lserial_putc_done
 4:
+#endif	/* CONFIG_ATARI */
+
+#if defined(CONFIG_MVME16x)
+	is_not_mvme16x(2f)
+	/*
+	 * The VME 16x class has PROM support for serial output
+	 * of some kind;  the TRAP table is still valid.
+	 */
+	moveml	%d0-%d7/%a2-%a6,%sp@-
+	moveb	%d7,%sp@-
+	.long	0x4e4f0020	/* TRAP 0x020 */
+	moveml	%sp@+,%d0-%d7/%a2-%a6
+	jbra	Lserial_putc_done
+2:
+#endif CONFIG_MVME162 | CONFIG_MVME167
+
+#if defined(CONFIG_BVME6000)
+	is_not_bvme6000(2f)
+	/*
+	 * The BVME6000 machine has a serial port ...
+	 */
+1:	btst	#2,BVME_SCC_CTRL_A
+	jeq	1b
+	moveb	%d7,BVME_SCC_DATA_A
+	jbra	Lserial_putc_done
+2:	
 #endif
-9:
+
+Lserial_putc_done:
 	moveml	%sp@+,%a0/%a1
 	rts
 
@@ -1346,28 +3115,557 @@
 	moveml	%sp@+,%d0-%d2/%d7
 	rts
 
+#if defined(CONFIG_MAC)
+/*
+ *	mac_serial_print
+ *
+ *	This routine takes its parameters on the stack.  It then
+ *	turns around and calls the internal routine.  This routine
+ *	is used until the Linux console driver initializes itself.
+ *
+ *	The calling parameters are:
+ *		void mac_serial_print(const char *str);
+ *
+ *	This routine does NOT understand variable arguments only
+ *	simple strings!
+ */
+ENTRY(mac_serial_print)
+	movel	%a0,%sp@-
+#if 1
+	move	%sr,%sp@-
+	ori	#0x0700,%sr
+#endif
+	movel	%sp@(10),%a0		/* fetch parameter */
+	jbsr	Lserial_puts
+#if 1
+	move	%sp@+,%sr
+#endif
+	movel	%sp@+,%a0
+	rts
+#endif /* CONFIG_MAC */
+
+#if defined(CONSOLE)
+/*
+ *	For continuity, see the data alignment
+ *	to which this structure is tied.
+ */
+#define Lconsole_struct_cur_column	0
+#define Lconsole_struct_cur_row		4
+#define Lconsole_struct_num_columns	8
+#define Lconsole_struct_num_rows	12
+#define Lconsole_struct_left_edge	16
+#define Lconsole_struct_penguin_putc	20
+
+Lconsole_init:
+	/*
+ 	 *	Some of the register usage that follows
+	 *		a0 = pointer to boot_info
+	 *		a1 = pointer to screen
+	 *		a2 = pointer to Lconsole_globals
+	 *		d3 = pixel width of screen
+	 *		d4 = pixel height of screen
+	 *		(d3,d4) ~= (x,y) of a point just below
+	 *			and to the right of the screen
+	 *			NOT on the screen!
+	 *		d5 = number of bytes per scan line
+	 *		d6 = number of bytes on the entire screen
+	 */
+	moveml	%a0-%a4/%d0-%d7,%sp@-
+	
+	lea	%pc@(SYMBOL_NAME(Lconsole_globals)),%a2
+	lea	%pc@(SYMBOL_NAME(mac_videobase)),%a0
+	movel	%a0@,%a1
+	lea	%pc@(SYMBOL_NAME(mac_rowbytes)),%a0
+	movel	%a0@,%d5
+	lea	%pc@(SYMBOL_NAME(mac_dimensions)),%a0
+	movel	%a0@,%d3	/* -> low byte */
+	movel	%d3,%d4
+	swap	%d4		/* -> high byte */
+	andl	#0xffff,%d3	/* d3 = screen width in pixels */
+	andl	#0xffff,%d4	/* d4 = screen height in pixels */
+
+	movel	%d5,%d6
+	subl	#20,%d6
+	mulul	%d4,%d6		/* scan line bytes x num scan lines */
+	divul	#8,%d6		/* we'll clear 8 bytes at a time */
+	subq	#1,%d6
+	
+console_clear_loop:
+	movel	#0xffffffff,%a1@+	/* Mac_black */
+	movel	#0xffffffff,%a1@+	/* Mac_black */
+	dbra	%d6,console_clear_loop
+
+	/* Calculate font size */
+
+#if   defined(FONT_8x8)
+	lea	%pc@(SYMBOL_NAME(font_vga_8x8)), %a0
+#elif defined(FONT_8x16)
+	lea	%pc@(SYMBOL_NAME(font_vga_8x16)),%a0
+#elif defined(FONT_6x11)
+	lea	%pc@(SYMBOL_NAME(font_vga_6x11)),%a0
+#else	/*   (FONT_8x8) default */
+	lea	%pc@(SYMBOL_NAME(font_vga_8x8)), %a0
+#endif
+
+	/*
+	 *	At this point we make a shift in register usage
+	 *	a1 = address of Lconsole_font pointer
+	 */
+	lea	%pc@(SYMBOL_NAME(Lconsole_font)),%a1
+	movel	%a0,%a1@	/* store pointer to struct fbcon_font_desc in Lconsole_font */
+
+	/*
+	 *	Calculate global maxs
+	 *	Note - we can use either an 
+	 *	8 x 16 or 8 x 8 character font
+	 *	6 x 11 also supported
+	 */
+		/* ASSERT: a0 = contents of Lconsole_font */
+	movel	%d3,%d0			/* screen width in pixels */
+	divul	%a0@(FBCON_FONT_DESC_width),%d0		/* d0 = max num chars per row */
+
+	movel	%d4,%d1			 /* screen height in pixels */
+	divul	%a0@(FBCON_FONT_DESC_height),%d1	 /* d1 = max num rows */
+
+	movel	%d0,%a2@(Lconsole_struct_num_columns)
+	movel	%d1,%a2@(Lconsole_struct_num_rows)
+
+	/*
+	 *	Clear the current row and column
+	 */
+	clrl	%a2@(Lconsole_struct_cur_column)
+	clrl	%a2@(Lconsole_struct_cur_row)
+	clrl	%a2@(Lconsole_struct_left_edge)
+
+	/*
+	 * Initialization is complete
+	 */
+	moveml	%sp@+,%a0-%a4/%d0-%d7
+	rts
+
+Lconsole_put_stats:
+	/*
+ 	 *	Some of the register usage that follows
+	 *		a0 = pointer to boot_info
+	 *		d7 = value of boot_info fields
+	 */
+	moveml	%a0/%d7,%sp@-
+
+	putr()
+	puts("MacLinux")
+	putr()
+	putr()
+
+#if defined(SERIAL_DEBUG)
+	puts(" vidaddr:")
+	lea	%pc@(SYMBOL_NAME(mac_videobase)),%a0
+	movel	%a0@,%d7			/* video addr. */
+	jbsr	Lserial_putnum			/* This redirects to console */
+	putr()
+
+	puts("  _stext:")
+	lea	%pc@(SYMBOL_NAME(_stext)),%a0
+	movel	%a0,%d7		/* get start addr. */
+	jbsr	Lserial_putnum
+	putr()
+
+	puts("bootinfo:")	
+	lea	%pc@(SYMBOL_NAME(_end)),%a0
+	movel	%a0, %d7	/* write start addr. */
+	jbsr	Lserial_putnum
+	putr()
+
+	puts("     kpt:")
+	lea	%pc@(SYMBOL_NAME(kpt)),%a0
+	movel	%a0,%d7		/* get start addr. */
+	jbsr	Lserial_putnum
+	putr()
+
+	puts("    *kpt:")
+	lea	%pc@(SYMBOL_NAME(kpt)),%a0
+	movel	%a0@,%d7	/* get start addr. */
+	jbsr	Lserial_putnum
+	putr()
+
+	puts("cpuid:")
+	lea	%pc@(SYMBOL_NAME(Lcputype)),%a0
+	movel	%a0@,%d7
+	jbsr	Lserial_putnum
+	putr()
+
+#  if defined(MMU_PRINT)
+	jbsr	mmu_print_machine_cpu_types
+#  endif /* MMU_PRINT */
+#endif /* SERIAL_DEBUG */
+	
+	moveml	%sp@+,%a0/%d7
+	rts
+
+#ifdef CONSOLE_PENGUIN
+Lconsole_put_penguin:
+	/*
+	 *	Get 'that_penguin' onto the screen in the upper right corner
+	 *	penguin is 64 x 74 pixels, align against right edge of screen
+	 */
+	moveml	%a0-%a1/%d0-%d7,%sp@-
+
+	lea	%pc@(SYMBOL_NAME(mac_dimensions)),%a0
+	movel	%a0@,%d0
+	andil	#0xffff,%d0
+	subil	#64,%d0		/* snug up against the right edge */
+	clrl	%d1		/* start at the top */
+	movel	#73,%d7
+	lea	%pc@(SYMBOL_NAME(that_penguin)),%a1
+console_penguin_row:
+	movel	#31,%d6
+console_penguin_pixel_pair:
+	moveb	%a1@,%d2
+	lsrb	#4,%d2
+	jbsr	console_plot_pixel
+	addq	#1,%d0
+	moveb	%a1@+,%d2
+	jbsr	console_plot_pixel
+	addq	#1,%d0
+	dbra	%d6,console_penguin_pixel_pair
+
+	subil	#64,%d0
+	addq	#1,%d1
+	dbra	%d7,console_penguin_row
+
+	moveml	%sp@+,%a0-%a1/%d0-%d7
+	rts
+#endif
+
+console_scroll:
+	moveml	%a0-%a4/%d0-%d7,%sp@-
+
+	/*
+	 * Calculate source and destination addresses
+	 *	output	a1 = dest
+	 *		a2 = source
+	 */	
+	lea	%pc@(SYMBOL_NAME(mac_videobase)),%a0
+	movel	%a0@,%a1
+	movel	%a1,%a2
+	lea	%pc@(SYMBOL_NAME(mac_rowbytes)),%a0
+	movel	%a0@,%d5
+	movel	%pc@(SYMBOL_NAME(Lconsole_font)),%a0
+	mulul	%a0@(FBCON_FONT_DESC_height),%d5	/* account for # scan lines per character */
+	addal	%d5,%a2
+
+	/*
+	 * Get dimensions
+	 */
+	lea	%pc@(SYMBOL_NAME(mac_dimensions)),%a0
+	movel	%a0@,%d3
+	movel	%d3,%d4
+	swap	%d4
+	andl	#0xffff,%d3	/* d3 = screen width in pixels */
+	andl	#0xffff,%d4	/* d4 = screen height in pixels */
+
+	/*
+	 * Calculate number of bytes to move
+	 */
+	lea	%pc@(SYMBOL_NAME(mac_rowbytes)),%a0
+	movel	%a0@,%d6
+	movel	%pc@(SYMBOL_NAME(Lconsole_font)),%a0
+	subl	%a0@(FBCON_FONT_DESC_height),%d4	/* we're not scrolling the top row! */
+	mulul	%d4,%d6		/* scan line bytes x num scan lines */
+	divul	#32,%d6		/* we'll move 8 longs at a time */
+	subq	#1,%d6
+	
+console_scroll_loop:
+	movel	%a2@+,%a1@+
+	movel	%a2@+,%a1@+
+	movel	%a2@+,%a1@+
+	movel	%a2@+,%a1@+
+	movel	%a2@+,%a1@+
+	movel	%a2@+,%a1@+
+	movel	%a2@+,%a1@+
+	movel	%a2@+,%a1@+
+	dbra	%d6,console_scroll_loop
+
+	lea	%pc@(SYMBOL_NAME(mac_rowbytes)),%a0
+	movel	%a0@,%d6
+	movel	%pc@(SYMBOL_NAME(Lconsole_font)),%a0
+	mulul	%a0@(FBCON_FONT_DESC_height),%d6	/* scan line bytes x font height */
+	divul	#32,%d6			/* we'll move 8 words at a time */
+	subq	#1,%d6
+
+	moveq	#-1,%d0
+console_scroll_clear_loop:
+	movel	%d0,%a1@+
+	movel	%d0,%a1@+
+	movel	%d0,%a1@+
+	movel	%d0,%a1@+
+	movel	%d0,%a1@+
+	movel	%d0,%a1@+
+	movel	%d0,%a1@+
+	movel	%d0,%a1@+
+	dbra	%d6,console_scroll_clear_loop
+	
+	moveml	%sp@+,%a0-%a4/%d0-%d7
+	rts
+	
+
+	
+Lconsole_putc:	
+/*
+ * Output character in d7 on console.
+ */
+	moveml	%a0/%a1/%d0-%d7,%sp@-
+	
+	lea	%pc@(Lconsole_globals),%a0
+
+	cmpib	#10,%d7
+	jne	console_not_lf
+	movel	%a0@(Lconsole_struct_cur_row),%d0
+	addil	#1,%d0
+	movel	%d0,%a0@(Lconsole_struct_cur_row)
+	movel	%a0@(Lconsole_struct_num_rows),%d1
+	cmpl	%d1,%d0
+	jcs	1f
+	subil	#1,%d0
+	movel	%d0,%a0@(Lconsole_struct_cur_row)
+	jbsr	console_scroll
+1:
+	jra	console_exit
+	
+console_not_lf:
+	cmpib	#13,%d7
+	jne	console_not_cr
+	clrl	%a0@(Lconsole_struct_cur_column)
+	jra	console_exit
+
+console_not_cr:
+	cmpib	#1,%d7
+	jne	console_not_home
+	clrl	%a0@(Lconsole_struct_cur_row)
+	clrl	%a0@(Lconsole_struct_cur_column)
+	jra	console_exit
+	
+/*
+ *	At this point we know that the %d7 character is going to be
+ *	rendered on the screen.  Register usage is -
+ *		a0 = pointer to console globals
+ *		a1 = font data
+ *		d0 = cursor column
+ *		d1 = cursor row to draw the character
+ *		d7 = character number
+ */
+console_not_home:
+	movel	%a0@(Lconsole_struct_cur_column),%d0
+	addil	#1,%a0@(Lconsole_struct_cur_column)
+	movel	%a0@(Lconsole_struct_num_columns),%d1	
+	cmpl	%d1,%d0
+	jcs	1f
+	movel	%d7,%sp@-
+	putr()		/* recursion is OK! */
+	movel	%sp@+,%d7
+1:	
+	movel	%a0@(Lconsole_struct_cur_row),%d1
+	
+	/*
+	 *	At this point we make a shift in register usage
+ 	 *	a0 = address of pointer to font data (fbcon_font_desc)
+	 */
+	movel	%pc@(SYMBOL_NAME(Lconsole_font)),%a0
+	movel	%a0@(FBCON_FONT_DESC_data),%a1	/* Load fbcon_font_desc.data into a1 */
+	andl	#0x000000ff,%d7
+		/* ASSERT: a0 = contents of Lconsole_font */
+	mulul	%a0@(FBCON_FONT_DESC_height),%d7	/* d7 = index into font data */
+	addl	%d7,%a1			/* a1 = points to char image */
+	
+	/*
+	 *	At this point we make a shift in register usage
+	 *	d0 = pixel coordinate, x
+	 *	d1 = pixel coordinate, y
+	 *	d2 = (bit 0) 1/0 for white/black (!) pixel on screen
+	 *	d3 = font scan line data (8 pixels)
+	 *	d6 = count down for the font's pixel width (8)
+	 *	d7 = count down for the font's pixel count in height
+	 */
+		/* ASSERT: a0 = contents of Lconsole_font */
+	mulul	%a0@(FBCON_FONT_DESC_width),%d0
+	mulul	%a0@(FBCON_FONT_DESC_height),%d1
+	movel	%a0@(FBCON_FONT_DESC_height),%d7	/* Load fbcon_font_desc.height into d7 */
+	subq	#1,%d7
+console_read_char_scanline:
+	moveb	%a1@+,%d3
+
+		/* ASSERT: a0 = contents of Lconsole_font */
+	movel	%a0@(FBCON_FONT_DESC_width),%d6	/* Load fbcon_font_desc.width into d6 */
+	subql	#1,%d6
+
+console_do_font_scanline:
+	lslb	#1,%d3
+	scsb	%d2		/* convert 1 bit into a byte */
+	jbsr	console_plot_pixel
+	addq	#1,%d0
+	dbra	%d6,console_do_font_scanline
+	
+		/* ASSERT: a0 = contents of Lconsole_font */
+	subl	%a0@(FBCON_FONT_DESC_width),%d0
+	addq	#1,%d1
+	dbra	%d7,console_read_char_scanline
+	
+console_exit:		
+	moveml	%sp@+,%a0/%a1/%d0-%d7
+	rts
+
+console_plot_pixel:
+	/*
+	 *	Input:
+	 *		d0 = x coordinate
+	 *		d1 = y coordinate
+	 *		d2 = (bit 0) 1/0 for white/black (!)
+	 *	All registers are preserved
+	 */
+	moveml	%a0-%a1/%d0-%d4,%sp@-
+	
+	lea	%pc@(SYMBOL_NAME(mac_videobase)),%a0
+	movel	%a0@,%a1
+	lea	%pc@(SYMBOL_NAME(mac_videodepth)),%a0
+	movel	%a0@,%d3
+	lea	%pc@(SYMBOL_NAME(mac_rowbytes)),%a0
+	mulul	%a0@,%d1
+
+	/*
+	 *	Register usage:
+	 *		d0 = x coord becomes byte offset into frame buffer
+	 *		d1 = y coord
+	 *		d2 = black or white (0/1)
+	 *		d3 = video depth
+	 *		d4 = temp of x (d0) for many bit depths
+	 *		d5 = unused
+	 *		d6 = unused
+	 *		d7 = unused
+	 */
+test_1bit:
+	cmpb	#1,%d3
+	jbne	test_2bit
+	movel	%d0,%d4		/* we need the low order 3 bits! */
+	divul	#8,%d0
+	addal	%d0,%a1
+	addal	%d1,%a1
+	andb	#7,%d4
+	eorb	#7,%d4		/* reverse the x-coordinate w/ screen-bit # */
+	andb	#1,%d2
+	jbne	white_1
+	bsetb	%d4,%a1@
+	jbra	console_plot_pixel_exit
+white_1:
+	bclrb	%d4,%a1@
+	jbra	console_plot_pixel_exit
+
+test_2bit:
+	cmpb	#2,%d3
+	jbne	test_4bit
+	movel	%d0,%d4		/* we need the low order 2 bits! */
+	divul	#4,%d0
+	addal	%d0,%a1
+	addal	%d1,%a1
+	andb	#3,%d4
+	eorb	#3,%d4		/* reverse the x-coordinate w/ screen-bit # */
+	lsll	#1,%d4		/* ! */
+	andb	#1,%d2
+	jbne	white_2
+	bsetb	%d4,%a1@
+	addq	#1,%d4
+	bsetb	%d4,%a1@
+	jbra	console_plot_pixel_exit
+white_2:
+	bclrb	%d4,%a1@
+	addq	#1,%d4
+	bclrb	%d4,%a1@
+	jbra	console_plot_pixel_exit
+
+test_4bit:
+	cmpb	#4,%d3
+	jbne	test_8bit
+	movel	%d0,%d4		/* we need the low order bit! */
+	divul	#2,%d0
+	addal	%d0,%a1
+	addal	%d1,%a1
+	andb	#1,%d4
+	eorb	#1,%d4
+	lsll	#2,%d4		/* ! */
+	andb	#1,%d2
+	jbne	white_4
+	bsetb	%d4,%a1@
+	addq	#1,%d4
+	bsetb	%d4,%a1@
+	addq	#1,%d4
+	bsetb	%d4,%a1@
+	addq	#1,%d4
+	bsetb	%d4,%a1@
+	jbra	console_plot_pixel_exit
+white_4:
+	bclrb	%d4,%a1@
+	addq	#1,%d4
+	bclrb	%d4,%a1@
+	addq	#1,%d4
+	bclrb	%d4,%a1@
+	addq	#1,%d4
+	bclrb	%d4,%a1@
+	jbra	console_plot_pixel_exit
+
+test_8bit:
+	cmpb	#8,%d3
+	jbne	test_16bit
+	addal	%d0,%a1
+	addal	%d1,%a1
+	andb	#1,%d2
+	jbne	white_8
+	moveb	#0xff,%a1@
+	jbra	console_plot_pixel_exit
+white_8:
+	clrb	%a1@
+	jbra	console_plot_pixel_exit
+
+test_16bit:
+	cmpb	#16,%d3
+	jbne	console_plot_pixel_exit
+	addal	%d0,%a1
+	addal	%d0,%a1
+	addal	%d1,%a1
+	andb	#1,%d2
+	jbne	white_16
+	clrw	%a1@
+	jbra	console_plot_pixel_exit
+white_16:
+	movew	#0x0fff,%a1@
+	jbra	console_plot_pixel_exit
+
+console_plot_pixel_exit:
+	moveml	%sp@+,%a0-%a1/%d0-%d4
+	rts
+#endif /* CONSOLE */
+
 #if 0
+/*
+ * This is some old code lying around.  I don't believe
+ * it's used or important anymore.  My guess is it contributed
+ * to getting to this point, but it's done for now.
+ * It was still in the 2.1.77 head.S, so it's still here.
+ * (And still not used!)
+ */
 Lshowtest:
 	moveml	%a0/%d7,%sp@-
-	putc('A')
-	putc('=')
+	puts("A=")
 	putn(%a1)
 
-	ptestr	#5,%a1@,#7,%a0
+	.long	0xf0119f15		| ptestr	#5,%a1@,#7,%a0
 
-	putc('D')
-	putc('A')
-	putc('=')
+	puts("DA=")
 	putn(%a0)
 
-	putc('D')
-	putc('=')
+	puts("D=")
 	putn(%a0@)
 
-	putc('S')
-	putc('=')
+	puts("S=")
 	lea	%pc@(Lmmu),%a0
-	pmove	%psr,%a0@
+	.long	0xf0106200		| pmove		%psr,%a0@
 	clrl	%d7
 	movew	%a0@,%d7
 	jbsr	Lserial_putnum
@@ -1375,13 +3673,92 @@
 	putr()
 	moveml	%sp@+,%a0/%d7
 	rts
-#endif
+#endif	/* 0 */
+	
 	.data
-	.even
+	.align	4
+	
+#if defined(CONFIG_ATARI) || defined(CONFIG_AMIGA)
 Lcustom:
 Liobase:
 	.long 0
-Lmmu:	.quad 0
+#endif
+
+#if defined(CONFIG_M68020) || defined(CONFIG_M68030)
+Lmmu:
+	.quad 0
+#endif
+
+#ifdef CONFIG_MAC
+Lconsole_video_virtual:
+	.long	0
+#endif	/* CONFIG_MAC */
+
+#if defined(CONSOLE)
+Lconsole_globals:
+	.long	0		/* cursor column */
+	.long	0		/* cursor row */
+	.long	0		/* max num columns */
+	.long	0		/* max num rows */
+	.long	0		/* left edge */
+	.long	0		/* mac putc */
+Lconsole_font:
+	.long	0		/* pointer to console font (struct fbcon_font_desc) */
+#endif /* CONSOLE */
+
+#if defined(MMU_PRINT)
+Lmmu_print_data:
+	.long	0		/* valid flag */
+	.long	0		/* start logical */
+	.long	0		/* next logical */
+	.long	0		/* start physical */
+	.long	0		/* next physical */
+#endif /* MMU_PRINT */
+
+Lcputype:
+	.long	0
+
+Lmmu_cached_page_tables:
+	.long	0
+
+Lmmu_cached_pointer_tables:
+	.long	0
+
+Lmmu_num_page_tables:
+	.long	0
+
+Lmmu_num_pointer_tables:
+	.long	0
+
+#if defined (CONFIG_BVME6000)
+BVME_SCC_CTRL_A	= 0xffb0000b
+BVME_SCC_DATA_A	= 0xffb0000f
+#endif
+
+#if 0
+#if defined(CONFIG_ATARI)
+SYMBOL_NAME_LABEL(atari_mch_type)
+	 .long 0
+#endif
+#endif
+
+#if defined(CONFIG_MAC)
+SYMBOL_NAME_LABEL(mac_booter_data)
+       .long 0
+SYMBOL_NAME_LABEL(mac_videobase)
+       .long 0
+SYMBOL_NAME_LABEL(mac_videodepth)
+       .long 0
+SYMBOL_NAME_LABEL(mac_dimensions)
+       .long 0
+SYMBOL_NAME_LABEL(mac_rowbytes)
+       .long 0
+#ifdef MAC_SERIAL_DEBUG
+SYMBOL_NAME_LABEL(mac_sccbase)
+       .long 0
+#endif /* MAC_SERIAL_DEBUG */
+#endif
+
 SYMBOL_NAME_LABEL(kpt)
 	.long 0
 SYMBOL_NAME_LABEL(availmem)
--- linux-2.1.131/arch/m68k/mac/config.c.org	Mon Dec 28 23:08:05 1998
+++ linux-2.1.131/arch/m68k/mac/config.c	Mon Dec 28 23:08:13 1998
@@ -423,7 +423,7 @@
 	 */
 
 	{	MAC_MODEL_CLII, "Classic II",		MAC_ADB_IISI,	MAC_VIA_IIci,	MAC_SCSI_OLD,	MAC_IDE_NONE,	MAC_SCC_II,     MAC_ETHER_NONE,	MAC_NUBUS},
-	{	MAC_MODEL_CCL,  "Color Classic",	MAC_ADB_IISI,	MAC_VIA_IIci,	MAC_SCSI_OLD,	MAC_IDE_NONE,	MAC_SCC_II,     MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_CCL,  "Color Classic",	MAC_ADB_CUDA,	MAC_VIA_IIci,	MAC_SCSI_OLD,	MAC_IDE_NONE,	MAC_SCC_II,     MAC_ETHER_NONE,	MAC_NUBUS},
 
 	/*
 	 *	Some Mac LC machines. Basically the same as the IIci, ADB like IIsi
@@ -475,8 +475,8 @@
 	 *	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_NONE,	MAC_NUBUS},
-	{	MAC_MODEL_C650, "Centris 650",   MAC_ADB_II,   MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	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},
 
 	/*
--- linux-2.1.131/arch/m68k/mac/debug.c.org	Mon Dec 28 23:08:44 1998
+++ linux-2.1.131/arch/m68k/mac/debug.c	Mon Dec 28 23:09:56 1998
@@ -397,14 +397,18 @@
 	/* Mac modem port */
 	mac_init_scc_port( B9600|CS8, 0 );
 	mac_console_driver.write = mac_scca_console_write;
+#ifdef CONFIG_SERIAL_CONSOLE
 	mac_console_driver.wait_key = mac_scca_console_wait_key;
+#endif
 	scc_port = 0;
     }
     else if (!strcmp( m68k_debug_device, "ser2" )) {
 	/* Mac printer port */
 	mac_init_scc_port( B9600|CS8, 1 );
 	mac_console_driver.write = mac_sccb_console_write;
+#ifdef CONFIG_SERIAL_CONSOLE
 	mac_console_driver.wait_key = mac_sccb_console_wait_key;
+#endif
 	scc_port = 1;
     }
 #endif
--- linux-2.1.131/arch/m68k/mac/macboing.c.org	Mon Dec 28 23:12:10 1998
+++ linux-2.1.131/arch/m68k/mac/macboing.c	Mon Dec 28 23:12:12 1998
@@ -1,6 +1,12 @@
 /*
  *	Mac bong noise generator. Note - we ought to put a boingy noise
  *	here 8)
+ *	 
+ *	----------------------------------------------------------------------
+ *	16.11.98:
+ *	rewrote some functions, added support for Enhanced ASC (Quadras)
+ *	after the NetBSD asc.c console bell patch by Colin Wood/Frederick Bruck
+ *	Juergen Mellinger (juergen.mellinger@t-online.de)
  */
 
 #include <linux/sched.h>
@@ -9,124 +15,281 @@
 #include <asm/macintosh.h>
 #include <asm/mac_asc.h>
 
+static int mac_asc_inited = 0;
+/*
+ * dumb triangular wave table
+ */
+static __u8 mac_asc_wave_tab[ 0x800 ];
+
+/*
+ * Alan's original sine table; needs interpolating to 0x800 
+ * (hint: interpolate or hardwire [0 -> Pi/2[, it's symmetric) 
+ */
 static const signed char sine_data[] = {
 	0,  39,  75,  103,  121,  127,  121,  103,  75,  39,
 	0, -39, -75, -103, -121, -127, -121, -103, -75, -39
 };
-#define DATA_SIZE	(sizeof(sine_data)/sizeof(sine_data[0]))
 
-static void nosound( unsigned long ignored );
-static struct timer_list sound_timer = { NULL, NULL, 0, 0, nosound };
+/*
+ * where the ASC hides ...
+ */
+static volatile __u8* mac_asc_regs = ( void* )0x50F14000;
 
-static volatile unsigned char *asc_base=(void *)0x50F14000;
+/* 
+ * sample rate; is this a good default value? 
+ */
+static unsigned long mac_asc_samplespersec = 11050;  
+static int mac_bell_duration = 0;
+static unsigned long mac_bell_phase; /* 0..2*Pi -> 0..0x800 (wavetable size) */
+static unsigned long mac_bell_phasepersample;
 
+/*
+ * some function protos 
+ */
+static void mac_init_asc( void );
+static void mac_nosound( unsigned long );
+static void mac_quadra_start_bell( unsigned int, unsigned int, unsigned int );
+static void mac_quadra_ring_bell( unsigned long );
+static void mac_av_start_bell( unsigned int, unsigned int, unsigned int );
+static void ( *mac_special_bell )( unsigned int, unsigned int, unsigned int ) = NULL;
+
+/*
+ * our timer to start/continue/stop the bell
+ */
+static struct timer_list mac_sound_timer = { NULL, NULL, 0, 0, mac_nosound };
 
-void mac_mksound( unsigned int hz, unsigned int ticks )
-{
-	static int inited = 0;
-	unsigned long flags;
-	int samples=512;
-
-	if (macintosh_config->ident == MAC_MODEL_C660
-	 || macintosh_config->ident == 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 
-		 * [678]100.  Because Singer and AWACS may have a similar hardware 
-		 * interface, this would imply that the code in drivers/sound/dmasound.c 
-		 * for AWACS could be used as a basis for Singer support.  All we have to
-		 * do is figure out how to do DMA on the 660AV/840AV through the PSC and 
-		 * figure out where the Singer hardware sits in memory. (I'd look in the
-		 * vicinity of the AWACS location in a Power Mac [678]100 first, or the 
-		 * current location of the Apple Sound Chip--ASC--in other Macs.)  The 
-		 * Power Mac [678]100 info can be found in MkLinux Mach kernel sources.
-		 *
-		 * Quoted from Apple's Tech Info Library, article number 16405:
-		 *   "Among desktop Macintosh computers, only the 660AV, 840AV, and Power
-		 *   Macintosh models have 16-bit audio input and output capability 
-		 *   because of the AT&T DSP3210 hardware circuitry and the 16-bit Singer
-		 *   codec circuitry in the AVs.  The Audio Waveform Amplifier and
-		 *   Converter (AWAC) chip in the Power Macintosh performs the same 
-		 *   16-bit I/O functionality.  The PowerBook 500 series computers
-		 *   support 16-bit stereo output, but only mono input."
-		 *
-		 *   http://til.info.apple.com/techinfo.nsf/artnum/n16405
-		 *
-		 * --David Kilzer
-		 */
+/*
+ * Sort of initialize the sound chip (called from mac_mksound on the first
+ * beep).
+ */
+static void mac_init_asc( void )
+{
+	int i;
+
+	/* 
+	 * do some machine specific initialization 
+	 * BTW:
+	 * the NetBSD Quadra patch identifies the Enhanced Apple Sound Chip via
+	 * 	mac_asc_regs[ 0x800 ] & 0xF0 != 0
+	 * this makes no sense here, because we have to set the default sample
+	 * rate anyway if we want correct frequencies
+	 */
+	switch ( macintosh_config->ident )
+	{
+		case MAC_MODEL_IIFX:
+			/*
+			 * The IIfx is always special ...
+			 */
+			mac_asc_regs = ( void* )0x50010000;
+			break;
+			/* 
+			 * not sure about how correct this list is 
+			 * machines with the EASC enhanced apple sound chip 
+			 */
+		case MAC_MODEL_Q630:
+		case MAC_MODEL_P475:
+			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!
+			 */
+			/*
+			 * 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 
+			 * [678]100.  Because Singer and AWACS may have a similar hardware 
+			 * interface, this would imply that the code in drivers/sound/dmasound.c 
+			 * for AWACS could be used as a basis for Singer support.  All we have to
+			 * do is figure out how to do DMA on the 660AV/840AV through the PSC and 
+			 * figure out where the Singer hardware sits in memory. (I'd look in the
+			 * vicinity of the AWACS location in a Power Mac [678]100 first, or the 
+			 * current location of the Apple Sound Chip--ASC--in other Macs.)  The 
+			 * Power Mac [678]100 info can be found in MkLinux Mach kernel sources.
+			 *
+			 * Quoted from Apple's Tech Info Library, article number 16405:
+			 *   "Among desktop Macintosh computers, only the 660AV, 840AV, and Power
+			 *   Macintosh models have 16-bit audio input and output capability
+			 *   because of the AT&T DSP3210 hardware circuitry and the 16-bit Singer
+			 *   codec circuitry in the AVs.  The Audio Waveform Amplifier and
+			 *   Converter (AWAC) chip in the Power Macintosh performs the same 
+			 *   16-bit I/O functionality.  The PowerBook 500 series computers
+			 *   support 16-bit stereo output, but only mono input."
+			 *
+			 *   http://til.info.apple.com/techinfo.nsf/artnum/n16405
+			 *
+			 * --David Kilzer
+			 */
+			mac_special_bell = mac_av_start_bell;
+			break;
+	}
+
+	/* 
+	 * init the wave table with a simple triangular wave 
+	 * A sine wave would sure be nicer here ...
+	 */
+	for ( i = 0; i < 0x400; i++ )
+	{
+		mac_asc_wave_tab[ i ] = i / 4;
+		mac_asc_wave_tab[ i + 0x400 ] = 0xFF - i / 4;
+	}
+	mac_asc_inited = 1;
+}	
 
+/*
+ * Called to make noise; current single entry to the boing driver. 
+ * Does the job for simple ASC, calls other routines else.
+ * XXX Fixme:
+ * Should be split into asc_mksound, easc_mksound, av_mksound and 
+ * function pointer set in mac_init_asc which would be called at 
+ * init time. 
+ * _This_ is rather ugly ...
+ */
+void mac_mksound( unsigned int freq, unsigned int length )
+{
+	__u32 cfreq = ( freq << 5 ) / 468;
+	__u32 flags;
+	int i;
+
+	if ( !mac_asc_inited )
+		mac_init_asc();
+
+	if ( mac_special_bell )
+	{
+		mac_special_bell( freq, length, 128 );
 		return;
 	}
-	
-	if(!inited)
+
+	if ( freq < 20 || freq > 20000 || length == 0 )
 	{
-		int i=0;
-		int j=0;
-		int k=0;
-		int l=0;
-
-		/*
-		 *	The IIfx strikes again!
-		 */
-		 
-		if(macintosh_config->ident==MAC_MODEL_IIFX)
-			asc_base=(void *)0x50010000;
+		mac_nosound( 0 );
+		return;
+	}
 
-		for(i=0;i<samples;i++)
-		{
-			asc_base[i]=sine_data[j];
-			asc_base[i+512]=sine_data[j];
-			asc_base[i+1024]=sine_data[j];
-			asc_base[i+1536]=sine_data[j];
-			j++;
-			if(j==DATA_SIZE)
-				j=0;
-			if(i&1)
-				k++;
-			if(k==DATA_SIZE)
-				k=0;
-			if((i&3)==3)
-				l++;
-			if(l==DATA_SIZE)
-				l=0;	
-		}
-		inited=1;
+	save_flags( flags );
+	cli();
+
+	del_timer( &mac_sound_timer );
+
+	for ( i = 0; i < 0x800; i++ )
+		mac_asc_regs[ i ] = 0;	
+	for ( i = 0; i < 0x800; i++ )
+		mac_asc_regs[ i ] = mac_asc_wave_tab[ i ];
+
+	for ( i = 0; i < 8; i++ )
+		*( __u32* )( ( __u32 )mac_asc_regs + ASC_CONTROL + 0x814 + 8 * i ) = cfreq;
+
+	mac_asc_regs[ 0x807 ] = 0;
+	mac_asc_regs[ ASC_VOLUME ] = 128;
+	mac_asc_regs[ 0x805 ] = 0;
+	mac_asc_regs[ 0x80F ] = 0;
+	mac_asc_regs[ ASC_MODE ] = ASC_MODE_SAMPLE;
+	mac_asc_regs[ ASC_ENABLE ] = ASC_ENABLE_SAMPLE;
+
+	mac_sound_timer.expires = jiffies + length;
+	add_timer( &mac_sound_timer );
+
+	restore_flags( flags );	
+}
+
+/*
+ * regular ASC: stop whining ..
+ */
+static void mac_nosound( unsigned long ignored )
+{
+	mac_asc_regs[ ASC_ENABLE ] = 0;
+}	
+
+/*
+ * EASC entry; init EASC, don't load wavetable, schedule 'start whining'.
+ */
+static void mac_quadra_start_bell( unsigned int freq, unsigned int length, unsigned int volume )
+{
+	__u32 flags;
+
+	/* if the bell is already ringing, ring longer */
+	if ( mac_bell_duration > 0 )
+	{
+		mac_bell_duration += length;
+		return;
 	}
-	save_flags(flags);
+
+	mac_bell_duration = length;
+	mac_bell_phase = 0;
+	mac_bell_phasepersample = ( freq * sizeof( mac_asc_wave_tab ) ) / mac_asc_samplespersec;
+	/* this is reasonably big for small frequencies */ 
+
+	save_flags( flags );
 	cli();
-	del_timer( &sound_timer );
 
-	if (hz > 20 && hz < 32767) {
-		int i;
-		u_long asc_pulses=((hz<<5)*samples)/468;
-		for(i=0;i<4;i++)
+	/* set the volume */
+	mac_asc_regs[ 0x806 ] = volume;
+
+	/* set up the ASC registers */
+	if ( mac_asc_regs[ 0x801 ] != 1 )
+	{
+		/* select mono mode */	
+		mac_asc_regs[ 0x807 ] = 0;
+		/* select sampled sound mode */
+		mac_asc_regs[ 0x802 ] = 0;
+	 	/* ??? */	
+		mac_asc_regs[ 0x801 ] = 1;
+		mac_asc_regs[ 0x803 ] |= 0x80;
+		mac_asc_regs[ 0x803 ] &= 0x7F;
+	}
+
+	mac_sound_timer.function = mac_quadra_ring_bell;
+	mac_sound_timer.expires = jiffies + 1;
+	add_timer( &mac_sound_timer );
+
+	restore_flags( flags );
+}
+
+/*
+ * EASC 'start/continue whining'; I'm not sure why the above function didn't
+ * already load the wave table, or at least call this one... 
+ * This piece keeps reloading the wave table until done.
+ */
+static void mac_quadra_ring_bell( unsigned long ignored )
+{
+	int 	i, count = mac_asc_samplespersec / HZ;
+	__u32 flags;
+
+	/*
+	 * we neither want a sound buffer overflow nor underflow, so we need to match
+	 * the number of samples per timer interrupt as exactly as possible.
+	 * using the asc interrupt will give better results in the future
+	 * ...and the possibility to use a real sample (a boingy noise, maybe...)
+	 */
+
+	save_flags( flags );
+	cli();
+	
+	del_timer( &mac_sound_timer );
+
+	if ( mac_bell_duration-- > 0 )
+	{
+		for ( i = 0; i < count; i++ )
 		{
-			asc_base[ASC_FREQ(i,0)]=0x00;
-			asc_base[ASC_FREQ(i,1)]=20;
-			asc_base[ASC_FREQ(i,2)]=0x00;
-			asc_base[ASC_FREQ(i,3)]=20;
-			asc_base[ASC_FREQ(i,4)]=(asc_pulses>>24)&0xFF;
-			asc_base[ASC_FREQ(i,5)]=(asc_pulses>>16)&0xFF;
-			asc_base[ASC_FREQ(i,6)]=(asc_pulses>>8)&0xFF;
-			asc_base[ASC_FREQ(i,7)]=(asc_pulses>>0)&0xFF;
-		}
-		asc_base[ASC_CHAN]=0x03;
-		asc_base[ASC_VOLUME]=128;
-		asc_base[ASC_MODE]=ASC_MODE_SAMPLE;
-		asc_base[ASC_ENABLE]=ASC_ENABLE_SAMPLE;
-		if (ticks) {
-			sound_timer.expires = jiffies + ticks;
-			add_timer( &sound_timer );
+			mac_bell_phase += mac_bell_phasepersample;
+			mac_asc_regs[ 0 ] = mac_asc_wave_tab[ mac_bell_phase & ( sizeof( mac_asc_wave_tab ) - 1 ) ];
 		}
-	} else {
-		nosound( 0 );
+		mac_sound_timer.expires = jiffies + 1;
+		add_timer( &mac_sound_timer );
 	}
-	restore_flags(flags);
+	else
+		mac_asc_regs[ 0x801 ] = 0;
+	
+	restore_flags( flags );
 }
 
-
-static void nosound( unsigned long ignored )
+/*
+ * AV code - please fill in.
+ */
+static void mac_av_start_bell( unsigned int freq, unsigned int length, unsigned int volume )
 {
-	asc_base[ASC_ENABLE]=0;
-}	
+} 
--- linux-2.1.131/arch/m68k/mac/macints.c.org	Mon Dec 28 23:12:31 1998
+++ linux-2.1.131/arch/m68k/mac/macints.c	Mon Dec 28 23:15:54 1998
@@ -163,6 +163,13 @@
 static unsigned long *mac_irqs[8];
 
 /*
+ * Some special nutcases ...
+ */
+
+static unsigned long mac_ide_irqs = 0;
+static unsigned long nubus_stuck_events = 0;
+
+/*
  * VIA/RBV/OSS/PSC register base pointers
  */
 
@@ -217,9 +224,13 @@
 static void via_do_nubus(int slot, void *via, struct pt_regs *regs);
 
 /* #define DEBUG_MACINTS */
-/* #define DEBUG_NUBUS_INT */
+
+#define DEBUG_SPURIOUS
+#define DEBUG_NUBUS_SPURIOUS
+#define DEBUG_NUBUS_INT
+
 /* #define DEBUG_VIA */
-/* #define DEBUG_VIA_NUBUS */
+#define DEBUG_VIA_NUBUS
 
 void mac_init_IRQ(void)
 {
@@ -351,6 +362,12 @@
 	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
@@ -430,8 +447,10 @@
 		return 0;
 	} 
 
-	/* add similar hack for Nubus pseudo-irq here - hide nubus_request_irq */
-
+	/* 
+	 * 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;
@@ -697,12 +716,18 @@
 	return (pending);
 }
 
+/*
+ * for /proc/interrupts: log interrupt stats broken down by 
+ * autovector int first, then by actual interrupt source.
+ */
+
 int mac_get_irq_list (char *buf)
 {
 	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);
 
@@ -767,6 +792,32 @@
 	}
 	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);
+
+	}
+	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;
 }
 
@@ -787,8 +838,9 @@
 
 void mac_default_handler(int irq, void *dev_id, struct pt_regs *regs)
 {
-#ifdef DEBUG_VIA
-	printk("Unexpected IRQ %d on device %p\n", irq, dev_id);
+#ifdef DEBUG_SPURIOUS
+	if (console_loglevel > 6)
+		printk("Unexpected IRQ %d on device %p\n", irq, dev_id);
 #endif
 }
 
@@ -864,6 +916,18 @@
 }
 
 /*
+ *	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 ...
@@ -1118,17 +1182,6 @@
 }
 
 /*
- *	Unexpected via interrupt
- */
- 
-void via_wtf(int slot, void *via, struct pt_regs *regs)
-{
-#ifdef DEBUG_VIA
-	printk("Unexpected event %d on via %p\n",slot,via);
-#endif
-}
-
-/*
  *	Nubus / SCSI interrupts; OSS style
  *	The OSS is even more different than the RBV. OSS appears to stand for 
  *	Obscenely Screwed Silicon ... 
@@ -1267,8 +1320,9 @@
  
 void nubus_wtf(int slot, void *via, struct pt_regs *regs)
 {
-#ifdef DEBUG_VIA_NUBUS
-	printk("Unexpected interrupt on nubus slot %d\n",slot);
+#ifdef DEBUG_NUBUS_SPURIOUS
+	if (console_loglevel > 6)
+		printk("Unexpected interrupt on nubus slot %d\n",slot);
 #endif
 }
 
@@ -1282,9 +1336,10 @@
 	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)
+		if (scc_handler[i].handler != mac_default_handler) {
 			(scc_handler[i].handler)(i, scc_handler[i].dev_id, regs);
-
+			scc_irqs[i]++;
+		}
 }
 
 /*
@@ -1426,6 +1481,7 @@
 	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;
@@ -1475,6 +1531,7 @@
  * IDE interrupt hook
  */
 extern void (*mac_ide_intr_hook)(int, void *, struct pt_regs *);
+extern int (*mac_ide_irq_p_hook)(void);
 #endif
 
 /*
@@ -1482,13 +1539,13 @@
  */
 static void via_do_nubus(int slot, void *via, struct pt_regs *regs)
 {
-	unsigned char map;
+	unsigned char map, allints;
 	int i;
 	int ct=0;
-
-/*	printk("nubus interrupt\n");*/
+	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
@@ -1496,37 +1553,69 @@
 	
 #ifdef CONFIG_BLK_DEV_MAC_IDE
 	/* IDE hack */
-	if (mac_ide_intr_hook)
+	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)
-			map = ~via_read(rbv_regp, rBufA);
+			allints = ~via_read(rbv_regp, rBufA);
 		else
-			map = ~via_read(via2_regp, vBufA);
+			allints = ~via_read(via2_regp, vBufA);
 		
-#ifdef DEBUG_NUBUS_INT
-		printk("nubus_irq: map %x mask %x\n", map, nubus_active);
+#ifdef CONFIG_BLK_DEV_MAC_IDE
+		if (mac_ide_irq_p_hook)
+			ide_pending = mac_ide_irq_p_hook();
 #endif
 
-		if( (map = (map&nubus_active)) ==0 ) {
-#ifdef DEBUG_NUBUS_INT
-			printk("nubus_irq: nothing pending, map %x mask %x\n", 
-				map, nubus_active);
+		if ( (map = (allints&nubus_active)) == 0 
+#ifdef CONFIG_BLK_DEV_MAC_IDE
+		      && !ide_pending 
 #endif
-			nubus_irqs[7]++;
+							) 
+		{
+			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)
 		{
-#ifdef DEBUG_NUBUS_INT
-			printk("nubus stuck events - %d/%d\n", map, nubus_active);
-#endif
+			if (console_loglevel > 5)
+				printk("nubus stuck events - %x/%x/%x ide %x\n", 
+				allints, nubus_active, map, ide_pending);
+			nubus_stuck_events++;
+
 			return;
 		}
 
@@ -1583,12 +1672,14 @@
 		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);
+				if (!mac_ide_intr_hook)
+					printk("nubus_irq: nothing pending, map %x mask %x\n", 
+						map, nubus_active);
 #endif
-			nubus_irqs[7]++;
+				nubus_irqs[7]++;
+			}
 			break;
 		}
 
--- linux-2.1.131/arch/m68k/config.in.org	Wed Dec 30 00:21:49 1998
+++ linux-2.1.131/arch/m68k/config.in	Wed Dec 30 00:22:31 1998
@@ -221,8 +221,8 @@
 fi
 if [ "$CONFIG_MAC" = "y" ]; then
   bool 'Mac NS 8390 based ethernet cards' CONFIG_DAYNAPORT
-  bool 'AV Macintosh onboard MACE ethernet' CONFIG_MACMACE
-  bool 'Macintosh onboard SONIC ethernet' CONFIG_MACSONIC
+#  bool 'Macintosh (AV) onboard MACE ethernet' CONFIG_MACMACE
+  bool 'Macintosh (Quadra) onboard SONIC ethernet' CONFIG_MACSONIC
 fi
 if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME16x" = "y" ]; then
   tristate 'MVME16x Ethernet support' CONFIG_MVME16x_NET
--- linux-2.1.131/drivers/block/macide.c.org	Tue Dec 29 00:07:54 1998
+++ linux-2.1.131/drivers/block/macide.c	Tue Dec 29 00:08:04 1998
@@ -104,6 +104,24 @@
 	ide_intr(mac_hwif->irq, mac_hwif->hwgroup, regs);
 }
 
+	/*
+	 * Seems we need this for the Quadra 630 to make sure IDE interrupts
+	 * aren't lost while we were processing other slot interrupts :-(
+	 */
+
+int (*mac_ide_irq_p_hook)(void) = NULL;
+
+int mac_ide_irq_p (void)
+{
+	unsigned char ch;
+	ide_hwif_t *hwif = mac_hwif;
+
+	ch = inb(hwif->io_ports[IDE_IRQ_OFFSET]);
+	if (!(ch & 0x20))
+		return 0;
+	return 1;
+}
+
     /*
      *  Check the interrupt status
      *
--- linux-2.1.131/drivers/net/sonic.c.org	Thu Jul 30 12:03:45 1998
+++ linux-2.1.131/drivers/net/sonic.c	Wed Dec 30 00:04:07 1998
@@ -8,9 +8,8 @@
  * 
  * (C) 1995 by Andreas Busse (andy@waldorf-gmbh.de)
  *
- * A driver for the onboard Sonic ethernet controller on Mips Jazz
- * systems (Acer Pica-61, Mips Magnum 4000, Olivetti M700 and
- * perhaps others, too)
+ *
+ *	Core code included by system sonic drivers
  */
 
 static const char *version =
@@ -22,269 +21,7 @@
  * controller, and the files "8390.c" and "skeleton.c" in this directory.
  */
 
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ptrace.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/malloc.h>
-#include <linux/string.h>
-#include <linux/delay.h>
-#include <asm/bootinfo.h>
-#include <asm/system.h>
-#include <asm/bitops.h>
-#include <asm/pgtable.h>
-#include <asm/segment.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/jazz.h>
-#include <asm/jazzdma.h>
-#include <linux/errno.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-
-#include "sonic.h"
-
-/* use 0 for production, 1 for verification, >2 for debug */
-#ifdef SONIC_DEBUG
-static unsigned int sonic_debug = SONIC_DEBUG;
-#else 
-static unsigned int sonic_debug = 2;
-#endif
-
-/*
- * Some tunables for the buffer areas. Power of 2 is required
- * the current driver uses one receive buffer for each descriptor.
- */
-#define SONIC_NUM_RRS    16             /* number of receive resources */
-#define SONIC_NUM_RDS    SONIC_NUM_RRS  /* number of receive descriptors */
-#define SONIC_NUM_TDS    16      /* number of transmit descriptors */
-#define SONIC_RBSIZE   1520      /* size of one resource buffer */
 
-#define SONIC_RDS_MASK   (SONIC_NUM_RDS-1)
-#define SONIC_TDS_MASK   (SONIC_NUM_TDS-1)
-
-/*
- * Base address and interupt of the SONIC controller on JAZZ boards
- */
-static struct {
-    unsigned int port;
-    unsigned int irq;
-    } sonic_portlist[] = { {JAZZ_ETHERNET_BASE, JAZZ_ETHERNET_IRQ}, {0, 0}};
-
-
-/* Information that need to be kept for each board. */
-struct sonic_local {
-    sonic_cda_t   cda;                     /* virtual CPU address of CDA */
-    sonic_td_t    tda[SONIC_NUM_TDS];      /* transmit descriptor area */
-    sonic_rr_t    rra[SONIC_NUM_RRS];      /* receive resource arrea */
-    sonic_rd_t    rda[SONIC_NUM_RDS];      /* receive descriptor area */
-    struct sk_buff* tx_skb[SONIC_NUM_TDS]; /* skbuffs for packets to transmit */
-    unsigned int  tx_laddr[SONIC_NUM_TDS]; /* logical DMA address fro skbuffs */
-    unsigned char *rba;                    /* start of receive buffer areas */    
-    unsigned int  cda_laddr;               /* logical DMA address of CDA */    
-    unsigned int  tda_laddr;               /* logical DMA address of TDA */
-    unsigned int  rra_laddr;               /* logical DMA address of RRA */    
-    unsigned int  rda_laddr;               /* logical DMA address of RDA */
-    unsigned int  rba_laddr;               /* logical DMA address of RBA */
-    unsigned int  cur_tx, cur_rx;          /* current indexes to resource areas */
-    unsigned int  dirty_tx,cur_rra;        /* last unacked transmit packet */
-    char tx_full;
-    struct enet_statistics stats;
-};
-
-/*
- * We cannot use station (ethernet) address prefixes to detect the
- * sonic controller since these are board manufacturer depended.
- * So we check for known Silicon Revision IDs instead. 
- */
-static unsigned short known_revisions[] =
-{
-  0x04,				/* Mips Magnum 4000 */
-  0xffff			/* end of list */
-};
-
-/* Index to functions, as function prototypes. */
-
-extern int sonic_probe(struct device *dev);
-static int sonic_probe1(struct device *dev, unsigned int base_addr, unsigned int irq);
-static int sonic_open(struct device *dev);
-static int sonic_send_packet(struct sk_buff *skb, struct device *dev);
-static void sonic_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static void sonic_rx(struct device *dev);
-static int sonic_close(struct device *dev);
-static struct enet_statistics *sonic_get_stats(struct device *dev);
-static void sonic_multicast_list(struct device *dev);
-static int sonic_init(struct device *dev);
-
-
-/*
- * Probe for a SONIC ethernet controller on a Mips Jazz board.
- * Actually probing is superfluous but we're paranoid.
- */
-__initfunc(int sonic_probe(struct device *dev))
-{
-    unsigned int base_addr = dev ? dev->base_addr : 0;
-    int i;
-
-    /*
-     * Don't probe if we're not running on a Jazz board.
-     */
-    if (mips_machgroup != MACH_GROUP_JAZZ)
-	return -ENODEV;
-    if (base_addr > 0x1ff)	/* Check a single specified location. */
-	return sonic_probe1(dev, base_addr, dev->irq);
-    else if (base_addr != 0)	/* Don't probe at all. */
-	return -ENXIO;
-    
-    for (i = 0; sonic_portlist[i].port; i++) {
-	int base_addr = sonic_portlist[i].port;
-	if (check_region(base_addr, 0x100))
-	    continue;
-	if (sonic_probe1(dev, base_addr, sonic_portlist[i].irq) == 0)
-	    return 0;
-    }
-    return -ENODEV;
-}
-
-__initfunc(static int sonic_probe1(struct device *dev,
-                                   unsigned int base_addr, unsigned int irq))
-{
-    static unsigned version_printed = 0;
-    unsigned int silicon_revision;
-    unsigned int val;
-    struct sonic_local *lp;
-    int i;
-    
-    /*
-     * get the Silicon Revision ID. If this is one of the known
-     * one assume that we found a SONIC ethernet controller at
-     * the expected location.
-     */
-    silicon_revision = SONIC_READ(SONIC_SR);
-    if (sonic_debug > 1)
-      printk("SONIC Silicon Revision = 0x%04x\n",silicon_revision);
-
-    i = 0;
-    while ((known_revisions[i] != 0xffff) &&
-	   (known_revisions[i] != silicon_revision))
-      i++;
-	
-    if (known_revisions[i] == 0xffff) {
-	printk("SONIC ethernet controller not found (0x%4x)\n",
-	       silicon_revision);
-	return -ENODEV;
-    }
-    
-    request_region(base_addr, 0x100, "SONIC");
-    
-    /* Allocate a new 'dev' if needed. */
-    if (dev == NULL)
-      dev = init_etherdev(0, sizeof(struct sonic_local));
-
-    if (sonic_debug  &&  version_printed++ == 0)
-      printk(version);
-
-    printk("%s: %s found at 0x%08x, ",
-	   dev->name, "SONIC ethernet", base_addr);
-
-    /* Fill in the 'dev' fields. */
-    dev->base_addr = base_addr;
-    dev->irq = irq;
-
-    /*
-     * Put the sonic into software reset, then
-     * retrieve and print the ethernet address.
-     */
-    SONIC_WRITE(SONIC_CMD,SONIC_CR_RST);
-    SONIC_WRITE(SONIC_CEP,0);
-    for (i=0; i<3; i++) {
-	val = SONIC_READ(SONIC_CAP0-i);
-	dev->dev_addr[i*2] = val;
-	dev->dev_addr[i*2+1] = val >> 8;
-    }
-
-    printk("HW Address ");
-    for (i = 0; i < 6; i++) {
-	printk("%2.2x", dev->dev_addr[i]);
-	if (i<5)
-	  printk(":");
-    }
-    
-    printk(" IRQ %d\n", irq);
-    
-    /* Initialize the device structure. */
-    if (dev->priv == NULL) {
-	/*
-	 * the memory be located in the same 64kb segment
-	 */
-	lp = NULL;
-	i = 0;
-	do {
-	    lp = (struct sonic_local *)kmalloc(sizeof(*lp), GFP_KERNEL);
-	    if ((unsigned long)lp >> 16 != ((unsigned long)lp + sizeof(*lp) ) >> 16) {
-		/* FIXME, free the memory later */
-		kfree (lp);
-		lp = NULL;
-	    }
-	} while (lp == NULL && i++ < 20);
-	
-	if (lp == NULL) {
-	    printk ("%s: couldn't allocate memory for descriptors\n",
-	            dev->name);
-	    return -ENOMEM;
-	}
-	
-	memset(lp, 0, sizeof(struct sonic_local));
-	
-	/* get the virtual dma address */
-	lp->cda_laddr = vdma_alloc(PHYSADDR(lp),sizeof(*lp));
-	if (lp->cda_laddr == ~0UL) {
-	    printk ("%s: couldn't get DMA page entry for descriptors\n",
-	            dev->name);
-	    return -ENOMEM;
-	}
-
-	lp->tda_laddr = lp->cda_laddr + sizeof (lp->cda);
-	lp->rra_laddr = lp->tda_laddr + sizeof (lp->tda);
-	lp->rda_laddr = lp->rra_laddr + sizeof (lp->rra);
-	
-	/* allocate receive buffer area */
-	/* FIXME, maybe we should use skbs */
-	if ((lp->rba = (char *)kmalloc(SONIC_NUM_RRS * SONIC_RBSIZE, GFP_KERNEL)) == NULL) {
-	    printk ("%s: couldn't allocate receive buffers\n",dev->name);
-	    return -ENOMEM;
-	}
-	
-	/* get virtual dma address */
-	if ((lp->rba_laddr = vdma_alloc(PHYSADDR(lp->rba),SONIC_NUM_RRS * SONIC_RBSIZE)) == ~0UL) {
-	    printk ("%s: couldn't get DMA page entry for receive buffers\n",dev->name);
-	    return -ENOMEM;
-	}
-	
-	/* now convert pointer to KSEG1 pointer */
-	lp->rba = (char *)KSEG1ADDR(lp->rba);
-	flush_cache_all();
-	dev->priv = (struct sonic_local *)KSEG1ADDR(lp);
-    }
-
-    lp = (struct sonic_local *)dev->priv;
-    dev->open = sonic_open;
-    dev->stop = sonic_close;
-    dev->hard_start_xmit = sonic_send_packet;
-    dev->get_stats	= sonic_get_stats;
-    dev->set_multicast_list = &sonic_multicast_list;
-
-    /* Fill in the fields of the device structure with ethernet values. */
-    ether_setup(dev);
-    return 0;
-}
 
 /*
  * Open/initialize the SONIC controller.
@@ -293,6 +30,7 @@
  *  registers that "should" only need to be set once at boot, so that
  *  there is non-reboot way to recover if something goes wrong.
  */
+
 static int sonic_open(struct device *dev)
 {
     if (sonic_debug > 2)
@@ -309,9 +47,9 @@
  * this glue works ok under all situations.
  */
 //    if (request_irq(dev->irq, &sonic_interrupt, 0, "sonic", dev)) {
-    if (request_irq(dev->irq, &sonic_interrupt, SA_INTERRUPT, "sonic", dev)) {
-	printk ("\n%s: unable to get IRQ %d .\n", dev->name, dev->irq);
-	return EAGAIN;
+    if (sonic_request_irq(dev->irq, &sonic_interrupt, SA_INTERRUPT, "sonic", dev)) {
+	  printk ("\n%s: unable to get IRQ %d .\n", dev->name, dev->irq);
+	  return EAGAIN;
     }
 
     /*
@@ -351,7 +89,7 @@
     SONIC_WRITE(SONIC_IMR,0);
     SONIC_WRITE(SONIC_CMD,SONIC_CR_RST);
 
-    free_irq(dev->irq, dev);			/* release the IRQ */
+    sonic_free_irq(dev->irq, dev);		/* release the IRQ */
 
     return 0;
 }
@@ -371,23 +109,23 @@
       printk("sonic_send_packet: skb=%p, dev=%p\n",skb,dev);
   
     if (dev->tbusy) {
-	int tickssofar = jiffies - dev->trans_start;
+	  int tickssofar = jiffies - dev->trans_start;
 
-	/* If we get here, some higher level has decided we are broken.
-	 There should really be a "kick me" function call instead. */
+	  /* If we get here, some higher level has decided we are broken.
+		 There should really be a "kick me" function call instead. */
       
-	if (sonic_debug > 1)
-	  printk("sonic_send_packet: called with dev->tbusy = 1 !\n");
+	  if (sonic_debug > 1)
+		printk("sonic_send_packet: called with dev->tbusy = 1 !\n");
 	
-	if (tickssofar < 5)
-	  return 1;
+	  if (tickssofar < 5)
+		return 1;
 	
-	printk("%s: transmit timed out.\n", dev->name);
+	  printk("%s: transmit timed out.\n", dev->name);
 	
-	/* Try to restart the adaptor. */
-	sonic_init(dev);
-	dev->tbusy=0;
-	dev->trans_start = jiffies;
+	  /* Try to restart the adaptor. */
+	  sonic_init(dev);
+	  dev->tbusy=0;
+	  dev->trans_start = jiffies;
     }
 
     /* 
@@ -395,25 +133,24 @@
      * done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
      */
     if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
-	printk("%s: Transmitter access conflict.\n", dev->name);
-	return 1;
+	  printk("%s: Transmitter access conflict.\n", dev->name);
+	  return 1;
     }
     
     /*
      * Map the packet data into the logical DMA address space
      */
     if ((laddr = vdma_alloc(PHYSADDR(skb->data),skb->len)) == ~0UL) {
-	printk("%s: no VDMA entry for transmit available.\n",dev->name);
-	dev_kfree_skb(skb);
-	dev->tbusy = 0;
-	return 1;
+	  printk("%s: no VDMA entry for transmit available.\n",dev->name);
+	  dev_kfree_skb(skb);
+	  dev->tbusy = 0;
+	  return 1;
     }
     entry = lp->cur_tx & SONIC_TDS_MASK;    
     lp->tx_laddr[entry] = laddr;
     lp->tx_skb[entry] = skb;
     
     length = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len;
-    flush_cache_all();
     
     /*
      * Setup the transmit descriptor and issue the transmit command.
@@ -427,13 +164,14 @@
     
     /* if there are already packets queued, allow sending serveral packets at once */
     if (lp->dirty_tx != lp->cur_tx)
-	lp->tda[(lp->cur_tx-1) % SONIC_TDS_MASK].link &= ~SONIC_END_OF_LINKS;
+	  lp->tda[(lp->cur_tx-1) % SONIC_TDS_MASK].link &= ~SONIC_END_OF_LINKS;
     
     lp->cur_tx++;
-    lp->stats.tx_bytes += length;
     
     if (sonic_debug > 2)
-      printk("sonic_send_packet: issueing Tx command\n");
+      printk("sonic_send_packet: issuing Tx command\n");
+
+    flush_cache_all();
 
     SONIC_WRITE(SONIC_CMD,SONIC_CR_TXP);
 
@@ -461,8 +199,8 @@
     int status;
 
     if (dev == NULL) {
-	printk ("sonic_interrupt: irq %d for unknown device.\n", irq);
-	return;
+	  printk ("sonic_interrupt: irq %d for unknown device.\n", irq);
+	  return;
     }
     dev->interrupt = 1;
     lp = (struct sonic_local *)dev->priv;
@@ -474,13 +212,15 @@
       printk("sonic_interrupt: ISR=%x\n",status);
 
     if (status & SONIC_INT_PKTRX) {
-	sonic_rx(dev);				/* got packet(s) */
+			if (sonic_debug > 3)
+					printk("received packet!!\n");
+			sonic_rx(dev);				/* got packet(s) */
     }
     
     if (status & SONIC_INT_TXDN) {
-	int dirty_tx = lp->dirty_tx;
+	  int dirty_tx = lp->dirty_tx;
 	
-	while (dirty_tx < lp->cur_tx) {
+	  while (dirty_tx < lp->cur_tx) {
 	    int entry = dirty_tx & SONIC_TDS_MASK;
 	    int status = lp->tda[entry].tx_status;
 	    
@@ -498,52 +238,52 @@
 	    if (status & 0x0001)
 	      lp->stats.tx_packets++;
 	    else {
-		lp->stats.tx_errors++;
-		if (status & 0x0642) lp->stats.tx_aborted_errors++;
-		if (status & 0x0180) lp->stats.tx_carrier_errors++;
-		if (status & 0x0020) lp->stats.tx_window_errors++;
-		if (status & 0x0004) lp->stats.tx_fifo_errors++;
+		  lp->stats.tx_errors++;
+		  if (status & 0x0642) lp->stats.tx_aborted_errors++;
+		  if (status & 0x0180) lp->stats.tx_carrier_errors++;
+		  if (status & 0x0020) lp->stats.tx_window_errors++;
+		  if (status & 0x0004) lp->stats.tx_fifo_errors++;
 	    }
 
 	    /* We must free the original skb */
 	    if (lp->tx_skb[entry]) {
-		dev_kfree_skb(lp->tx_skb[entry]);
-		lp->tx_skb[entry] = 0;
+		  dev_kfree_skb(lp->tx_skb[entry]);
+		  lp->tx_skb[entry] = 0;
 	    }
 	    /* and the VDMA address */
 	    vdma_free(lp->tx_laddr[entry]);
 	    dirty_tx++;
-	}
+	  }
 	
-	if (lp->tx_full && dev->tbusy
+	  if (lp->tx_full && dev->tbusy
 	    && dirty_tx + SONIC_NUM_TDS > lp->cur_tx + 2) {
 	    /* The ring is no longer full, clear tbusy. */
 	    lp->tx_full = 0;
 	    dev->tbusy = 0;
 	    mark_bh(NET_BH);
-	}
+	  }
 	
-	lp->dirty_tx = dirty_tx;
+	  lp->dirty_tx = dirty_tx;
     }
     
     /*
      * check error conditions
      */
     if (status & SONIC_INT_RFO) {
-	printk ("%s: receive fifo underrun\n",dev->name);
-	lp->stats.rx_fifo_errors++;
+	  printk ("%s: receive fifo underrun\n",dev->name);
+	  lp->stats.rx_fifo_errors++;
     }
     if (status & SONIC_INT_RDE) {
-	printk ("%s: receive descriptors exhausted\n",dev->name);
-	lp->stats.rx_dropped++;
+	  printk ("%s: receive descriptors exhausted\n",dev->name);
+	  lp->stats.rx_dropped++;
     }
     if (status & SONIC_INT_RBE) {
-	printk ("%s: receive buffer exhausted\n",dev->name);
-	lp->stats.rx_dropped++;	
+	  printk ("%s: receive buffer exhausted\n",dev->name);
+	  lp->stats.rx_dropped++;	
     }
     if (status & SONIC_INT_RBAE) {
-	printk ("%s: receive buffer area exhausted\n",dev->name);
-	lp->stats.rx_dropped++;	
+	  printk ("%s: receive buffer area exhausted\n",dev->name);
+	  lp->stats.rx_dropped++;	
     }
 
     /* counter overruns; all counters are 16bit wide */
@@ -579,30 +319,30 @@
 
     while(lp->rda[entry].in_use == 0)
     {
-	struct sk_buff *skb;
-	int pkt_len;
-	unsigned char *pkt_ptr;
-	
-	status = lp->rda[entry].rx_status;
-	if (sonic_debug > 3)
-	  printk ("status %x, cur_rx %d, cur_rra %d\n",status,lp->cur_rx,lp->cur_rra);
-	if (status & SONIC_RCR_PRX) {	    
+	  struct sk_buff *skb;
+	  int pkt_len;
+	  unsigned char *pkt_ptr;
+	
+	  status = lp->rda[entry].rx_status;
+	  if (sonic_debug > 3)
+		printk ("status %x, cur_rx %d, cur_rra %d\n",status,lp->cur_rx,lp->cur_rra);
+	  if (status & SONIC_RCR_PRX) {	    
 	    pkt_len = lp->rda[entry].rx_pktlen;
-	    pkt_ptr = (char *)KSEG1ADDR(vdma_log2phys((lp->rda[entry].rx_pktptr_h << 16) +
-						      lp->rda[entry].rx_pktptr_l));
+	    pkt_ptr = (char *)sonic_chiptomem((lp->rda[entry].rx_pktptr_h << 16) +
+										  lp->rda[entry].rx_pktptr_l);
 	    
 	    if (sonic_debug > 3)
 	      printk ("pktptr %p (rba %p) h:%x l:%x, rra h:%x l:%x bsize h:%x l:%x\n", pkt_ptr,lp->rba,
-		      lp->rda[entry].rx_pktptr_h,lp->rda[entry].rx_pktptr_l,
-		      lp->rra[lp->cur_rra & 15].rx_bufadr_h,lp->rra[lp->cur_rra & 15].rx_bufadr_l,
-		      SONIC_READ(SONIC_RBWC1),SONIC_READ(SONIC_RBWC0));
-	
+				  lp->rda[entry].rx_pktptr_h,lp->rda[entry].rx_pktptr_l,
+				  lp->rra[lp->cur_rra & 15].rx_bufadr_h,lp->rra[lp->cur_rra & 15].rx_bufadr_l,
+				  SONIC_READ(SONIC_RBWC1),SONIC_READ(SONIC_RBWC0));
+		
 	    /* Malloc up new buffer. */
 	    skb = dev_alloc_skb(pkt_len+2);
 	    if (skb == NULL) {
-		printk("%s: Memory squeeze, dropping packet.\n", dev->name);
-		lp->stats.rx_dropped++;
-		break;
+		  printk("%s: Memory squeeze, dropping packet.\n", dev->name);
+		  lp->stats.rx_dropped++;
+		  break;
 	    }
 	    skb->dev = dev;
 	    skb_reserve(skb,2);	/* 16 byte align */
@@ -611,30 +351,29 @@
 	    skb->protocol=eth_type_trans(skb,dev);
 	    netif_rx(skb);			/* pass the packet to upper layers */
 	    lp->stats.rx_packets++;
-	    lp->stats.rx_bytes += pkt_len;
 	    
-	} else {
-	    /* This should only happen, if we enable accepting broken packets. */
-	    lp->stats.rx_errors++;
-	    if (status & SONIC_RCR_FAER) lp->stats.rx_frame_errors++;
-	    if (status & SONIC_RCR_CRCR) lp->stats.rx_crc_errors++;
-	}
-	
-	lp->rda[entry].in_use = 1;
-	entry = (++lp->cur_rx) & SONIC_RDS_MASK;
-	/* now give back the buffer to the receive buffer area */
-	if (status & SONIC_RCR_LPKT) {
+	  } else {
+		/* This should only happen, if we enable accepting broken packets. */
+		lp->stats.rx_errors++;
+		if (status & SONIC_RCR_FAER) lp->stats.rx_frame_errors++;
+		if (status & SONIC_RCR_CRCR) lp->stats.rx_crc_errors++;
+	  }
+	  
+	  lp->rda[entry].in_use = 1;
+	  entry = (++lp->cur_rx) & SONIC_RDS_MASK;
+	  /* now give back the buffer to the receive buffer area */
+	  if (status & SONIC_RCR_LPKT) {
 	    /*
 	     * this was the last packet out of the current receice buffer
 	     * give the buffer back to the SONIC
 	     */
 	    SONIC_WRITE(SONIC_RWP,(lp->rra_laddr + (++lp->cur_rra & 15) * sizeof(sonic_rr_t)) & 0xffff);
-	}
+	  }
     }
-  
-    /* If any worth-while packets have been received, dev_rint()
-     has done a mark_bh(NET_BH) for us and will work on them
-     when we get to the bottom-half routine. */
+	
+    /* If any worth-while packets have been received, netif_rx()
+	   has done a mark_bh(NET_BH) for us and will work on them
+	   when we get to the bottom-half routine. */
     return;
 }
 
@@ -678,28 +417,41 @@
     rcr |= SONIC_RCR_BRD; /* accept broadcast packets */
     
     if (dev->flags & IFF_PROMISC) {         /* set promiscuous mode */
-	rcr |= SONIC_RCR_PRO;
+	  rcr |= SONIC_RCR_PRO;
     } else {
+#ifdef DEBUG_CAM /* XXX */
+	if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 14)) {
+#else
 	if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 15)) {
+#endif
 	    rcr |= SONIC_RCR_AMC;
 	} else {
-	    if (sonic_debug > 2)
-	      printk ("sonic_multicast_list: mc_count %d\n",dev->mc_count);
+	  if (sonic_debug > 2)
+		printk ("sonic_multicast_list: mc_count %d\n",dev->mc_count);
+#ifdef DEBUG_CAM /* XXX skip CAM0+1 */
+	  lp->cda.cam_enable = 3; /* always enable our own address */
+	  for (i = 2; i <= dev->mc_count; i++) {
+#else
 	    lp->cda.cam_enable = 1; /* always enable our own address */
 	    for (i = 1; i <= dev->mc_count; i++) {
-		addr = dmi->dmi_addr;
-		dmi = dmi->next;
-		lp->cda.cam_desc[i].cam_frag2 = addr[1] << 8 | addr[0];
-		lp->cda.cam_desc[i].cam_frag1 = addr[3] << 8 | addr[2];
-		lp->cda.cam_desc[i].cam_frag0 = addr[5] << 8 | addr[4];
-		lp->cda.cam_enable |= (1 << i);
+#endif
+		  addr = dmi->dmi_addr;
+		  dmi = dmi->next;
+		  lp->cda.cam_desc[i].cam_frag2 = addr[1] << 8 | addr[0];
+		  lp->cda.cam_desc[i].cam_frag1 = addr[3] << 8 | addr[2];
+		  lp->cda.cam_desc[i].cam_frag0 = addr[5] << 8 | addr[4];
+		  lp->cda.cam_enable |= (1 << i);
 	    }
 	    /* number of CAM entries to load */
+#ifdef DEBUG_CAM
+	    SONIC_WRITE(SONIC_CDC,dev->mc_count+2);
+#else
 	    SONIC_WRITE(SONIC_CDC,dev->mc_count+1);
+#endif
 	    /* issue Load CAM command */
 	    SONIC_WRITE(SONIC_CDP, lp->cda_laddr & 0xffff);	    
 	    SONIC_WRITE(SONIC_CMD,SONIC_CR_LCAM);	    
-	}
+	  }
     }
     
     if (sonic_debug > 2)
@@ -747,10 +499,10 @@
     rra_end   = (rra_start + (SONIC_NUM_RRS * sizeof(sonic_rr_t))) & 0xffff;
   
     for (i = 0; i < SONIC_NUM_RRS; i++) {
-	lp->rra[i].rx_bufadr_l = (lp->rba_laddr + i * SONIC_RBSIZE) & 0xffff;
-	lp->rra[i].rx_bufadr_h = (lp->rba_laddr + i * SONIC_RBSIZE) >> 16;
-	lp->rra[i].rx_bufsize_l = SONIC_RBSIZE >> 1;
-	lp->rra[i].rx_bufsize_h = 0;
+	  lp->rra[i].rx_bufadr_l = (lp->rba_laddr + i * SONIC_RBSIZE) & 0xffff;
+	  lp->rra[i].rx_bufadr_h = (lp->rba_laddr + i * SONIC_RBSIZE) >> 16;
+	  lp->rra[i].rx_bufsize_l = SONIC_RBSIZE >> 1;
+	  lp->rra[i].rx_bufsize_h = 0;
     }
 
     /* initialize all RRA registers */
@@ -770,8 +522,8 @@
     SONIC_WRITE(SONIC_CMD,SONIC_CR_RRRA);
     i = 0;
     while (i++ < 100) {
-	if (SONIC_READ(SONIC_CMD) & SONIC_CR_RRRA)
-	  break;
+	  if (SONIC_READ(SONIC_CMD) & SONIC_CR_RRRA)
+		break;
     }
     
     if (sonic_debug > 2)
@@ -785,13 +537,13 @@
     if (sonic_debug > 2)
       printk ("sonic_init: initialize receive descriptors\n");      
     for (i=0; i<SONIC_NUM_RDS; i++) {
-	lp->rda[i].rx_status = 0;
-	lp->rda[i].rx_pktlen = 0;
-	lp->rda[i].rx_pktptr_l = 0;
-	lp->rda[i].rx_pktptr_h = 0;
-	lp->rda[i].rx_seqno = 0;
-	lp->rda[i].in_use = 1;		       	
-	lp->rda[i].link = lp->rda_laddr + (i+1) * sizeof (sonic_rd_t);
+	  lp->rda[i].rx_status = 0;
+	  lp->rda[i].rx_pktlen = 0;
+	  lp->rda[i].rx_pktptr_l = 0;
+	  lp->rda[i].rx_pktptr_h = 0;
+	  lp->rda[i].rx_seqno = 0;
+	  lp->rda[i].in_use = 1;		       	
+	  lp->rda[i].link = lp->rda_laddr + (i+1) * sizeof (sonic_rd_t);
     }
     /* fix last descriptor */
     lp->rda[SONIC_NUM_RDS-1].link = lp->rda_laddr;
@@ -806,11 +558,11 @@
     if (sonic_debug > 2)
       printk ("sonic_init: initialize transmit descriptors\n");
     for (i = 0; i < SONIC_NUM_TDS; i++) {
-	lp->tda[i].tx_status = 0;
-	lp->tda[i].tx_config = 0;
-	lp->tda[i].tx_pktsize = 0;
-	lp->tda[i].tx_frag_count = 0;
-	lp->tda[i].link = (lp->tda_laddr + (i+1) * sizeof (sonic_td_t)) | SONIC_END_OF_LINKS;
+	  lp->tda[i].tx_status = 0;
+	  lp->tda[i].tx_config = 0;
+	  lp->tda[i].tx_pktsize = 0;
+	  lp->tda[i].tx_frag_count = 0;
+	  lp->tda[i].link = (lp->tda_laddr + (i+1) * sizeof (sonic_td_t)) | SONIC_END_OF_LINKS;
     }
     lp->tda[SONIC_NUM_TDS-1].link = (lp->tda_laddr & 0xffff) | SONIC_END_OF_LINKS;    
 
@@ -824,7 +576,26 @@
     lp->cda.cam_desc[0].cam_frag1 = dev->dev_addr[3] << 8 | dev->dev_addr[2];
     lp->cda.cam_desc[0].cam_frag0 = dev->dev_addr[5] << 8 | dev->dev_addr[4];
     lp->cda.cam_enable = 1;
-    
+
+#ifdef DEBUG_CAM
+    /* byte reversed in CAM 1 */
+    lp->cda.cam_desc[1].cam_frag2 = dev->dev_addr[0] << 8 | dev->dev_addr[1];
+    lp->cda.cam_desc[1].cam_frag1 = dev->dev_addr[2] << 8 | dev->dev_addr[3];
+    lp->cda.cam_desc[1].cam_frag0 = dev->dev_addr[4] << 8 | dev->dev_addr[4];
+    lp->cda.cam_enable = 3;
+
+    if (sonic_debug > 2) {
+	  printk("This is what should be put into CAM desc[0]:\n");
+	  printk("cda.cam_desc[0].cam_frag2=%x\n",lp->cda.cam_desc[0].cam_frag2);
+	  printk("cda.cam_desc[0].cam_frag1=%x\n",lp->cda.cam_desc[0].cam_frag1);
+	  printk("cda.cam_desc[0].cam_frag0=%x\n",lp->cda.cam_desc[0].cam_frag0);
+	  printk("This is what should be put into CAM desc[1]:\n");
+	  printk("cda.cam_desc[1].cam_frag2=%x\n",lp->cda.cam_desc[1].cam_frag2);
+	  printk("cda.cam_desc[1].cam_frag1=%x\n",lp->cda.cam_desc[1].cam_frag1);
+	  printk("cda.cam_desc[1].cam_frag0=%x\n",lp->cda.cam_desc[1].cam_frag0);
+    }
+#endif
+
     for (i=0; i < 16; i++)
       lp->cda.cam_desc[i].cam_entry_pointer = i;
 
@@ -832,8 +603,12 @@
      * initialize CAM registers
      */
     SONIC_WRITE(SONIC_CDP, lp->cda_laddr & 0xffff);
+#ifdef DEBUG_CAM
+    SONIC_WRITE(SONIC_CDC,2);
+#else
     SONIC_WRITE(SONIC_CDC,1);
-    
+#endif    
+
     /*
      * load the CAM
      */
@@ -841,13 +616,30 @@
     
     i = 0;
     while (i++ < 100) {
-	if (SONIC_READ(SONIC_ISR) & SONIC_INT_LCD)
-	  break;
+	  if (SONIC_READ(SONIC_ISR) & SONIC_INT_LCD)
+		break;
     }
     if (sonic_debug > 2) {
-	printk("sonic_init: CMD=%x, ISR=%x\n",
-	       SONIC_READ(SONIC_CMD),
-	       SONIC_READ(SONIC_ISR));
+#ifdef DEBUG_CAM
+	  printk("This is what got put into CAM desc[0]\n");
+	  SONIC_WRITE(SONIC_CMD,SONIC_CR_RST);
+	  SONIC_WRITE(SONIC_CEP,0);
+	  printk("CAP0: %x - CAP1: %x - CAP2: %x\n",
+			 SONIC_READ(SONIC_CAP0),
+			 SONIC_READ(SONIC_CAP1),
+			 SONIC_READ(SONIC_CAP2));
+	  printk("This is what got put into CAM desc[1]\n");
+	  SONIC_WRITE(SONIC_CMD,SONIC_CR_RST);
+	  SONIC_WRITE(SONIC_CEP,1);
+	  printk("CAP0: %x - CAP1: %x - CAP2: %x\n",
+			 SONIC_READ(SONIC_CAP0),
+			 SONIC_READ(SONIC_CAP1),
+			 SONIC_READ(SONIC_CAP2));
+	  SONIC_WRITE(SONIC_CMD,0);
+#endif
+	  printk("sonic_init: CMD=%x, ISR=%x\n",
+			 SONIC_READ(SONIC_CMD),
+			 SONIC_READ(SONIC_ISR));
     }
 
     /*
@@ -862,12 +654,12 @@
 
     cmd = SONIC_READ(SONIC_CMD);
     if ((cmd & SONIC_CR_RXEN) == 0 ||
-	(cmd & SONIC_CR_STP) == 0)
+		(cmd & SONIC_CR_STP) == 0)
       printk("sonic_init: failed, status=%x\n",cmd);
-
+	
     if (sonic_debug > 2)
       printk("sonic_init: new status=%x\n",SONIC_READ(SONIC_CMD));
-
+	
     return(0);
 }
 
--- linux-2.1.131/drivers/net/sonic.h.org	Thu Jul 17 08:45:23 1997
+++ linux-2.1.131/drivers/net/sonic.h	Wed Dec 30 00:39:46 1998
@@ -9,20 +9,14 @@
  * and pad structure members must be exchanged. Also, the structures
  * need to be changed accordingly to the bus size. 
  *
+ * 981229 MSch:	did just that for the 68k Mac port (32 bit, big endian),
+ *		see CONFIG_MACSONIC branch below.
+ *
  */
 
 #ifndef SONIC_H
 #define SONIC_H
 
-/*
- * Macros to access SONIC registers
- */
-#define SONIC_READ(reg) \
-	*((volatile unsigned int *)base_addr+reg)
-
-#define SONIC_WRITE(reg,val) \
-	*((volatile unsigned int *)base_addr+reg) = val
-
 
 /*
  * SONIC register offsets
@@ -223,6 +217,108 @@
 #define	SONIC_END_OF_LINKS	0x0001
 
 
+#ifdef CONFIG_MACSONIC
+/* Big endian like structures on Mac
+ * (680x0)
+ */
+
+typedef struct {
+  u32 rx_bufadr_l;	/* receive buffer ptr */
+  u32 rx_bufadr_h;
+
+  u32 rx_bufsize_l;	/* no. of words in the receive buffer */
+  u32 rx_bufsize_h;
+} sonic_rr_t;
+
+/*
+ * Sonic receive descriptor. Receive descriptors are
+ * kept in a linked list of these structures.
+ */
+
+typedef struct {
+  u16 pad0;
+  u16 rx_status;	/* status after reception of a packet */
+  u16 pad1;
+  u16 rx_pktlen;	/* length of the packet incl. CRC */
+  
+  /*
+   * Pointers to the location in the receive buffer area (RBA)
+   * where the packet resides. A packet is always received into
+   * a contiguous piece of memory.
+   */
+  u16 pad2;
+  u16 rx_pktptr_l;
+  u16 pad3;
+  u16 rx_pktptr_h;
+
+  u16 pad4;
+  u16 rx_seqno;	/* sequence no. */
+
+  u16 pad5;
+  u16 link;		/* link to next RDD (end if EOL bit set) */
+
+  /*
+   * Owner of this descriptor, 0= driver, 1=sonic
+   */
+  
+  u16 pad6;
+  u16 in_use;	
+
+  caddr_t rda_next;		/* pointer to next RD */
+} sonic_rd_t;
+
+
+/*
+ * Describes a Transmit Descriptor
+ */
+typedef struct {
+  u16 pad0;		
+  u16 tx_status;	/* status after transmission of a packet */
+  u16 pad1;		
+  u16 tx_config;	/* transmit configuration for this packet */
+  u16 pad2;		
+  u16 tx_pktsize;	/* size of the packet to be transmitted */
+  u16 pad3;		
+  u16 tx_frag_count;	/* no. of fragments */
+
+  u16 pad4;		
+  u16 tx_frag_ptr_l;
+  u16 pad5;		
+  u16 tx_frag_ptr_h;
+  u16 pad6;		
+  u16 tx_frag_size;
+  
+  u16 pad7;		
+  u16 link;		/* ptr to next descriptor */
+} sonic_td_t;
+
+
+/*
+ * Describes an entry in the CAM Descriptor Area.
+ */
+
+typedef struct {
+  u16 pad;
+  u16 cam_entry_pointer;
+  u16 pad2;
+  u16 cam_frag2;
+  u16 pad1;
+  u16 cam_frag1;
+  u16 pad0;
+  u16 cam_frag0;
+} sonic_cd_t;
+
+#define CAM_DESCRIPTORS 16
+
+
+typedef struct {
+  sonic_cd_t cam_desc[CAM_DESCRIPTORS];
+  u16 pad;
+  u16 cam_enable;
+} sonic_cda_t;
+
+#else /* original declarations, little endian 32 bit */
+
 /*
  * structure definitions
  */
@@ -321,6 +417,57 @@
   u16 cam_enable;
   u16 pad;
 } sonic_cda_t;
+#endif	/* endianness */ 
 
+/*
+ * Some tunables for the buffer areas. Power of 2 is required
+ * the current driver uses one receive buffer for each descriptor.
+ *
+ * MSch: use more buffer space for the slow m68k Macs!
+ */
+#ifdef CONFIG_MACSONIC
+#define SONIC_NUM_RRS    32             /* number of receive resources */
+#define SONIC_NUM_RDS    SONIC_NUM_RRS  /* number of receive descriptors */
+#define SONIC_NUM_TDS    32      /* number of transmit descriptors */
+#else
+#define SONIC_NUM_RRS    16             /* number of receive resources */
+#define SONIC_NUM_RDS    SONIC_NUM_RRS  /* number of receive descriptors */
+#define SONIC_NUM_TDS    16      /* number of transmit descriptors */
+#endif
+#define SONIC_RBSIZE   1520      /* size of one resource buffer */
+
+#define SONIC_RDS_MASK   (SONIC_NUM_RDS-1)
+#define SONIC_TDS_MASK   (SONIC_NUM_TDS-1)
+
+/* Information that need to be kept for each board. */
+struct sonic_local {
+    sonic_cda_t   cda;                     /* virtual CPU address of CDA */
+    sonic_td_t    tda[SONIC_NUM_TDS];      /* transmit descriptor area */
+    sonic_rr_t    rra[SONIC_NUM_RRS];      /* receive resource arrea */
+    sonic_rd_t    rda[SONIC_NUM_RDS];      /* receive descriptor area */
+    struct sk_buff* tx_skb[SONIC_NUM_TDS]; /* skbuffs for packets to transmit */
+    unsigned int  tx_laddr[SONIC_NUM_TDS]; /* logical DMA address fro skbuffs */
+    unsigned char *rba;                    /* start of receive buffer areas */    
+    unsigned int  cda_laddr;               /* logical DMA address of CDA */    
+    unsigned int  tda_laddr;               /* logical DMA address of TDA */
+    unsigned int  rra_laddr;               /* logical DMA address of RRA */    
+    unsigned int  rda_laddr;               /* logical DMA address of RDA */
+    unsigned int  rba_laddr;               /* logical DMA address of RBA */
+    unsigned int  cur_tx, cur_rx;          /* current indexes to resource areas */
+    unsigned int  dirty_tx,cur_rra;        /* last unacked transmit packet */
+    char tx_full;
+    struct enet_statistics stats;
+};
+
+/* Index to functions, as function prototypes. */
+
+static int sonic_open(struct device *dev);
+static int sonic_send_packet(struct sk_buff *skb, struct device *dev);
+static void sonic_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void sonic_rx(struct device *dev);
+static int sonic_close(struct device *dev);
+static struct enet_statistics *sonic_get_stats(struct device *dev);
+static void sonic_multicast_list(struct device *dev);
+static int sonic_init(struct device *dev);
 
 #endif /* SONIC_H */
--- linux-2.1.131/drivers/net/Makefile.org	Wed Dec 30 00:06:50 1998
+++ linux-2.1.131/drivers/net/Makefile	Wed Dec 30 00:10:07 1998
@@ -854,10 +854,10 @@
 endif
 
 ifeq ($(CONFIG_MIPS_JAZZ_SONIC),y)
-L_OBJS += sonic.o
+L_OBJS += jazzsonic.o
 else
   ifeq ($(CONFIG_MIPS_JAZZ_SONIC),m)
-    M_OBJS += sonic.o
+    M_OBJS += jazzsonic.o
   endif
 endif
 
@@ -967,6 +967,10 @@
 
 ifeq ($(CONFIG_MACE),y)
 L_OBJS += mace.o
+endif
+
+ifeq ($(CONFIG_MACSONIC),y)
+L_OBJS += macsonic.o
 endif
 
 ifeq ($(CONFIG_BMAC),y)
--- linux-2.1.131/drivers/net/Space.c.org	Wed Dec 30 00:10:28 1998
+++ linux-2.1.131/drivers/net/Space.c	Wed Dec 30 00:13:13 1998
@@ -111,6 +111,7 @@
 extern int hplance_probe(struct device *dev);
 extern int via_rhine_probe(struct device *dev);
 extern int tc515_probe(struct device *dev);
+extern int mac_onboard_sonic_probe(struct device *dev);
 
 /* Gigabit Ethernet adapters */
 extern int yellowfin_probe(struct device *dev);
@@ -403,6 +404,9 @@
 #endif
 #ifdef CONFIG_HPLANCE		/* HP300 internal Ethernet */
 	{hplance_probe, 0},
+#endif
+#ifdef CONFIG_MACSONIC		/* Mac 68k Quadra builtin Ethernet */ 
+	{mac_onboard_sonic_probe, 0},
 #endif
 	{NULL, 0},
 };
--- linux-2.1.131/drivers/net/macsonic.c.org	Wed Dec 30 00:23:01 1998
+++ linux-2.1.131/drivers/net/macsonic.c	Wed Dec 30 00:31:29 1998
@@ -0,0 +1,484 @@
+/*
+ * macsonic.c
+ *
+ * (C) 1998 Alan Cox
+ *
+ * Debugging Andreas Ehliar, Michael Schmitz
+ *
+ * Based on code
+ * (C) 1996 by Thomas Bogendoerfer (tsbogend@bigbug.franken.de)
+ * 
+ * This driver is based on work from Andreas Busse, but most of
+ * the code is rewritten.
+ * 
+ * (C) 1995 by Andreas Busse (andy@waldorf-gmbh.de)
+ *
+ * A driver for the Mac onboard Sonic ethernet chip.
+ *
+ * 98/12/21 MSch: judged from tests on Q800, it's basically working, 
+ *		  but eating up both receive and transmit resources
+ *		  and duplicating packets. Needs more testing.
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/ctype.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/nubus.h>
+#include <asm/bootinfo.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/pgtable.h>
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/macintosh.h>
+
+#include <linux/errno.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include "sonic.h"
+
+extern int mac_onboard_sonic_probe(struct device *unused);
+
+static int setup_debug = -1;
+static int setup_offset = -1;
+static int setup_shift = -1;
+
+/*
+ * This seems to be the right default for the Q800
+ */
+
+static int reg_offset = 0;
+static int reg_shift = 0;
+
+/*
+ * Macros to access SONIC registers
+ */
+ 
+#define MAC_SONIC_REGISTERS	0x50F0A000
+#define MAC_SONIC_PROM_BASE	0x50f08000
+#define MAC_SONIC_IRQ		9	/* Nubus 9 */
+
+/*
+ *    FIXME: We may need to invert the byte ordering. These should
+ *      be ok for other aspects as they are uncached spaces.
+ *      The original macros from jazzsonic.c works for me
+ *      on my LC 630, YMMV /Andreas Ehliar
+ */
+
+#if 0
+#define SONIC_READ(reg) \
+	*((volatile unsigned int *)base_addr+((reg)<<2)+2)
+
+#define SONIC_WRITE(reg,val) \
+	*((volatile unsigned int *)base_addr+((reg)<<2)+2) = val
+#else
+#define SONIC_READ(reg) \
+	*((volatile unsigned int *)base_addr+reg)
+
+#define SONIC_WRITE(reg,val) \
+	*((volatile unsigned int *)base_addr+reg) = val
+#endif
+
+#define SONIC_READ_PROM(addr) \
+	*((volatile unsigned char *)prom_addr+addr)
+/*
+ * Function : mac_sonic_setup(char *str, int *ints)
+ *
+ * Purpose : booter command line initialization of the overrides array,
+ *
+ * Inputs : str - unused, ints - array of integer parameters with ints[0]
+ *	equal to the number of ints.
+ *
+ * Currently unused in the new driver; need to add settable parameters to the 
+ * detect function.
+ *
+ */
+
+void mac_sonic_setup(char *str, int *ints) {
+	/* Format of macsonic parameter is:
+	 *   macsonic=<debug>,<offset>,<shift>
+	 * Negative values mean don't change.
+	 */
+	
+	/* Grmbl... the standard parameter parsing can't handle negative numbers
+	 * :-( So let's do it ourselves!
+	 */
+
+	int i = ints[0]+1, fact;
+
+	while( str && (isdigit(*str) || *str == '-') && i <= 10) {
+		if (*str == '-')
+			fact = -1, ++str;
+		else
+			fact = 1;
+		ints[i++] = simple_strtoul( str, NULL, 0 ) * fact;
+		if ((str = strchr( str, ',' )) != NULL)
+			++str;
+	}
+	ints[0] = i-1;
+	
+	if (ints[0] < 1) {
+		printk( "mac_sonic_setup: no arguments!\n" );
+		return;
+	}
+
+	if (ints[0] >= 1) {
+	       	/* 0 <= n <= 2 */
+		if (ints[1] >= 0 && ints[1] <= 8)
+			setup_debug = ints[1];
+		else if (ints[1] > 16)
+			printk( "mac_sonic_setup: invalid debug level %d !\n", ints[1] );
+	}
+	if (ints[0] >= 2) {
+	       	/* 0 <= n <= 2 */
+		if (ints[2] >= 0 && ints[2] <= 16)
+			setup_offset = ints[2];
+		else if (ints[2] > 16)
+			printk( "mac_sonic_setup: invalid offset %d !\n", ints[2] );
+	}
+	if (ints[0] >= 3) {
+	       	/* 0 <= n <= 2 */
+		if (ints[3] >= 0 && ints[3] <= 16)
+			setup_shift = ints[3];
+		else if (ints[3] > 16)
+			printk( "mac_sonic_setup: invalid shift %d !\n", ints[3] );
+	}
+}
+
+static int sonic_debug = 0;
+
+/*
+ * For reversing the PROM address
+ */
+
+static unsigned char nibbletab[] = {0, 8, 4, 12, 2, 10, 6, 14,
+				    1, 9, 5, 13, 3, 11, 7, 15};
+
+__initfunc(int mac_onboard_sonic_probe(struct device *unused))
+{
+	static struct device *dev;
+	unsigned int silicon_revision;
+	unsigned int val;
+	struct sonic_local *lp;
+	int i;
+	int base_addr = MAC_SONIC_REGISTERS;
+	int prom_addr = MAC_SONIC_PROM_BASE;
+	static int one=0;
+	
+	if (!MACH_IS_MAC)
+		return -ENODEV;
+
+	if(++one!=1)	/* Only one is allowed */
+		return -ENODEV;
+
+	printk(KERN_INFO "Checking for internal Macintosh ethernet (SONIC).. ");
+
+	if (macintosh_config->ether_type != MAC_ETHER_SONIC)
+	{
+		printk("none.\n");
+		return -ENODEV;
+	}
+	
+	printk("yes\n");
+	
+	if (setup_debug >= 0)
+	  sonic_debug = setup_debug;
+
+	/*
+	 * This may depend on the actual Mac model ... works for me.
+	 */
+	reg_offset = 
+	  (setup_offset >= 0) ? setup_offset : 0;
+	reg_shift = 
+	  (setup_shift >= 0) ? setup_shift : 0;
+
+	/*
+	 * get the Silicon Revision ID. If this is one of the known
+	 * one assume that we found a SONIC ethernet controller at
+	 * the expected location.
+	 * (This is not implemented in the Macintosh driver yet; need
+	 * to collect values from various sources. Mine is 0x4 ...)
+	 */
+
+	silicon_revision = SONIC_READ(SONIC_SR);
+	if (sonic_debug > 1)
+		printk("SONIC Silicon Revision = 0x%04x\n", silicon_revision);
+
+	/*
+	 * We need to allocate sonic_local later on, making sure it's
+	 * aligned on a 64k boundary. So, no space for dev->priv allocated
+	 * here ...
+	 */
+	dev = init_etherdev(0,0);
+	
+	if(dev==NULL)
+		return -ENOMEM;
+
+	printk("%s: %s found at 0x%08x, ",
+	       dev->name, "SONIC ethernet", base_addr);
+
+	if (sonic_debug > 1)
+		printk("using offset %d shift %d,", reg_offset, reg_shift);
+
+	/* Fill in the 'dev' fields. */
+	dev->base_addr = base_addr;
+	dev->irq = MAC_SONIC_IRQ;
+
+	/*
+	 * Put the sonic into software reset, then
+	 * retrieve and print the ethernet address.
+	 */
+
+	SONIC_WRITE(SONIC_CMD, SONIC_CR_RST);
+
+	/*
+	 *        We can't trust MacOS to initialise things it seems.
+	 */
+
+	if (sonic_debug > 1)
+		printk("SONIC_DCR was %X\n",SONIC_READ(SONIC_DCR));
+	
+	SONIC_WRITE(SONIC_DCR,
+		    SONIC_DCR_RFT1 | SONIC_DCR_TFT0 | SONIC_DCR_EXBUS | SONIC_DCR_DW);
+
+	/*
+	 *  We don't want floating spare IRQ's around, not on
+	 *  level triggered systems!
+	 *  Strange though - writing to the ISR only clears currently
+	 *  pending IRQs, but doesn't disable them... Does this make 
+	 *  a difference?? Seems it does ...
+	 */
+#if 1
+	SONIC_WRITE(SONIC_ISR,0x7fff);
+	SONIC_WRITE(SONIC_IMR,0);
+#else
+	SONIC_WRITE(SONIC_ISR, SONIC_IMR_DEFAULT);
+#endif
+	
+	/* This is how it is done in jazzsonic.c
+	 * It doesn't seem to work here though.
+	 */
+	if (sonic_debug > 2) {
+		printk("Retreiving CAM entry 0. This should be the HW address.\n");
+		
+		SONIC_WRITE(SONIC_CEP, 0);
+		for (i = 0; i < 3; i++)
+		{
+			val = SONIC_READ(SONIC_CAP0 - i);
+			dev->dev_addr[i * 2] = val;
+			dev->dev_addr[i * 2 + 1] = val >> 8;
+		}
+
+		printk("HW Address from CAM 0: ");
+		for (i = 0; i < 6; i++)
+		{
+			printk("%2.2x", dev->dev_addr[i]);
+			if (i < 5)
+				printk(":");
+		}
+		printk("\n");
+
+		printk("Retreiving CAM entry 15. Another candidate...\n");
+
+		/*
+		 * MacOS seems to use CAM entry 15 ...
+		 */
+	       	SONIC_WRITE(SONIC_CEP, 15);
+		for (i = 0; i < 3; i++)
+		{
+			val = SONIC_READ(SONIC_CAP0 - i);
+			dev->dev_addr[i * 2] = val;
+			dev->dev_addr[i * 2 + 1] = val >> 8;
+		}
+
+		printk("HW Address from CAM 15: ");
+		for (i = 0; i < 6; i++)
+		{
+			printk("%2.2x", dev->dev_addr[i]);
+			if (i < 5)
+				printk(":");
+		}
+		printk("\n");
+	}
+
+	/*
+	 * if we can read the PROM, we're safe :-)
+	 */
+	if (sonic_debug > 1)
+		printk("Retreiving HW address from the PROM: ");
+
+	for(i=0;i<6;i++){
+                dev->dev_addr[i]=SONIC_READ_PROM(i);
+        }                             
+	if (sonic_debug > 1) {
+	        for (i = 0; i < 6; i++)
+		{
+			printk("%2.2x", dev->dev_addr[i]);
+			if (i <	5)
+				printk(":");
+		}
+		printk("\n");
+	}
+	/*
+	 *                If its not one of these we have
+	 *          screwed up on this Mac model
+	 */
+
+	if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) &&
+	    memcmp(dev->dev_addr, "\x00\xA0\x40", 3) &&
+	    memcmp(dev->dev_addr, "\x00\x05\x02", 3))
+	{
+		/*
+		 * Try bit reversed
+		 */
+		for(i=0;i<6;i++){
+			val = SONIC_READ_PROM(i);
+			dev->dev_addr[i]=(nibbletab[val & 0xf] << 4) | 
+					  nibbletab[(val >> 4) &0xf];
+		}
+		if (sonic_debug > 1) {
+			printk("Trying bit reversed:  ");
+			for (i = 0; i < 6; i++)
+			{
+				printk("%2.2x", dev->dev_addr[i]);
+				if (i < 5)
+					printk(":");
+			}
+			printk("\n");
+		}
+		if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) &&
+		    memcmp(dev->dev_addr, "\x00\xA0\x40", 3) &&
+		    memcmp(dev->dev_addr, "\x00\x05\x02", 3))
+		{
+		        /*
+			 * Still nonsense ... messed up someplace!
+			 */
+			printk("ERROR (INVALID MAC)\n");
+			return -EIO;
+		}
+	}
+
+	printk(" MAC ");
+	for (i = 0; i < 6; i++)
+	{
+		printk("%2.2x", dev->dev_addr[i]);
+		if (i < 5)
+			printk(":");
+	}
+
+	printk(" IRQ %d\n", MAC_SONIC_IRQ);
+
+	/* Initialize the device structure. */
+	if (dev->priv == NULL)
+	{
+		if (sonic_debug > 2) {
+			printk("Allocating memory for dev->priv aka lp\n");
+			printk("Memory to allocate: %d\n",sizeof(*lp));
+		}
+		/*
+		 * the memory be located in the same 64kb segment
+		 */
+		lp = NULL;
+		i = 0;
+
+		/* 
+		 * Isn't there a better way to allocate a 64kb segment?
+		 */
+		do
+		{
+			/* should we use GFP_DMA here? */
+			lp = (struct sonic_local *) kmalloc(sizeof(*lp), GFP_KERNEL);
+			if ((unsigned long) lp >> 16 != ((unsigned long) lp + sizeof(*lp)) >> 16)
+			{
+				/* FIXME, free the memory later */
+				kfree(lp);
+				lp = NULL;
+			}
+		}
+		while (lp == NULL && i++ < 20);
+
+		if (lp == NULL)
+		{
+			printk("%s: couldn't allocate memory for descriptors\n",
+			       dev->name);
+			return -ENOMEM;
+		}
+
+		if (sonic_debug > 2) {
+			printk("Memory allocated after %d tries\n",i);
+		}
+
+		/* XXX sonic_local has the TDA, RRA, RDA, don't cache */
+		kernel_set_cachemode((u32)lp, 8192, KERNELMAP_NOCACHE_SER);
+		memset(lp, 0, sizeof(struct sonic_local));
+
+		lp->cda_laddr = (u32)lp;
+		if (sonic_debug > 2) {
+			printk("memory allocated for sonic at 0x%x\n",lp);
+		}
+		lp->tda_laddr = lp->cda_laddr + sizeof(lp->cda);
+		lp->rra_laddr = lp->tda_laddr + sizeof(lp->tda);
+		lp->rda_laddr = lp->rra_laddr + sizeof(lp->rra);
+
+		/* allocate receive buffer area */
+		/* FIXME, maybe we should use skbs */
+		if ((lp->rba = (char *) kmalloc(SONIC_NUM_RRS * SONIC_RBSIZE, GFP_KERNEL)) == NULL)
+		{
+			printk("%s: couldn't allocate receive buffers\n", dev->name);
+			return -ENOMEM;
+		}
+		/* XXX RBA written by Sonic, not cached either */
+		kernel_set_cachemode((u32)lp->rba, 6*8192, KERNELMAP_NOCACHE_SER);
+		lp->rba_laddr = (u32)lp->rba;
+		flush_cache_all();
+		dev->priv = (struct sonic_local *) lp;
+	}
+	lp = (struct sonic_local *) dev->priv;
+	dev->open = sonic_open;
+	dev->stop = sonic_close;
+	dev->hard_start_xmit = sonic_send_packet;
+	dev->get_stats = sonic_get_stats;
+	dev->set_multicast_list = &sonic_multicast_list;
+
+	/* Fill in the fields of the device structure with ethernet values. */
+	ether_setup(dev);
+	return 0;
+}
+
+/*
+ *    SONIC uses a nubus IRQ
+ */
+
+#define sonic_request_irq(irq, vec, flags, name, dev) \
+		nubus_request_irq(irq, dev, vec)
+#define sonic_free_irq(irq,id)	nubus_free_irq(irq)
+
+/*
+ *    No funnies on memory mapping.
+ */
+
+#define sonic_chiptomem(x)	(x)
+
+/*
+ *    No VDMA on a Macintosh. So we need request no such facility.
+ */
+
+#define vdma_alloc(x,y)		((u32)(x))
+#define vdma_free(x)
+#define PHYSADDR(x)		(x)
+
+#include "sonic.c"
--- linux-2.1.131/drivers/net/jazzsonic.c.org	Wed Dec 30 00:23:07 1998
+++ linux-2.1.131/drivers/net/jazzsonic.c	Wed Dec 30 00:04:58 1998
@@ -0,0 +1,260 @@
+/*
+ * jazzsonic.c
+ *
+ * (C) 1996 by Thomas Bogendoerfer (tsbogend@bigbug.franken.de)
+ * 
+ * This driver is based on work from Andreas Busse, but most of
+ * the code is rewritten.
+ * 
+ * (C) 1995 by Andreas Busse (andy@waldorf-gmbh.de)
+ *
+ *
+ * A driver for the onboard Sonic ethernet controller on Mips Jazz
+ * systems (Acer Pica-61, Mips Magnum 4000, Olivetti M700 and
+ * perhaps others, too)
+ */
+ 
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <asm/bootinfo.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/pgtable.h>
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#include <asm/jazz.h>
+#include <asm/jazzdma.h>
+
+#include <linux/errno.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include "sonic.h"
+
+/*
+ * Macros to access SONIC registers
+ */
+#define SONIC_READ(reg) \
+	*((volatile unsigned int *)base_addr+reg)
+
+#define SONIC_WRITE(reg,val) \
+	*((volatile unsigned int *)base_addr+reg) = val
+
+
+/*
+ * Base address and interupt of the SONIC controller on JAZZ boards
+ */
+static struct {
+    unsigned int port;
+    unsigned int irq;
+    } sonic_portlist[] = { {JAZZ_ETHERNET_BASE, JAZZ_ETHERNET_IRQ}, {0, 0}};
+
+/*
+ * We cannot use station (ethernet) address prefixes to detect the
+ * sonic controller since these are board manufacturer depended.
+ * So we check for known Silicon Revision IDs instead. 
+ */
+static unsigned short known_revisions[] =
+{
+  0x04,				/* Mips Magnum 4000 */
+  0xffff			/* end of list */
+};
+
+extern int sonic_probe(struct device *dev);
+static int sonic_probe1(struct device *dev, unsigned int base_addr, unsigned int irq);
+
+
+/*
+ * Probe for a SONIC ethernet controller on a Mips Jazz board.
+ * Actually probing is superfluous but we're paranoid.
+ */
+__initfunc(int sonic_probe(struct device *dev))
+{
+    unsigned int base_addr = dev ? dev->base_addr : 0;
+    int i;
+
+    /*
+     * Don't probe if we're not running on a Jazz board.
+     */
+    if (mips_machgroup != MACH_GROUP_JAZZ)
+	return -ENODEV;
+    if (base_addr > 0x1ff)	/* Check a single specified location. */
+	return sonic_probe1(dev, base_addr, dev->irq);
+    else if (base_addr != 0)	/* Don't probe at all. */
+	return -ENXIO;
+    
+    for (i = 0; sonic_portlist[i].port; i++) {
+	int base_addr = sonic_portlist[i].port;
+	if (check_region(base_addr, 0x100))
+	    continue;
+	if (sonic_probe1(dev, base_addr, sonic_portlist[i].irq) == 0)
+	    return 0;
+    }
+    return -ENODEV;
+}
+
+__initfunc(static int sonic_probe1(struct device *dev,
+                                   unsigned int base_addr, unsigned int irq))
+{
+    static unsigned version_printed = 0;
+    unsigned int silicon_revision;
+    unsigned int val;
+    struct sonic_local *lp;
+    int i;
+    
+    /*
+     * get the Silicon Revision ID. If this is one of the known
+     * one assume that we found a SONIC ethernet controller at
+     * the expected location.
+     */
+    silicon_revision = SONIC_READ(SONIC_SR);
+    if (sonic_debug > 1)
+      printk("SONIC Silicon Revision = 0x%04x\n",silicon_revision);
+
+    i = 0;
+    while ((known_revisions[i] != 0xffff) &&
+	   (known_revisions[i] != silicon_revision))
+      i++;
+	
+    if (known_revisions[i] == 0xffff) {
+	printk("SONIC ethernet controller not found (0x%4x)\n",
+	       silicon_revision);
+	return -ENODEV;
+    }
+    
+    request_region(base_addr, 0x100, "SONIC");
+    
+    /* Allocate a new 'dev' if needed. */
+    if (dev == NULL)
+      dev = init_etherdev(0, sizeof(struct sonic_local));
+
+    if (sonic_debug  &&  version_printed++ == 0)
+      printk(version);
+
+    printk("%s: %s found at 0x%08x, ",
+	   dev->name, "SONIC ethernet", base_addr);
+
+    /* Fill in the 'dev' fields. */
+    dev->base_addr = base_addr;
+    dev->irq = irq;
+
+    /*
+     * Put the sonic into software reset, then
+     * retrieve and print the ethernet address.
+     */
+    SONIC_WRITE(SONIC_CMD,SONIC_CR_RST);
+    SONIC_WRITE(SONIC_CEP,0);
+    for (i=0; i<3; i++) {
+	val = SONIC_READ(SONIC_CAP0-i);
+	dev->dev_addr[i*2] = val;
+	dev->dev_addr[i*2+1] = val >> 8;
+    }
+
+    printk("HW Address ");
+    for (i = 0; i < 6; i++) {
+	printk("%2.2x", dev->dev_addr[i]);
+	if (i<5)
+	  printk(":");
+    }
+    
+    printk(" IRQ %d\n", irq);
+    
+    /* Initialize the device structure. */
+    if (dev->priv == NULL) {
+	/*
+	 * the memory be located in the same 64kb segment
+	 */
+	lp = NULL;
+	i = 0;
+	do {
+	    lp = (struct sonic_local *)kmalloc(sizeof(*lp), GFP_KERNEL);
+	    if ((unsigned long)lp >> 16 != ((unsigned long)lp + sizeof(*lp) ) >> 16) {
+		/* FIXME, free the memory later */
+		kfree (lp);
+		lp = NULL;
+	    }
+	} while (lp == NULL && i++ < 20);
+	
+	if (lp == NULL) {
+	    printk ("%s: couldn't allocate memory for descriptors\n",
+	            dev->name);
+	    return -ENOMEM;
+	}
+	
+	memset(lp, 0, sizeof(struct sonic_local));
+	
+	/* get the virtual dma address */
+	lp->cda_laddr = vdma_alloc(PHYSADDR(lp),sizeof(*lp));
+	if (lp->cda_laddr == ~0UL) {
+	    printk ("%s: couldn't get DMA page entry for descriptors\n",
+	            dev->name);
+	    return -ENOMEM;
+	}
+
+	lp->tda_laddr = lp->cda_laddr + sizeof (lp->cda);
+	lp->rra_laddr = lp->tda_laddr + sizeof (lp->tda);
+	lp->rda_laddr = lp->rra_laddr + sizeof (lp->rra);
+	
+	/* allocate receive buffer area */
+	/* FIXME, maybe we should use skbs */
+	if ((lp->rba = (char *)kmalloc(SONIC_NUM_RRS * SONIC_RBSIZE, GFP_KERNEL)) == NULL) {
+	    printk ("%s: couldn't allocate receive buffers\n",dev->name);
+	    return -ENOMEM;
+	}
+	
+	/* get virtual dma address */
+	if ((lp->rba_laddr = vdma_alloc(PHYSADDR(lp->rba),SONIC_NUM_RRS * SONIC_RBSIZE)) == ~0UL) {
+	    printk ("%s: couldn't get DMA page entry for receive buffers\n",dev->name);
+	    return -ENOMEM;
+	}
+	
+	/* now convert pointer to KSEG1 pointer */
+	lp->rba = (char *)KSEG1ADDR(lp->rba);
+	flush_cache_all();
+	dev->priv = (struct sonic_local *)KSEG1ADDR(lp);
+    }
+
+    lp = (struct sonic_local *)dev->priv;
+    dev->open = sonic_open;
+    dev->stop = sonic_close;
+    dev->hard_start_xmit = sonic_send_packet;
+    dev->get_stats	= sonic_get_stats;
+    dev->set_multicast_list = &sonic_multicast_list;
+
+    /* Fill in the fields of the device structure with ethernet values. */
+    ether_setup(dev);
+    return 0;
+}
+
+/*
+ *	SONIC uses a normal IRQ
+ */
+ 
+#define sonic_request_irq	request_irq
+#define sonic_free_irq		free_irq
+
+#define sonic_chiptomem(x)	KSEG1ADDR(vdma_log2phys(x))
+
+/* use 0 for production, 1 for verification, >2 for debug */
+#ifdef SONIC_DEBUG
+static unsigned int sonic_debug = SONIC_DEBUG;
+#else 
+static unsigned int sonic_debug = 2;
+#endif
+
+
+#include "sonic.c"

--------------4512410F37455D20F52AFE7B--

