## Automatically generated incremental diff
## From:   linux-2.2.8-pre7
## To:     linux-2.2.8
## Robot:  $Id: make-incremental-diff,v 1.5 2001/12/01 08:32:36 hpa Exp $

diff -urN linux-2.2.8-pre7/CREDITS linux/CREDITS
--- linux-2.2.8-pre7/CREDITS	Mon Dec  3 18:46:19 2001
+++ linux/CREDITS	Mon Dec  3 18:46:53 2001
@@ -2222,6 +2222,12 @@
 S: Bellevue, Washington 98007
 S: USA
 
+N: Richard Zidlicky
+E: rdzidlic@geocities.com,rdzidlic@cip.informatik.uni-erlangen.de
+W: http://www.geocities.com/SiliconValley/Bay/2602/
+D: Q40 port - see arch/m68k/q40/README
+S: Germany
+
 N: Werner Zimmermann
 E: Werner.Zimmermann@fht-esslingen.de
 D: CDROM driver "aztcd" (Aztech/Okano/Orchid/Wearnes)
diff -urN linux-2.2.8-pre7/Documentation/Configure.help linux/Documentation/Configure.help
--- linux-2.2.8-pre7/Documentation/Configure.help	Mon Dec  3 18:46:19 2001
+++ linux/Documentation/Configure.help	Mon Dec  3 18:46:54 2001
@@ -10170,27 +10170,11 @@
   MC68EC040 will not work, as it does not include an MMU (Memory
   Management Unit).
 
-Use -m68040 flag for 68040 specific optimizations
-CONFIG_OPTIMIZE_040
-  If you will only be running this kernel on a 68040-series processor,
-  this will make the kernel run somewhat faster. However, it will no
-  longer run on a 68020 or 68030, no matter whether you included 68020
-  and 68030 support or not. Say N unless the only processor you are
-  compiling support for is the 68040 (or 68LC040).
-
 68060 support
 CONFIG_M68060
   If you anticipate running this kernel on a computer with a MC68060
   processor, say Y. Otherwise, say N.
 
-Use -m68060 flag for 68060 specific optimizations
-CONFIG_OPTIMIZE_060
-  If you will only be running this kernel on a 68060-series processor,
-  this will make the kernel run somewhat faster. However, it will no
-  longer run on a 68020, 68030 or 68040, no matter whether you
-  included support for those processors or not. Say N unless the only
-  processor you are compiling support for is the 68060.
-
 Advanced processor options
 CONFIG_ADVANCED_CPU
   This gives you access to some advanced options for the CPU. The
@@ -10223,25 +10207,9 @@
   Note that even if you say N here, you can still use your expansion
   cards. If in doubt, say Y.
 
-Amiga OCS chipset support
-CONFIG_AMIFB_OCS
-  This enables support for the original Agnus and Denise video chips,
-  found in the Amiga 1000 and most A500's and A2000's. If you intend
-  to run Linux on any of these systems, say Y; otherwise say N.
-
-Amiga ECS chipset support
-CONFIG_AMIFB_ECS
-  This enables support for the Enhanced Chip Set, found in later
-  A500's, later A2000's, the A600, the A3000, the A3000T and CDTV. If
-  you intend to run Linux on any of these systems, say Y; otherwise
-  say N.
-
-Amiga AGA chipset support
-CONFIG_AMIFB_AGA
-  This enables support for the Advanced Graphics Architecture (also
-  known as the AGA or AA) Chip Set, found in the A1200, A4000, A4000T
-  and CD32. If you intend to run Linux on any of these systems, say Y;
-  otherwise say N.
+CONFIG_AMIGA_PCMCIA
+  Include support in the kernel for pcmcia on Amiga 1200 and Amiga 600.
+  If you intend to use pcmcia cards say Y; otherwise say N.
 
 Amiga GSP (TMS340x0) support
 CONFIG_AMIGA_GSP
@@ -10445,6 +10413,16 @@
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you
   want). The module is called hydra.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt.
+
+Pcmcia NE2000 compatible support
+CONFIG_APNE
+  If you have a pcmcia ne2000 compatible adapter, say Y.  Otherwise,
+  say N.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you
+  want). The module is called apne.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt.
 
 Atari Lance support
diff -urN linux-2.2.8-pre7/Documentation/m68k/kernel-options.txt linux/Documentation/m68k/kernel-options.txt
--- linux-2.2.8-pre7/Documentation/m68k/kernel-options.txt	Thu Jan  7 08:41:54 1999
+++ linux/Documentation/m68k/kernel-options.txt	Mon Dec  3 18:46:54 2001
@@ -3,10 +3,10 @@
 				  Command Line Options for Linux/m68k
 				  ===================================
 
-Last Update: Nov 28, 1997
-Linux/m68k version: 2.1.64
+Last Update: 2 May 1999
+Linux/m68k version: 2.2.6
 Author: Roman.Hodek@informatik.uni-erlangen.de (Roman Hodek)
-Update: jds@kom.auc.dk (Jes Sorensen)
+Update: jds@kom.auc.dk (Jes Sorensen) and faq@linux-m68k.org (Chris Lawrence)
 
 0) Introduction
 ===============
@@ -145,7 +145,7 @@
 
 These two options tell the kernel whether it should mount the root
 filesystem read-only or read-write. The default is read-only, except
-for ramdisks which are read-write.
+for ramdisks, which default to read-write.
 
 
 2.3) debug
@@ -216,23 +216,10 @@
 
 
 2.7) swap=
------------
-
-Syntax: swap=<max_age>,<adv>,<decl>,<init_age>,<cl_fract>,<cl_min>,\
-        <pgout_wgt>,<bfout_wgt>
-(All optional)
-
-TODO
-
-
 2.8) buff=
 -----------
 
-Syntax: buff=<max_age>,<adv>,<decl>,<init_age>,<bfout_wgt>,<mem_grace>
-(All optional)
-
-TODO
-
+  I can't find any sign of these options in 2.2.6.
 
 
 3) General Device Options (Amiga and Atari)
@@ -311,7 +298,7 @@
 =========================
 
 4.1) video=
---------------
+-----------
 
 Syntax: video=<fbname>:<sub-options...>
 
@@ -322,8 +309,8 @@
 
 NB: Please notice that this option was renamed from `atavideo' to
     `video' during the development of the 1.3.x kernels, thus you
-    might need to update your boot-scripts if upgrading to 2.0.x from
-    an 1.2.13ply kernel.
+    might need to update your boot-scripts if upgrading to 2.x from
+    an 1.2.x kernel.
 
 NBB: The behavior of video= was changed in 2.1.57 so the recommended
 option is to specify the name of the frame buffer.
@@ -705,10 +692,11 @@
 Syntax: video=<fbname>:<sub-options...>
 
 The <fbname> parameter specifies the name of the frame buffer, valid
-options are `amifb', `cyberfb', `retz3' and `clgen', provided that the
-respective frame buffer devices have been compiled into the kernel (or
-compiled as loadable modules). The behavior of the <fbname> option was
-changed in 2.1.57 so it is now recommended to specify this option.
+options are `amifb', `cyber', 'virge', `retz3' and `clgen', provided
+that the respective frame buffer devices have been compiled into the
+kernel (or compiled as loadable modules). The behavior of the <fbname>
+option was changed in 2.1.57 so it is now recommended to specify this
+option.
 
 The <sub-options> is a comma-separated list of the sub-options listed
 below. This option is organized similar to the Atari version of the
@@ -762,8 +750,8 @@
 5.1.3) inverse
 --------------
 
-Use inverted display. Functionally the same as the "inverse"
-sub-option for the Atari.
+Use inverted display (black on white). Functionally the same as the
+"inverse" sub-option for the Atari.
 
 5.1.4) font
 -----------
@@ -787,7 +775,7 @@
 your monitor can work with, in Hz. <hmin> and <hmax> are the same for
 the horizontal frequency, in kHz.
 
-  The defaults are 50;90;15;38 (Generic Amiga monitor).
+  The defaults are 50;90;15;38 (Generic Amiga multisync monitor).
 
 
 5.2) fd_def_df0=
@@ -804,6 +792,9 @@
 
 Syntax: wd33c93=<sub-options...>
 
+These options affect the A590/A2091, A3000 and GVP Series II SCSI
+controllers.
+
 The <sub-options> is a comma-separated list of the sub-options listed
 below.
 
@@ -861,7 +852,7 @@
 -----------
 
   No argument. Used to separate blocks of keywords when there's more
-than one host adapter in the system.
+than one wd33c93-based host adapter in the system.
 
 5.3.7) nodma
 ------------
@@ -903,6 +894,69 @@
 32 bit address range for DMA. The correct setting depends on your
 controller and should be autodetected by the driver. An example is the
 24 bit region which is specified by a mask of 0x00fffffe.
+
+
+5.5) 53c7xx=
+------------
+
+Syntax: 53c7xx=<sub-options...>
+
+These options affect the A4000T, A4091, WarpEngine, Blizzard 603e+,
+and GForce 040/060 SCSI controllers on the Amiga, as well as the
+builtin MVME 16x SCSI controller.
+
+The <sub-options> is a comma-separated list of the sub-options listed
+below.
+
+5.5.1) nosync
+-------------
+
+Syntax: nosync:0
+
+  Disables sync negotiation for all devices.  Any value after the
+  colon is acceptable (and has the same effect).
+
+5.5.2) noasync
+--------------
+
+Syntax: noasync:0
+
+  Disables async and sync negotiation for all devices.  Any value
+  after the colon is acceptable (and has the same effect).
+
+5.5.3) nodisconnect
+-------------------
+
+Syntax: nodisconnect:0
+
+  Disables SCSI disconnects.  Any value after the colon is acceptable
+  (and has the same effect).
+
+5.5.4) validids
+---------------
+
+Syntax: validids:0xNN
+
+  Specify which SCSI ids the driver should pay attention to.  This is
+  a bitmask (i.e. to only pay attention to ID#4, you'd use 0x10).
+  Default is 0x7f (devices 0-6).
+
+5.5.5) opthi
+5.5.6) optlo
+------------
+
+Syntax: opthi:M,optlo:N
+
+  Specify options for "hostdata->options".  The acceptable definitions
+  are listed in drivers/scsi/53c7xx.h; the 32 high bits should be in
+  opthi and the 32 low bits in optlo.  They must be specified in the
+  order opthi=M,optlo=N.
+
+5.5.7) next
+-----------
+
+  No argument. Used to separate blocks of keywords when there's more
+  than one 53c7xx host adapter in the system.
 
 
 /* Local Variables: */
diff -urN linux-2.2.8-pre7/arch/m68k/Makefile linux/arch/m68k/Makefile
--- linux-2.2.8-pre7/arch/m68k/Makefile	Tue Jan 19 10:58:26 1999
+++ linux/arch/m68k/Makefile	Mon Dec  3 18:46:54 2001
@@ -56,6 +56,11 @@
 CORE_FILES := arch/m68k/kernel/kernel.o arch/m68k/mm/mm.o $(CORE_FILES)
 LIBS += arch/m68k/lib/lib.a
 
+ifdef CONFIG_Q40
+CORE_FILES := $(CORE_FILES) arch/m68k/q40/q40.o
+SUBDIRS := $(SUBDIRS) arch/m68k/q40
+endif
+
 ifdef CONFIG_AMIGA
 CORE_FILES := $(CORE_FILES) arch/m68k/amiga/amiga.o
 SUBDIRS := $(SUBDIRS) arch/m68k/amiga
@@ -81,6 +86,11 @@
 SUBDIRS := $(SUBDIRS) arch/m68k/apollo
 endif
 
+ifdef CONFIG_MVME147
+CORE_FILES := $(CORE_FILES) arch/m68k/mvme147/mvme147.o
+SUBDIRS := $(SUBDIRS) arch/m68k/mvme147
+endif
+
 ifdef CONFIG_MVME16x
 CORE_FILES := $(CORE_FILES) arch/m68k/mvme16x/mvme16x.o
 SUBDIRS := $(SUBDIRS) arch/m68k/mvme16x
@@ -89,6 +99,11 @@
 ifdef CONFIG_BVME6000
 CORE_FILES := $(CORE_FILES) arch/m68k/bvme6000/bvme6000.o
 SUBDIRS := $(SUBDIRS) arch/m68k/bvme6000
+endif
+
+ifdef CONFIG_SUN3X
+CORE_FILES := $(CORE_FILES) arch/m68k/sun3x/sun3x.o
+SUBDIRS := $(SUBDIRS) arch/m68k/sun3x
 endif
 
 ifdef CONFIG_M68040
diff -urN linux-2.2.8-pre7/arch/m68k/bvme6000/config.c linux/arch/m68k/bvme6000/config.c
--- linux-2.2.8-pre7/arch/m68k/bvme6000/config.c	Thu Dec 17 09:06:29 1998
+++ linux/arch/m68k/bvme6000/config.c	Mon Dec  3 18:46:54 2001
@@ -417,10 +417,10 @@
 static void scc_delay (void)
 {
         int n;
-        char i;
+	volatile int trash;
 
         for (n = 0; n < 20; n++)
-                i = *(volatile char *)0;
+		trash = n;
 }
 
 static void scc_write (char ch)
diff -urN linux-2.2.8-pre7/arch/m68k/config.in linux/arch/m68k/config.in
--- linux-2.2.8-pre7/arch/m68k/config.in	Mon Feb  1 12:03:20 1999
+++ linux/arch/m68k/config.in	Mon Dec  3 18:46:54 2001
@@ -37,6 +37,7 @@
 bool 'Apollo support' CONFIG_APOLLO
 bool 'VME (Motorola and BVM) support' CONFIG_VME
 if [ "$CONFIG_VME" = "y" ]; then
+  bool 'MVME147 support' CONFIG_MVME147
   bool 'MVME162, 166 and 167 support' CONFIG_MVME16x
   bool 'BVME4000 and BVME6000 support' CONFIG_BVME6000
 fi
@@ -44,10 +45,13 @@
 if [ "$CONFIG_HP300" = "y" ]; then
   bool 'DIO bus support' CONFIG_DIO
 fi
+bool 'Sun3x support' CONFIG_SUN3X
+  
 define_bool CONFIG_SUN3 n
 if [ "$CONFIG_PCI" = "y" ]; then
   bool 'Backward-compatible /proc/pci' CONFIG_PCI_OLD_PROC
 fi
+bool 'Q40/Q60 support' CONFIG_Q40
 
 comment 'Processor type'
 bool '68020 support' CONFIG_M68020
@@ -94,6 +98,29 @@
   fi
 fi
 bool '/proc/hardware support' CONFIG_PROC_HARDWARE
+
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+  tristate 'Parallel port support (EXPERIMENTAL, disables old lp driver!)' CONFIG_PARPORT
+  if [ "$CONFIG_PARPORT" != "n" ]; then
+    if [ "$CONFIG_AMIGA" != "n" ]; then
+      dep_tristate '   Amiga builtin port' CONFIG_PARPORT_AMIGA $CONFIG_PARPORT
+      if [ "$CONFIG_ZORRO" != "n" ]; then
+        dep_tristate '    Multiface III parallel port' CONFIG_PARPORT_MFC3 $CONFIG_PARPORT
+      fi
+    fi
+    if [ "$CONFIG_Q40" != "n" ]; then
+       tristate '    Q40 Parallel port' CONFIG_PARPORT
+       if [ "$CONFIG_PARPORT" != "n" ]; then
+         define_bool CONFIG_PARPORT_PC y
+       fi
+    fi
+  fi
+  if [ "$CONFIG_ATARI" == "y" ]; then
+    dep_tristate '    Atari builtin port' CONFIG_PARPORT_ATARI $CONFIG_PARPORT
+  fi
+fi
+
+
 endmenu
 
 source drivers/block/Config.in
@@ -147,6 +174,7 @@
     bool 'A4091 SCSI support' CONFIG_A4091_SCSI
     bool 'WarpEngine SCSI support' CONFIG_WARPENGINE_SCSI
     bool 'Blizzard PowerUP 603e+ SCSI' CONFIG_BLZ603EPLUS_SCSI
+    dep_tristate 'BSC Oktagon SCSI support' CONFIG_OKTAGON_SCSI $CONFIG_SCSI
     bool 'Cyberstorm Mk III SCSI support' CONFIG_CYBERSTORMIII_SCSI
 #    bool 'GVP Turbo 040/060 SCSI support' CONFIG_GVP_TURBO_SCSI
   fi
@@ -167,6 +195,10 @@
 fi
 #dep_tristate 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG $CONFIG_SCSI
 
+if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME147" = "y" ]; then
+  bool 'WD33C93 SCSI driver for MVME147' CONFIG_MVME147_SCSI
+fi
+
 if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME16x" = "y" ]; then
   bool 'NCR53C710 SCSI driver for MVME16x' CONFIG_MVME16x_SCSI
 fi
@@ -175,6 +207,10 @@
   bool 'NCR53C710 SCSI driver for BVME6000' CONFIG_BVME6000_SCSI
 fi
 
+if [ "$CONFIG_SUN3X" = "y" ]; then
+  bool 'ESP SCSI driver' CONFIG_SUN3X_ESP
+fi
+
 endmenu
 
 fi
@@ -219,6 +255,9 @@
 #  bool 'Macintosh (AV) onboard MACE ethernet' CONFIG_MACMACE
   bool 'Macintosh (Quadra) onboard SONIC ethernet' CONFIG_MACSONIC
 fi
+if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME147" = "y" ]; then
+  tristate 'MVME147 (Lance) Ethernet support' CONFIG_MVME147_NET
+fi
 if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME16x" = "y" ]; then
   tristate 'MVME16x Ethernet support' CONFIG_MVME16x_NET
 fi
@@ -232,9 +271,17 @@
     tristate 'PAMsNet support' CONFIG_ATARI_PAMSNET
   fi
 fi
+if [ "$CONFIG_SUN3X" = "y" ]; then
+  bool 'Sun3x Lance support' CONFIG_SUNLANCE
+fi
 if [ "$CONFIG_HP300" = "y" ]; then
   bool 'HP on-board LANCE support' CONFIG_HPLANCE
 fi
+if [ "$CONFIG_Q40" = "y" ]; then
+  if [ ! "$CONFIG_PARPORT" = "n" ]; then
+    dep_tristate 'PLIP (parallel port) support' CONFIG_PLIP $CONFIG_PARPORT
+  fi
+fi
 fi
 endmenu
 
@@ -243,6 +290,23 @@
 mainmenu_option next_comment
 comment 'Character devices'
  
+if [ "$CONFIG_Q40" = "y" ]; then
+   tristate 'Q40 Standard/generic serial support' CONFIG_SERIAL
+fi
+
+if [ "$CONFIG_SERIAL" = "y" ]; then
+   bool '   Support for console on serial port' CONFIG_SERIAL_CONSOLE
+   bool 'Extended dumb serial driver options' CONFIG_SERIAL_EXTENDED
+fi
+
+if [ "$CONFIG_SERIAL_EXTENDED" = "y" ]; then
+   bool '   Support more than 4 serial ports' CONFIG_SERIAL_MANY_PORTS
+   bool '   Support for sharing serial interrupts' CONFIG_SERIAL_SHARE_IRQ
+#   bool '   Autodetect IRQ - do not yet enable !!' CONFIG_SERIAL_DETECT_IRQ
+   bool '   Support special multiport boards' CONFIG_SERIAL_MULTIPORT
+   bool '   Support the Bell Technologies HUB6 card' CONFIG_HUB6
+fi
+
 if [ "$CONFIG_VME" = "n" ]; then
   define_bool CONFIG_VT y
   if [ "$CONFIG_VT" = "y" ]; then
@@ -254,10 +318,17 @@
   define_bool CONFIG_NVRAM y
 fi
 
-tristate 'Parallel printer support' CONFIG_M68K_PRINTER
-if [ "$CONFIG_ZORRO" = "y" ]; then
-  dep_tristate 'Multiface Card III parallel support' CONFIG_MULTIFACE_III_LP $CONFIG_M68K_PRINTER
-fi
+if [ "$CONFIG_PARPORT" = "n" ]; then
+  tristate 'Parallel printer support' CONFIG_M68K_PRINTER
+  if [ "$CONFIG_ZORRO" = "y" ]; then
+    dep_tristate 'Multiface Card III parallel support' CONFIG_MULTIFACE_III_LP $CONFIG_M68K_PRINTER
+  fi
+else
+  dep_tristate 'Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT
+  if [ "$CONFIG_PRINTER" != "n" ]; then
+    bool '  Support IEEE1284 status readback' CONFIG_PRINTER_READBACK
+  fi
+fi   
 if [ "$CONFIG_AMIGA" = "y" ]; then
   tristate 'Amiga mouse support' CONFIG_AMIGAMOUSE
 fi
@@ -280,13 +351,17 @@
 fi
 if [ "$CONFIG_AMIGA" = "y" ]; then
   tristate 'Amiga builtin serial support' CONFIG_AMIGA_BUILTIN_SERIAL
-  bool 'Hisoft Whippet PCMCIA serial support' CONFIG_WHIPPET
+  if [ "$CONFIG_AMIGA_PCMCIA" = "y" ]; then
+    tristate 'Hisoft Whippet PCMCIA serial support' CONFIG_WHIPPET_SERIAL
+  fi
 fi
-if [ "$CONFIG_ZORRO" = "y" ]; then
-  tristate 'GVP IO-Extender support' CONFIG_GVPIOEXT
-  dep_tristate 'GVP IO-Extender parallel printer support' CONFIG_GVPIOEXT_LP $CONFIG_GVPIOEXT
-  dep_tristate 'GVP IO-Extender PLIP support' CONFIG_GVPIOEXT_PLIP $CONFIG_GVPIOEXT
-  tristate 'Multiface Card III serial support' CONFIG_MULTIFACE_III_TTY
+if [ "$CONFIG_PARPORT" = "n" ]; then
+  if [ "$CONFIG_ZORRO" = "y" ]; then
+    tristate 'GVP IO-Extender support' CONFIG_GVPIOEXT
+    dep_tristate 'GVP IO-Extender parallel printer support' CONFIG_GVPIOEXT_LP $CONFIG_GVPIOEXT
+    dep_tristate 'GVP IO-Extender PLIP support' CONFIG_GVPIOEXT_PLIP $CONFIG_GVPIOEXT
+    tristate 'Multiface Card III serial support' CONFIG_MULTIFACE_III_TTY
+  fi
 fi
 if [ "$CONFIG_MAC" = "y" ]; then
   bool 'Mac SCC serial support' CONFIG_MAC_SCC
@@ -294,18 +369,32 @@
 if [ "$CONFIG_HP300" = "y" -a "$CONFIG_DIO" = "y" ]; then
   tristate 'HP DCA serial support' CONFIG_HPDCA
 fi
+if [ "$CONFIG_SUN3X" = "y" ]; then
+  bool 'Sun3x builtin serial support' CONFIG_SUN3X_ZS
+  if [ "$CONFIG_SUN3X_ZS" = "y" ]; then
+    bool 'Sun keyboard support' CONFIG_SUN_KEYBOARD
+    bool 'Sun mouse support' CONFIG_SUN_MOUSE
+    define_bool CONFIG_SBUS y
+    define_bool CONFIG_SBUSCHAR y
+    define_bool CONFIG_SUN_SERIAL y
+  fi  
+fi
 if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_ATARI" = "y" -o \
-     "$CONFIG_MAC" = "y" -o "$CONFIG_HP300" = "y" ]; then
+     "$CONFIG_MAC" = "y" -o "$CONFIG_HP300" = "y" -o \
+     "$CONFIG_SUN3X" = "y" ]; then
   if [ "$CONFIG_ATARI_MFPSER" = "y" -o "$CONFIG_ATARI_SCC" = "y" -o \
        "$CONFIG_ATARI_MIDI" = "y" -o "$CONFIG_MAC_SCC" = "y" -o \
        "$CONFIG_AMIGA_BUILTIN_SERIAL" = "y" -o \
        "$CONFIG_GVPIOEXT" = "y" -o "$CONFIG_MULTIFACE_III_TTY" = "y" -o \
-       "$CONFIG_HPDCA" = "y" ]; then
+       "$CONFIG_HPDCA" = "y" -o "$CONFIG_SUN3X_ZS" = "y" ]; then
     bool 'Support for serial port console' CONFIG_SERIAL_CONSOLE
   fi
 fi
 if [ "$CONFIG_VME" = "y" ]; then
   define_bool CONFIG_SERIAL_CONSOLE y
+  if [ "$CONFIG_MVME147" = "y" ]; then
+    bool 'SCC support for MVME147 serial ports' CONFIG_MVME147_SCC
+  fi
   if [ "$CONFIG_MVME16x" = "y" ]; then
     bool 'CD2401 support for MVME166/7 serial ports' CONFIG_SERIAL167
     bool 'SCC support for MVME162 serial ports' CONFIG_MVME162_SCC
diff -urN linux-2.2.8-pre7/arch/m68k/kernel/entry.S linux/arch/m68k/kernel/entry.S
--- linux-2.2.8-pre7/arch/m68k/kernel/entry.S	Tue Jan 19 10:58:26 1999
+++ linux/arch/m68k/kernel/entry.S	Mon Dec  3 18:46:54 2001
@@ -164,8 +164,17 @@
 
 	movel	%sp,%sp@-
 	movel	%d0,%sp@- 		|  put vector # on stack
+#if defined(MACH_Q40_ONLY) && defined(CONFIG_BLK_DEV_FD)
+	btstb	#4,0xff000000	| Q40 floppy needs very special treatment ...
+	jbeq	1f
+	btstb	#3,0xff000004		
+	jbeq	1f
+	jbsr	SYMBOL_NAME(floppy_hardint)
+	jbra	3f
+1:		
+#endif		
 	jbsr	SYMBOL_NAME(process_int)|  process the IRQ
-	addql	#8,%sp			|  pop parameters off stack
+3:     	addql	#8,%sp			|  pop parameters off stack
 
 SYMBOL_NAME_LABEL(ret_from_interrupt)
 	subql	#1,SYMBOL_NAME(local_irq_count)
@@ -295,6 +304,8 @@
 2:	fmovemx	%fp0-%fp7,%a0@(TASK_TSS+TSS_FPREG)
 	fmoveml	%fpcr/%fpsr/%fpiar,%a0@(TASK_TSS+TSS_FPCNTL)
 3:
+	/* Return previous task in %d1 */
+	movel	%curptr,%d1
 
 	/* switch to new task (a1 contains new task) */
 	movel	%a1,%curptr
@@ -320,7 +331,14 @@
 	movec	%d0,%cacr
 
 	/* switch the root pointer */
+#ifdef CPU_M68030_ONLY
+	.chip	68030
+	pmovefd	%a1@(TASK_TSS+TSS_CRP),%crp
+	.chip	68k
+	pflush	#0,#4
+#else
 	pmove	%a1@(TASK_TSS+TSS_CRP),%crp
+#endif
 #endif
 
 #if defined(CPU_M68020_OR_M68030) && defined(CPU_M68040_OR_M68060)
diff -urN linux-2.2.8-pre7/arch/m68k/kernel/head.S linux/arch/m68k/kernel/head.S
--- linux-2.2.8-pre7/arch/m68k/kernel/head.S	Tue Jan 19 10:58:26 1999
+++ linux/arch/m68k/kernel/head.S	Mon Dec  3 18:46:54 2001
@@ -23,6 +23,7 @@
 ** 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
+** 9/02/11  Richard Zidlicky: added Q40 support (initial vesion 99/01/01) 
 **
 ** 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
@@ -303,6 +304,12 @@
 .globl SYMBOL_NAME(availmem)
 .globl SYMBOL_NAME(m68k_pgtable_cachemode)
 .globl SYMBOL_NAME(m68k_supervisor_cachemode)
+#ifdef CONFIG_MVME16x
+.globl SYMBOL_NAME(mvme_bdid_ptr)
+#endif
+#ifdef CONFIG_Q40
+.globl SYMBOL_NAME(q40_mem_cptr)	
+#endif		
 
 CPUTYPE_040	= 1	/* indicates an 040 */
 CPUTYPE_060	= 2	/* indicates an 060 */
@@ -512,13 +519,15 @@
 #endif
 .endm
 
-
 #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_mvme147(lab) cmpl &MACH_MVME147,%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_not_q40(lab) cmpl &MACH_Q40,%pc@(m68k_machtype); jne lab
+#define is_not_sun3x(lab) cmpl &MACH_SUN3X,%pc@(m68k_machtype); jne lab
 
 #define is_040_or_060(lab)	btst &CPUTYPE_0460,%pc@(L(cputype)+3); jne lab
 #define is_not_040_or_060(lab)	btst &CPUTYPE_0460,%pc@(L(cputype)+3); jeq lab
@@ -552,9 +561,11 @@
 	.long	BOOTINFOV_MAGIC
 	.long	MACH_AMIGA, AMIGA_BOOTI_VERSION
 	.long	MACH_ATARI, ATARI_BOOTI_VERSION
+	.long	MACH_MVME147, MVME147_BOOTI_VERSION
 	.long	MACH_MVME16x, MVME16x_BOOTI_VERSION
 	.long	MACH_BVME6000, BVME6000_BOOTI_VERSION
 	.long	MACH_MAC, MAC_BOOTI_VERSION
+	.long	MACH_Q40, Q40_BOOTI_VERSION	
 	.long	0
 1:	jra	SYMBOL_NAME(__start)
 
@@ -859,7 +870,12 @@
 	/*
 	 * 040: Map the 16Meg range physical 0x0 upto logical 0x8000.0000
 	 */
-	mmu_map	#0x80000000,#0,#0x01000000,#_PAGE_NOCACHE_S
+	mmu_map		#0x80000000,#0,#0x01000000,#_PAGE_NOCACHE_S
+	/*
+	 * Map the Zorro III I/O space with transparent translation
+	 * for frame buffer memory etc.
+	 */
+	mmu_map_tt	#1,#0x40000000,#0x20000000,#_PAGE_NOCACHE_S
 
 	jbra	L(mmu_init_done)
 
@@ -867,7 +883,8 @@
 	/*
 	 * 030:	Map the 32Meg range physical 0x0 upto logical 0x8000.0000
 	 */
-	mmu_map	#0x80000000,#0,#0x02000000,#_PAGE_NOCACHE030
+	mmu_map		#0x80000000,#0,#0x02000000,#_PAGE_NOCACHE030
+	mmu_map_tt	#1,#0x40000000,#0x20000000,#_PAGE_NOCACHE030
 
 	jbra	L(mmu_init_done)
 
@@ -926,6 +943,25 @@
 L(mmu_init_not_atari):
 #endif
 
+#ifdef CONFIG_Q40
+	is_not_q40(L(notq40))
+	/*
+	 * add transparent mapping for 0xff00 0000 - 0xffff ffff
+	 * non-cached serialized etc..
+	 * this includes master chip, DAC, RTC and ISA ports
+	 * 0xfe000000-0xfeffffff is for screen and ROM
+	 */
+
+	putc    'Q'
+
+	mmu_map_tt	#0,#0xfe000000,#0x01000000,#_PAGE_CACHE040W
+	mmu_map_tt	#1,#0xff000000,#0x01000000,#_PAGE_NOCACHE_S
+	
+	jbra	L(mmu_init_done)
+	
+L(notq40):		
+#endif	
+	
 #ifdef CONFIG_HP300
 	is_not_hp300(L(nothp300))
 
@@ -940,6 +976,24 @@
 
 #endif
 
+#ifdef CONFIG_MVME147
+
+       is_not_mvme147(L(not147))
+
+       /*
+	* On MVME147 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,
+	* so we can access on-board i/o areas.
+	*/
+
+       mmu_map_tt      #1,#0xe0000000,#0x20000000,#_PAGE_NOCACHE030
+
+       jbra    L(mmu_init_done)
+
+L(not147):
+#endif /* CONFIG_MVME147 */
+
 #ifdef CONFIG_MVME16x
 
 	is_not_mvme16x(L(not16x))
@@ -965,7 +1019,7 @@
 	 * 0xffe00000->0xffe1ffff.
 	 */
 
-	mmu_map_tt	1,#0xe0000000,#0x20000000,#_PAGE_NOCACHE_S
+	mmu_map_tt	#1,#0xe0000000,#0x20000000,#_PAGE_NOCACHE_S
 
 	jbra	L(mmu_init_done)
 
@@ -985,7 +1039,7 @@
 	 * clash with User code virtual address space.
 	 */
 
-	mmu_map_tt	1,#0xe0000000,#0x20000000,#_PAGE_NOCACHE_S
+	mmu_map_tt	#1,#0xe0000000,#0x20000000,#_PAGE_NOCACHE_S
 
 	jbra	L(mmu_init_done)
 
@@ -1052,13 +1106,23 @@
 	mmu_map_eq	#0x50000000,#0x02000000,%d3
 	mmu_map_eq	#0x60000000,#0x00400000,%d3
 	mmu_map_eq	#0x9c000000,#0x00400000,%d3
-	mmu_map_tt	1,#0xf8000000,#0x08000000,%d3
+	mmu_map_tt	#1,#0xf8000000,#0x08000000,%d3
 
 	jbra	L(mmu_init_done)
 
 L(mmu_init_not_mac):
 #endif
 
+#ifdef CONFIG_SUN3X
+	is_not_sun3x(L(notsun3x))
+
+	/* setup tt1 for I/O */
+	mmu_map_tt	#1,#0x40000000,#0x40000000,#_PAGE_NOCACHE_S
+
+L(notsun3x):
+	jbra	L(mmu_init_done)
+#endif
+
 L(mmu_init_done):
 
 	putc	'G'
@@ -1214,6 +1278,14 @@
 1:
 #endif
 
+#ifdef CONFIG_SUN3X
+	is_not_sun3x(1f)
+
+	/* enable copro */
+	oriw	#0x4000,0x61000000
+1:
+#endif
+
 /*
  * Fixup the addresses for the kernel pointer table and availmem.
  * Convert them from physical addresses to virtual addresses.
@@ -1780,7 +1852,7 @@
 	/* Extract the highest bit set
 	 */
 	bfffo	ARG3{#0,#32},%d1
-	cmpw	#8,%d0
+	cmpw	#8,%d1
 	jcc	L(do_map)
 
 	/* And get the mask
@@ -2155,7 +2227,9 @@
 	/* Temporary allocate a page table and insert it into the ptr table
 	 */
 	movel	%a1@,%d0
-	addl	#PTR_TABLE_SIZE*4,%a1@
+	/* The 512 should be PAGE_TABLE_SIZE*4, but that violates the
+	   alignment restriction for pointer tables on the '0[46]0.  */
+	addl	#512,%a1@
 	orw	#_PAGE_TABLE+_PAGE_ACCESSED,%d0
 	movel	%d0,%a0@
 	dputs	" (new)"
@@ -2703,6 +2777,31 @@
 L(serial_init_not_mac):
 #endif	/* CONFIG_MAC */
 
+#ifdef CONFIG_Q40
+	is_not_q40(2f)
+/* debug output goes into SRAM, so we don't do it unless requested
+   - check for '%LX$' signature in SRAM   */
+	lea	%pc@(SYMBOL_NAME(q40_mem_cptr)),%a1
+	move.l	#0xff020010,%a1@  /* must be inited - also used by debug=mem */
+	move.l	#0xff020000,%a1   
+	cmp.b	#'%',%a1@
+	bne	2f	/*nodbg*/
+	addq.w	#4,%a1
+	cmp.b	#'L',%a1@
+	bne	2f	/*nodbg*/
+	addq.w	#4,%a1
+	cmp.b	#'X',%a1@
+	bne	2f	/*nodbg*/
+	addq.w	#4,%a1
+	cmp.b	#'$',%a1@
+	bne	2f	/*nodbg*/
+	/* signature OK */
+	lea	%pc@(L(q40_do_debug)),%a1
+	tas	%a1@
+/*nodbg: q40_do_debug is 0 by default*/	
+2:		
+#endif	
+	
 L(serial_init_done):
 func_return	serial_init
 
@@ -2792,6 +2891,15 @@
 4:
 #endif	/* CONFIG_ATARI */
 
+#ifdef CONFIG_MVME147
+	is_not_mvme147(2f)
+1:	btst	#2,M147_SCC_CTRL_A
+	jeq	1b
+	moveb	%d0,M147_SCC_DATA_A
+	jbra	L(serial_putc_done)
+2:
+#endif
+
 #ifdef CONFIG_MVME16x
 	is_not_mvme16x(2f)
 	/*
@@ -2805,7 +2913,7 @@
 	moveml	%sp@+,%d0-%d7/%a2-%a6
 	jbra	L(serial_putc_done)
 2:
-#endif CONFIG_MVME162 | CONFIG_MVME167
+#endif CONFIG_MVME16x
 
 #ifdef CONFIG_BVME6000
 	is_not_bvme6000(2f)
@@ -2819,6 +2927,18 @@
 2:
 #endif
 
+#ifdef CONFIG_Q40
+	is_not_q40(2f)
+	tst.l	%pc@(L(q40_do_debug))	/* only debug if requested */
+	beq	2f
+	lea	%pc@(SYMBOL_NAME(q40_mem_cptr)),%a1
+	move.l	%a1@,%a0
+	move.b	%d0,%a0@
+	addq.l	#4,%a0
+	move.l	%a0,%a1@
+2:		
+#endif	
+
 L(serial_putc_done):
 func_return	serial_putc
 
@@ -3472,6 +3592,10 @@
 L(temp_mmap_mem):
 	.long	0
 
+#if defined (CONFIG_MVME147)
+M147_SCC_CTRL_A = 0xfffe3002
+M147_SCC_DATA_A = 0xfffe3003
+#endif
 
 #if defined (CONFIG_BVME6000)
 BVME_SCC_CTRL_A	= 0xffb0000b
@@ -3508,4 +3632,10 @@
 #if defined(CONFIG_MVME16x)
 SYMBOL_NAME_LABEL(mvme_bdid_ptr)
 	.long	0
+#endif
+#if defined(CONFIG_Q40)
+SYMBOL_NAME_LABEL(q40_mem_cptr)
+	.long 0
+L(q40_do_debug):	
+	.long 0	
 #endif
diff -urN linux-2.2.8-pre7/arch/m68k/kernel/ints.c linux/arch/m68k/kernel/ints.c
--- linux-2.2.8-pre7/arch/m68k/kernel/ints.c	Sat Jun 13 13:14:32 1998
+++ linux/arch/m68k/kernel/ints.c	Mon Dec  3 18:46:54 2001
@@ -38,6 +38,10 @@
 #include <asm/page.h>
 #include <asm/machdep.h>
 
+#ifdef CONFIG_Q40
+#include <asm/q40ints.h>
+#endif
+
 /* table for system interrupt handlers */
 static irq_handler_t irq_list[SYS_IRQS];
 
@@ -177,14 +181,24 @@
 
 /*
  * Do we need these probe functions on the m68k?
+ *
+ *  ... may be usefull with ISA devices
  */
 unsigned long probe_irq_on (void)
 {
+#ifdef CONFIG_Q40
+	if (MACH_IS_Q40)
+		return q40_probe_irq_on();
+#endif
 	return 0;
 }
 
 int probe_irq_off (unsigned long irqs)
 {
+#ifdef CONFIG_Q40
+	if (MACH_IS_Q40)
+		return q40_probe_irq_off(irqs);
+#endif
 	return 0;
 }
 
diff -urN linux-2.2.8-pre7/arch/m68k/kernel/m68k_defs.h linux/arch/m68k/kernel/m68k_defs.h
--- linux-2.2.8-pre7/arch/m68k/kernel/m68k_defs.h	Tue Jan  5 11:20:43 1999
+++ linux/arch/m68k/kernel/m68k_defs.h	Mon Dec  3 18:46:54 2001
@@ -3,6 +3,47 @@
  */
 
 #define TS_MAGICKEY	0x5a5a5a5a
-#define TS_TSS 482
-#define TS_ESP0 502
-#define TS_FPU 506
+#define TASK_STATE 0
+#define TASK_FLAGS 4
+#define TASK_SIGPENDING 8
+#define TASK_NEEDRESCHED 20
+#define TASK_TSS 470
+#define TASK_MM 622
+#define TSS_KSP 0
+#define TSS_USP 4
+#define TSS_SR 8
+#define TSS_FS 10
+#define TSS_CRP 12
+#define TSS_ESP0 20
+#define TSS_FPREG 24
+#define TSS_FPCNTL 120
+#define TSS_FPSTATE 132
+#define PT_D0 32
+#define PT_ORIG_D0 36
+#define PT_SR 44
+#define PT_VECTOR 50
+#define IRQ_HANDLER 0
+#define IRQ_DEVID 8
+#define IRQ_NEXT 16
+#define STAT_IRQ 120
+#define BIR_TAG 0
+#define BIR_SIZE 2
+#define BIR_DATA 4
+#define FBCON_FONT_DESC_IDX 0
+#define FBCON_FONT_DESC_NAME 4
+#define FBCON_FONT_DESC_WIDTH 8
+#define FBCON_FONT_DESC_HEIGHT 12
+#define FBCON_FONT_DESC_DATA 16
+#define FBCON_FONT_DESC_PREF 20
+#define CUSTOMBASE -2132807680
+#define C_INTENAR 28
+#define C_INTREQR 30
+#define C_INTENA 154
+#define C_INTREQ 156
+#define C_SERDATR 24
+#define C_SERDAT 48
+#define C_SERPER 50
+#define CIAABASE -2134908927
+#define CIABBASE -2134913024
+#define C_PRA 0
+#define ZTWOBASE -2147483648
diff -urN linux-2.2.8-pre7/arch/m68k/kernel/m68k_ksyms.c linux/arch/m68k/kernel/m68k_ksyms.c
--- linux-2.2.8-pre7/arch/m68k/kernel/m68k_ksyms.c	Tue Jan 19 10:58:34 1999
+++ linux/arch/m68k/kernel/m68k_ksyms.c	Mon Dec  3 18:46:54 2001
@@ -18,6 +18,7 @@
 #include <asm/checksum.h>
 #include <asm/hardirq.h>
 #include <asm/softirq.h>
+#include <asm/m68kserial.h>
 
 asmlinkage long long __ashrdi3 (long long, int);
 extern char m68k_debug_device[];
@@ -54,6 +55,8 @@
 EXPORT_SYMBOL(disable_irq);
 EXPORT_SYMBOL(kernel_set_cachemode);
 EXPORT_SYMBOL(kernel_thread);
+EXPORT_SYMBOL(register_serial);
+EXPORT_SYMBOL(unregister_serial);
 
 /* Networking helper routines. */
 EXPORT_SYMBOL(csum_partial_copy);
@@ -69,4 +72,5 @@
 
 EXPORT_SYMBOL_NOVERS(__down_failed);
 EXPORT_SYMBOL_NOVERS(__down_failed_interruptible);
+EXPORT_SYMBOL_NOVERS(__down_failed_trylock);
 EXPORT_SYMBOL_NOVERS(__up_wakeup);
diff -urN linux-2.2.8-pre7/arch/m68k/kernel/process.c linux/arch/m68k/kernel/process.c
--- linux-2.2.8-pre7/arch/m68k/kernel/process.c	Tue Jan 19 10:58:34 1999
+++ linux/arch/m68k/kernel/process.c	Mon Dec  3 18:46:54 2001
@@ -169,15 +169,7 @@
 
 asmlinkage int m68k_vfork(struct pt_regs *regs)
 {
-	int     child;
-	struct semaphore sem = MUTEX_LOCKED;
-
-	child = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs);
-
-	if (child > 0)
-		down(&sem);
-
-	return child;
+	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs);
 }
 
 asmlinkage int m68k_clone(struct pt_regs *regs)
@@ -190,7 +182,7 @@
 	newsp = regs->d2;
 	if (!newsp)
 		newsp = rdusp();
-	return do_fork(clone_flags & ~CLONE_VFORK, newsp, regs);
+	return do_fork(clone_flags, newsp, regs);
 }
 
 int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
diff -urN linux-2.2.8-pre7/arch/m68k/kernel/ptrace.c linux/arch/m68k/kernel/ptrace.c
--- linux-2.2.8-pre7/arch/m68k/kernel/ptrace.c	Tue Jan 19 10:58:34 1999
+++ linux/arch/m68k/kernel/ptrace.c	Mon Dec  3 18:46:54 2001
@@ -312,6 +312,7 @@
 asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
 {
 	struct task_struct *child;
+	unsigned long flags;
 	int ret;
 
 	lock_kernel();
@@ -343,21 +344,22 @@
 		    (current->uid != child->uid) ||
 	 	    (current->gid != child->egid) ||
 		    (current->gid != child->sgid) ||
+	 	    (!cap_issubset(child->cap_permitted, current->cap_permitted)) ||
 	 	    (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE))
 			goto out;
 		/* the same process cannot be attached many times */
 		if (child->flags & PF_PTRACED)
 			goto out;
 		child->flags |= PF_PTRACED;
-		if (child->p_pptr != current) {
-			unsigned long flags;
 
-			write_lock_irqsave(&tasklist_lock, flags);
+		write_lock_irqsave(&tasklist_lock, flags);
+		if (child->p_pptr != current) {
 			REMOVE_LINKS(child);
 			child->p_pptr = current;
 			SET_LINKS(child);
-			write_unlock_irqrestore(&tasklist_lock, flags);
 		}
+		write_unlock_irqrestore(&tasklist_lock, flags);
+
 		send_sig(SIGSTOP, child, 1);
 		ret = 0;
 		goto out;
@@ -502,7 +504,6 @@
 		}
 
 		case PTRACE_DETACH: { /* detach a process that was attached. */
-			unsigned long flags;
 			long tmp;
 
 			ret = -EIO;
diff -urN linux-2.2.8-pre7/arch/m68k/kernel/setup.c linux/arch/m68k/kernel/setup.c
--- linux-2.2.8-pre7/arch/m68k/kernel/setup.c	Tue Jan 19 10:58:34 1999
+++ linux/arch/m68k/kernel/setup.c	Mon Dec  3 18:46:54 2001
@@ -77,10 +77,26 @@
 int (*mach_set_clock_mmss) (unsigned long) = NULL;
 void (*mach_reset)( void );
 long mach_max_dma_address = 0x00ffffff; /* default set to the lower 16MB */
-#if defined(CONFIG_AMIGA_FLOPPY) || defined(CONFIG_ATARI_FLOPPY)
+#if defined(CONFIG_AMIGA_FLOPPY) || defined(CONFIG_ATARI_FLOPPY) || defined(CONFIG_BLK_DEV_FD)
 void (*mach_floppy_setup) (char *, int *) __initdata = NULL;
 void (*mach_floppy_eject) (void) = NULL;
 #endif
+struct serial_struct;
+#ifdef CONFIG_SERIAL
+long serial_rs_init(void);
+int serial_register_serial(struct serial_struct *);
+void serial_unregister_serial(int);
+long ser_console_init(long, long );
+#endif
+#if defined(CONFIG_USERIAL)||defined(CONFIG_BVME6000_SCC)||defined(CONFIG_MVME162_SCC)||defined(CONFIG_HPDCA)||defined(CONFIG_WHIPPET_SERIAL)||defined(CONFIG_MULTIFACE_III_TTY)||defined(CONFIG_GVPIOEXT)||defined(CONFIG_AMIGA_BUILTIN_SERIAL)||defined(CONFIG_MAC_SCC)||defined(CONFIG_ATARI_MIDI)||defined(CONFIG_ATARI_SCC)||defined(CONFIG_ATARI_MFPSER)
+#define M68K_SERIAL
+#endif
+#ifdef M68K_SERIAL
+long m68k_rs_init(void);
+int m68k_register_serial(struct serial_struct *);
+void m68k_unregister_serial(int);
+long m68k_serial_console_init(long, long );
+#endif
 #ifdef CONFIG_HEARTBEAT
 void (*mach_heartbeat) (int) = NULL;
 #endif
@@ -97,15 +113,19 @@
 extern int amiga_parse_bootinfo(const struct bi_record *);
 extern int atari_parse_bootinfo(const struct bi_record *);
 extern int mac_parse_bootinfo(const struct bi_record *);
+extern int q40_parse_bootinfo(const struct bi_record *);
 
 extern void config_amiga(void);
 extern void config_atari(void);
 extern void config_mac(void);
 extern void config_sun3(void);
 extern void config_apollo(void);
+extern void config_mvme147(void);
 extern void config_mvme16x(void);
 extern void config_bvme6000(void);
 extern void config_hp300(void);
+extern void config_q40(void);
+extern void config_sun3x(void);
 
 #define MASK_256K 0xfffc0000
 
@@ -149,6 +169,8 @@
 		    unknown = atari_parse_bootinfo(record);
 		else if (MACH_IS_MAC)
 		    unknown = mac_parse_bootinfo(record);
+		else if (MACH_IS_Q40)
+		    unknown = q40_parse_bootinfo(record);
 		else
 		    unknown = 1;
 	}
@@ -258,6 +280,11 @@
 	    	config_apollo();
 	    	break;
 #endif
+#ifdef CONFIG_MVME147
+	    case MACH_MVME147:
+	    	config_mvme147();
+	    	break;
+#endif
 #ifdef CONFIG_MVME16x
 	    case MACH_MVME16x:
 	    	config_mvme16x();
@@ -273,6 +300,16 @@
 		config_hp300();
 		break;
 #endif
+#ifdef CONFIG_Q40
+	    case MACH_Q40:
+	        config_q40();
+		break;
+#endif
+#ifdef CONFIG_SUN3X
+	    case MACH_SUN3X:
+		config_sun3x();
+		break;
+#endif
 	    default:
 		panic ("No configuration setup");
 	}
@@ -384,7 +421,52 @@
     return(len);
 }
 
-#if defined(CONFIG_AMIGA_FLOPPY) || defined(CONFIG_ATARI_FLOPPY)
+#if defined(CONFIG_SERIAL) || defined(M68K_SERIAL)
+int rs_init(void)
+{
+#ifdef CONFIG_SERIAL
+  if (MACH_IS_Q40)
+    return serial_rs_init();
+#endif
+#ifdef M68K_SERIAL  
+    return m68k_rs_init();
+#endif
+}
+int register_serial(struct serial_struct *p)
+{
+#ifdef CONFIG_SERIAL
+  if (MACH_IS_Q40)
+    return serial_register_serial(p);
+#endif
+#ifdef M68K_SERIAL
+  return m68k_register_serial(p);
+#endif
+}
+void unregister_serial(int i)
+{
+#ifdef CONFIG_SERIAL
+  if (MACH_IS_Q40)
+    serial_unregister_serial(i);
+#endif
+#ifdef M68K_SERIAL
+  m68k_unregister_serial(i);
+#endif
+}
+#ifdef CONFIG_SERIAL_CONSOLE
+long serial_console_init(long kmem_start, long kmem_end)
+{
+#ifdef CONFIG_SERIAL
+  if (MACH_IS_Q40)
+    return ser_console_init(kmem_start, kmem_end);
+#endif
+#if defined(M68K_SERIAL) && defined(CONFIG_SERIAL_CONSOLE)
+  return m68k_serial_console_init(kmem_start, kmem_end);
+#endif
+}
+#endif
+#endif
+
+#if defined(CONFIG_AMIGA_FLOPPY) || defined(CONFIG_ATARI_FLOPPY) || defined(CONFIG_BLK_DEV_FD)
 __initfunc(void floppy_setup(char *str, int *ints))
 {
 	if (mach_floppy_setup)
@@ -399,7 +481,7 @@
 #endif
 
 /* for "kbd-reset" cmdline param */
-void __init kbd_reset_setup(char *str, int *ints)
+__initfunc(void kbd_reset_setup(char *str, int *ints))
 {
 }
 
diff -urN linux-2.2.8-pre7/arch/m68k/kernel/time.c linux/arch/m68k/kernel/time.c
--- linux-2.2.8-pre7/arch/m68k/kernel/time.c	Thu Mar 11 23:25:10 1999
+++ linux/arch/m68k/kernel/time.c	Mon Dec  3 18:46:54 2001
@@ -200,5 +200,5 @@
 	time_status |= STA_UNSYNC;
 	time_maxerror = NTP_PHASE_LIMIT;
 	time_esterror = NTP_PHASE_LIMIT;
-	sti();
+	write_unlock_irq(&xtime_lock);
 }
diff -urN linux-2.2.8-pre7/arch/m68k/lib/semaphore.S linux/arch/m68k/lib/semaphore.S
--- linux-2.2.8-pre7/arch/m68k/lib/semaphore.S	Sat May 24 09:10:22 1997
+++ linux/arch/m68k/lib/semaphore.S	Mon Dec  3 18:46:54 2001
@@ -32,6 +32,16 @@
 	movel (%sp)+,%a0
 	rts
 
+ENTRY(__down_failed_trylock)
+	movel %a0,-(%sp)
+	movel %d1,-(%sp)
+	movel %a1,-(%sp)
+	jbsr SYMBOL_NAME(__down_trylock)
+	movel (%sp)+,%a1
+	movel (%sp)+,%d1
+	movel (%sp)+,%a0
+	rts
+
 ENTRY(__up_wakeup)
 	moveml %a0/%d0/%d1,-(%sp)
 	movel %a1,-(%sp)
diff -urN linux-2.2.8-pre7/arch/m68k/mm/init.c linux/arch/m68k/mm/init.c
--- linux-2.2.8-pre7/arch/m68k/mm/init.c	Tue Jan 19 10:58:34 1999
+++ linux/arch/m68k/mm/init.c	Mon Dec  3 18:46:54 2001
@@ -123,7 +123,7 @@
 unsigned long mm_cachebits = 0;
 #endif
 
-static pte_t *__init kernel_page_table(unsigned long *memavailp)
+__initfunc(static pte_t * kernel_page_table(unsigned long *memavailp))
 {
 	pte_t *ptablep;
 
@@ -140,15 +140,19 @@
 
 static pmd_t *last_pgtable __initdata = NULL;
 
-static pmd_t *__init kernel_ptr_table(unsigned long *memavailp)
+__initfunc(static pmd_t * kernel_ptr_table(unsigned long *memavailp))
 {
 	if (!last_pgtable) {
 		unsigned long pmd, last;
 		int i;
 
+		/* Find the last ptr table that was used in head.S and
+		 * reuse the remaining space in that page for further
+		 * ptr tables.
+		 */
 		last = (unsigned long)kernel_pg_dir;
 		for (i = 0; i < PTRS_PER_PGD; i++) {
-			if (!pgd_val(kernel_pg_dir[i]))
+			if (!pgd_present(kernel_pg_dir[i]))
 				continue;
 			pmd = pgd_page(kernel_pg_dir[i]);
 			if (pmd > last)
@@ -175,8 +179,8 @@
 	return last_pgtable;
 }
 
-static unsigned long __init
-map_chunk (unsigned long addr, long size, unsigned long *memavailp)
+__initfunc(static unsigned long
+map_chunk (unsigned long addr, long size, unsigned long *memavailp))
 {
 #define PTRTREESIZE (256*1024)
 #define ROOTTREESIZE (32*1024*1024)
@@ -282,8 +286,8 @@
  * paging_init() continues the virtual memory environment setup which
  * was begun by the code in arch/head.S.
  */
-unsigned long __init paging_init(unsigned long start_mem,
-				 unsigned long end_mem)
+__initfunc(unsigned long paging_init(unsigned long start_mem,
+				     unsigned long end_mem))
 {
 	int chunk;
 	unsigned long mem_avail = 0;
@@ -392,7 +396,7 @@
 	return PAGE_ALIGN(free_area_init(start_mem, end_mem));
 }
 
-void __init mem_init(unsigned long start_mem, unsigned long end_mem)
+__initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
 {
 	int codepages = 0;
 	int datapages = 0;
@@ -443,7 +447,7 @@
 	/* insert pointer tables allocated so far into the tablelist */
 	init_pointer_table((unsigned long)kernel_pg_dir);
 	for (i = 0; i < PTRS_PER_PGD; i++) {
-		if (pgd_val(kernel_pg_dir[i]))
+		if (pgd_present(kernel_pg_dir[i]))
 			init_pointer_table(pgd_page(kernel_pg_dir[i]));
 	}
 
diff -urN linux-2.2.8-pre7/arch/m68k/mm/kmap.c linux/arch/m68k/mm/kmap.c
--- linux-2.2.8-pre7/arch/m68k/mm/kmap.c	Tue Jan 19 10:58:34 1999
+++ linux/arch/m68k/mm/kmap.c	Mon Dec  3 18:46:54 2001
@@ -116,6 +116,14 @@
 	if (!size || size > physaddr + size)
 		return NULL;
 
+#ifdef CONFIG_AMIGA
+	if (MACH_IS_AMIGA) {
+		if ((physaddr >= 0x40000000) && (physaddr + size < 0x60000000)
+		    && (cacheflag == IOMAP_NOCACHE_SER))
+			return (void *)physaddr;
+	}
+#endif
+
 #ifdef DEBUG
 	printk("ioremap: 0x%lx,0x%lx(%d) - ", physaddr, size, cacheflag);
 #endif
@@ -174,7 +182,7 @@
 		}
 	}
 
-	while (size > 0) {
+	while ((long)size > 0) {
 #ifdef DEBUG
 		if (!(virtaddr & (PTRTREESIZE-1)))
 			printk ("\npa=%#lx va=%#lx ", physaddr, virtaddr);
@@ -187,7 +195,7 @@
 		}
 
 		if (CPU_IS_020_OR_030) {
-			pmd_dir->pmd[(virtaddr/PTRTREESIZE)&-16] = physaddr;
+			pmd_dir->pmd[(virtaddr/PTRTREESIZE) & 15] = physaddr;
 			physaddr += PTRTREESIZE;
 			virtaddr += PTRTREESIZE;
 			size -= PTRTREESIZE;
@@ -217,7 +225,14 @@
  */
 void iounmap(void *addr)
 {
+#ifdef CONFIG_AMIGA
+	if ((!MACH_IS_AMIGA) ||
+	    (((unsigned long)addr < 0x40000000) ||
+	     ((unsigned long)addr > 0x60000000)))
+			free_io_area(addr);
+#else
 	free_io_area(addr);
+#endif
 }
 
 /*
@@ -232,7 +247,7 @@
 	pmd_t *pmd_dir;
 	pte_t *pte_dir;
 
-	while (size > 0) {
+	while ((long)size > 0) {
 		pgd_dir = pgd_offset_k(virtaddr);
 		if (pgd_bad(*pgd_dir)) {
 			printk("iounmap: bad pgd(%08lx)\n", pgd_val(*pgd_dir));
@@ -242,7 +257,7 @@
 		pmd_dir = pmd_offset(pgd_dir, virtaddr);
 
 		if (CPU_IS_020_OR_030) {
-			int pmd_off = (virtaddr/PTRTREESIZE) & -16;
+			int pmd_off = (virtaddr/PTRTREESIZE) & 15;
 
 			if ((pmd_dir->pmd[pmd_off] & _DESCTYPE_MASK) == _PAGE_PRESENT) {
 				pmd_dir->pmd[pmd_off] = 0;
@@ -308,7 +323,7 @@
 		}
 	}
 
-	while (size > 0) {
+	while ((long)size > 0) {
 		pgd_dir = pgd_offset_k(virtaddr);
 		if (pgd_bad(*pgd_dir)) {
 			printk("iocachemode: bad pgd(%08lx)\n", pgd_val(*pgd_dir));
@@ -318,7 +333,7 @@
 		pmd_dir = pmd_offset(pgd_dir, virtaddr);
 
 		if (CPU_IS_020_OR_030) {
-			int pmd_off = (virtaddr/PTRTREESIZE) & -16;
+			int pmd_off = (virtaddr/PTRTREESIZE) & 15;
 
 			if ((pmd_dir->pmd[pmd_off] & _DESCTYPE_MASK) == _PAGE_PRESENT) {
 				pmd_dir->pmd[pmd_off] = (pmd_dir->pmd[pmd_off] &
diff -urN linux-2.2.8-pre7/arch/m68k/mm/memory.c linux/arch/m68k/mm/memory.c
--- linux-2.2.8-pre7/arch/m68k/mm/memory.c	Tue Jan 19 10:58:34 1999
+++ linux/arch/m68k/mm/memory.c	Mon Dec  3 18:46:54 2001
@@ -11,6 +11,7 @@
 #include <linux/types.h>
 #include <linux/malloc.h>
 #include <linux/init.h>
+#include <linux/pagemap.h>
 
 #include <asm/setup.h>
 #include <asm/segment.h>
@@ -93,12 +94,11 @@
 static ptable_desc ptable_list = { &ptable_list, &ptable_list };
 
 #define PD_MARKBITS(dp) (*(unsigned char *)&(dp)->offset)
-#define PD_PAGE(dp) (PAGE_OFFSET + ((dp)->map_nr << PAGE_SHIFT))
 #define PAGE_PD(page) ((ptable_desc *)&mem_map[MAP_NR(page)])
 
 #define PTABLE_SIZE (PTRS_PER_PMD * sizeof(pmd_t))
 
-void __init init_pointer_table(unsigned long ptable)
+__initfunc(void init_pointer_table(unsigned long ptable))
 {
 	ptable_desc *dp;
 	unsigned long page = ptable & PAGE_MASK;
@@ -166,7 +166,7 @@
 		(dp->next = last->next)->prev = dp;
 		(dp->prev = last)->next = dp;
 	}
-	return (pmd_t *) (PD_PAGE(dp) + off);
+	return (pmd_t *) (page_address(dp) + off);
 }
 
 int free_pointer_table (pmd_t *ptable)
@@ -215,8 +215,8 @@
 	/* function code match? */
 	base = (regval >> 4) & 7;
 	mask = ~(regval & 7);
-	if ((SUPER_DATA & mask) != (base & mask))
-	    return( 0 );
+	if (((SUPER_DATA ^ base) & mask) != 0)
+	    return 0;
     }
     else {
 	/* must not be user-only */
@@ -226,8 +226,8 @@
 
     /* address match? */
     base = regval & 0xff000000;
-    mask = ~((regval << 8) & 0xff000000);
-    return( (vaddr & mask) == (base & mask) );
+    mask = ~(regval << 8) & 0xff000000;
+    return ((vaddr ^ base) & mask) == 0;
 }
 
 #ifndef CONFIG_SINGLE_MEMORY_CHUNK
diff -urN linux-2.2.8-pre7/arch/m68k/mvme147/147ints.c linux/arch/m68k/mvme147/147ints.c
--- linux-2.2.8-pre7/arch/m68k/mvme147/147ints.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/mvme147/147ints.c	Mon Dec  3 18:46:54 2001
@@ -0,0 +1,142 @@
+/*
+ * arch/m68k/mvme147/147ints.c
+ *
+ * Copyright (C) 1997 Richard Hirst [richard@sleepie.demon.co.uk]
+ *
+ * based on amiints.c -- Amiga Linux interrupt handling code
+ *
+ * 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.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+
+#include <asm/ptrace.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/traps.h>
+
+static void mvme147_defhand (int irq, void *dev_id, struct pt_regs *fp);
+
+/*
+ * This should ideally be 4 elements only, for speed.
+ */
+
+static struct {
+	void		(*handler)(int, void *, struct pt_regs *);
+	unsigned long	flags;
+	void		*dev_id;
+	const char	*devname;
+	unsigned	count;
+} irq_tab[256];
+
+/*
+ * void mvme147_init_IRQ (void)
+ *
+ * Parameters:	None
+ *
+ * Returns:	Nothing
+ *
+ * This function is called during kernel startup to initialize
+ * the mvme147 IRQ handling routines.
+ */
+
+void mvme147_init_IRQ (void)
+{
+	int i;
+
+	for (i = 0; i < 256; i++) {
+		irq_tab[i].handler = mvme147_defhand;
+		irq_tab[i].flags = IRQ_FLG_STD;
+		irq_tab[i].dev_id = NULL;
+		irq_tab[i].devname = NULL;
+		irq_tab[i].count = 0;
+	}
+}
+
+int mvme147_request_irq(unsigned int irq,
+		void (*handler)(int, void *, struct pt_regs *),
+                unsigned long flags, const char *devname, void *dev_id)
+{
+	if (irq > 255) {
+		printk("%s: Incorrect IRQ %d from %s\n", __FUNCTION__, irq, devname);
+		return -ENXIO;
+	}
+	if (!(irq_tab[irq].flags & IRQ_FLG_STD)) {
+		if (irq_tab[irq].flags & IRQ_FLG_LOCK) {
+			printk("%s: IRQ %d from %s is not replaceable\n",
+			       __FUNCTION__, irq, irq_tab[irq].devname);
+			return -EBUSY;
+		}
+		if (flags & IRQ_FLG_REPLACE) {
+			printk("%s: %s can't replace IRQ %d from %s\n",
+			       __FUNCTION__, devname, irq, irq_tab[irq].devname);
+			return -EBUSY;
+		}
+	}
+	irq_tab[irq].handler = handler;
+	irq_tab[irq].flags   = flags;
+	irq_tab[irq].dev_id  = dev_id;
+	irq_tab[irq].devname = devname;
+	return 0;
+}
+
+void mvme147_free_irq(unsigned int irq, void *dev_id)
+{
+	if (irq > 255) {
+		printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq);
+		return;
+	}
+	if (irq_tab[irq].dev_id != dev_id)
+		printk("%s: Removing probably wrong IRQ %d from %s\n",
+		       __FUNCTION__, irq, irq_tab[irq].devname);
+
+	irq_tab[irq].handler = mvme147_defhand;
+	irq_tab[irq].flags   = IRQ_FLG_STD;
+	irq_tab[irq].dev_id  = NULL;
+	irq_tab[irq].devname = NULL;
+}
+
+void mvme147_process_int (unsigned long vec, struct pt_regs *fp)
+{
+	if (vec > 255)
+		printk ("mvme147_process_int: Illegal vector %ld\n", vec);
+	else
+	{
+		irq_tab[vec].count++;
+		irq_tab[vec].handler(vec, irq_tab[vec].dev_id, fp);
+	}
+}
+
+int mvme147_get_irq_list (char *buf)
+{
+	int i, len = 0;
+
+	for (i = 0; i < 256; i++) {
+		if (irq_tab[i].count)
+			len += sprintf (buf+len, "Vec 0x%02x: %8d  %s\n",
+			    i, irq_tab[i].count,
+			    irq_tab[i].devname ? irq_tab[i].devname : "free");
+	}
+	return len;
+}
+
+
+static void mvme147_defhand (int irq, void *dev_id, struct pt_regs *fp)
+{
+	printk ("Unknown interrupt 0x%02x\n", irq);
+}
+
+void mvme147_enable_irq (unsigned int irq)
+{
+}
+
+
+void mvme147_disable_irq (unsigned int irq)
+{
+}
+
diff -urN linux-2.2.8-pre7/arch/m68k/mvme147/Makefile linux/arch/m68k/mvme147/Makefile
--- linux-2.2.8-pre7/arch/m68k/mvme147/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/mvme147/Makefile	Mon Dec  3 18:46:54 2001
@@ -0,0 +1,14 @@
+#
+# Makefile for Linux arch/m68k/mvme147 source directory
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+
+O_TARGET := mvme147.o
+O_OBJS   := config.o 147ints.o
+
+
+include $(TOPDIR)/Rules.make
+
diff -urN linux-2.2.8-pre7/arch/m68k/mvme147/config.c linux/arch/m68k/mvme147/config.c
--- linux-2.2.8-pre7/arch/m68k/mvme147/config.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/mvme147/config.c	Mon Dec  3 18:46:54 2001
@@ -0,0 +1,240 @@
+/*
+ *  arch/m68k/mvme147/config.c
+ *
+ *  Copyright (C) 1996 Dave Frascone [chaos@mindspring.com]
+ *  Cloned from        Richard Hirst [richard@sleepie.demon.co.uk]
+ *
+ * Based on:
+ *
+ *  Copyright (C) 1993 Hamish Macdonald
+ *
+ * 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.
+ */
+
+#include <linux/config.h>
+#include <stdarg.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/kd.h>
+#include <linux/tty.h>
+#include <linux/console.h>
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <linux/major.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/setup.h>
+#include <asm/irq.h>
+#include <asm/traps.h>
+#include <asm/machdep.h>
+#include <asm/mvme147hw.h>
+
+
+extern void mvme147_process_int (int level, struct pt_regs *regs);
+extern void mvme147_init_IRQ (void);
+extern void mvme147_free_irq (unsigned int, void *);
+extern int  mvme147_get_irq_list (char *);
+extern void mvme147_enable_irq (unsigned int);
+extern void mvme147_disable_irq (unsigned int);
+static void mvme147_get_model(char *model);
+static int  mvme147_get_hardware_list(char *buffer);
+extern int mvme147_request_irq (unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id);
+extern void mvme147_sched_init(void (*handler)(int, void *, struct pt_regs *));
+extern int mvme147_keyb_init(void);
+extern int mvme147_kbdrate (struct kbd_repeat *);
+extern unsigned long mvme147_gettimeoffset (void);
+extern void mvme147_gettod (int *year, int *mon, int *day, int *hour,
+                           int *min, int *sec);
+extern int mvme147_hwclk (int, struct hwclk_time *);
+extern int mvme147_set_clock_mmss (unsigned long);
+extern void mvme147_check_partition (struct gendisk *hd, unsigned int dev);
+extern void mvme147_reset (void);
+extern void mvme147_waitbut(void);
+
+
+static int bcd2int (unsigned char b);
+
+/* Save tick handler routine pointer, will point to do_timer() in
+ * kernel/sched.c, called via mvme147_process_int() */
+
+void (*tick_handler)(int, void *, struct pt_regs *);
+
+
+int mvme147_kbdrate (struct kbd_repeat *k)
+{
+	return 0;
+}
+
+void mvme147_reset()
+{
+	printk ("\r\n\nCalled mvme147_reset\r\n");
+	m147_pcc->watchdog = 0x0a;	/* Clear timer */
+	m147_pcc->watchdog = 0xa5;	/* Enable watchdog - 100ms to reset */
+	while (1)
+		;
+}
+
+static void mvme147_get_model(char *model)
+{
+	sprintf(model, "Motorola MVME147");
+}
+
+
+static int mvme147_get_hardware_list(char *buffer)
+{
+	*buffer = '\0';
+
+	return 0;
+}
+
+
+__initfunc(void config_mvme147(void))
+{
+	mach_sched_init		= mvme147_sched_init;
+	mach_keyb_init		= mvme147_keyb_init;
+	mach_kbdrate		= mvme147_kbdrate;
+	mach_init_IRQ		= mvme147_init_IRQ;
+	mach_gettimeoffset	= mvme147_gettimeoffset;
+	mach_gettod		= mvme147_gettod;
+	mach_hwclk		= mvme147_hwclk;
+	mach_set_clock_mmss	= mvme147_set_clock_mmss;
+	mach_reset		= mvme147_reset;
+	mach_free_irq		= mvme147_free_irq;
+	mach_process_int	= mvme147_process_int;
+	mach_get_irq_list	= mvme147_get_irq_list;
+	mach_request_irq	= mvme147_request_irq;
+	enable_irq		= mvme147_enable_irq;
+	disable_irq		= mvme147_disable_irq;
+	mach_get_model		= mvme147_get_model;
+	mach_get_hardware_list	= mvme147_get_hardware_list;
+}
+
+
+/* Using pcc tick timer 1 */
+
+static void mvme147_timer_int (int irq, void *dev_id, struct pt_regs *fp)
+{
+	m147_pcc->t1_int_cntrl = PCC_TIMER_INT_CLR;  
+	m147_pcc->t1_int_cntrl = PCC_INT_ENAB|PCC_LEVEL_TIMER1;   
+	tick_handler(irq, dev_id, fp);
+}
+
+
+void mvme147_sched_init (void (*timer_routine)(int, void *, struct pt_regs *))
+{
+	tick_handler = timer_routine;
+	request_irq (PCC_IRQ_TIMER1, mvme147_timer_int, 
+		IRQ_FLG_REPLACE, "timer 1", NULL);
+	
+	/* Init the clock with a value */
+	/* our clock goes off every 6.25us */
+	m147_pcc->t1_preload = PCC_TIMER_PRELOAD;
+	m147_pcc->t1_cntrl = 0x0;   	/* clear timer */
+	m147_pcc->t1_cntrl = 0x3; 	/* start timer */
+	m147_pcc->t1_int_cntrl = PCC_TIMER_INT_CLR;  /* clear pending ints */
+	m147_pcc->t1_int_cntrl = PCC_INT_ENAB|PCC_LEVEL_TIMER1;   
+}
+
+/* This is always executed with interrupts disabled.  */
+/* XXX There are race hazards in this code XXX */
+unsigned long mvme147_gettimeoffset (void)
+{
+	volatile unsigned short *cp = (volatile unsigned short *)0xfffe1012;
+	unsigned short n;
+
+	n = *cp;
+	while (n != *cp)
+		n = *cp;
+
+	n -= PCC_TIMER_PRELOAD;
+	return (unsigned long)n * 25 / 4;
+}
+
+extern void mvme147_gettod (int *year, int *mon, int *day, int *hour,
+                           int *min, int *sec)
+{
+	m147_rtc->ctrl = RTC_READ;
+	*year = bcd2int (m147_rtc->bcd_year);
+	*mon = bcd2int (m147_rtc->bcd_mth);
+	*day = bcd2int (m147_rtc->bcd_dom);
+	*hour = bcd2int (m147_rtc->bcd_hr);
+	*min = bcd2int (m147_rtc->bcd_min);
+	*sec = bcd2int (m147_rtc->bcd_sec);
+	m147_rtc->ctrl = 0;
+}
+
+static int bcd2int (unsigned char b)
+{
+	return ((b>>4)*10 + (b&15));
+}
+
+int mvme147_hwclk(int op, struct hwclk_time *t)
+{
+	return 0;
+}
+
+int mvme147_set_clock_mmss (unsigned long nowtime)
+{
+	return 0;
+}
+
+int mvme147_keyb_init (void)
+{
+	return 0;
+}
+
+/*-------------------  Serial console stuff ------------------------*/
+
+void m147_scc_write(struct console *co, const char *str, unsigned cnt);
+
+
+void mvme147_init_console_port (struct console *co, int cflag)
+{
+	co->write = m147_scc_write;
+}
+
+
+static void scc_delay (void)
+{
+	int n;
+	volatile int trash;
+
+	for (n = 0; n < 20; n++)
+		trash = n;
+}
+
+static void scc_write (char ch)
+{
+	volatile char *p = (volatile char *)M147_SCC_A_ADDR;
+
+	do {
+		scc_delay();
+	}
+	while (!(*p & 4));
+	scc_delay();
+	*p = 8;
+	scc_delay();
+	*p = ch;
+}
+
+
+void m147_scc_write (struct console *co, const char *str, unsigned count)
+{
+	unsigned long	flags;
+
+	save_flags(flags);
+	cli();
+
+	while (count--)
+	{
+		if (*str == '\n')
+			scc_write ('\r');
+		scc_write (*str++);
+	}
+	restore_flags(flags);
+}
+
diff -urN linux-2.2.8-pre7/arch/m68k/mvme16x/config.c linux/arch/m68k/mvme16x/config.c
--- linux-2.2.8-pre7/arch/m68k/mvme16x/config.c	Sat Jun 13 13:14:33 1998
+++ linux/arch/m68k/mvme16x/config.c	Mon Dec  3 18:46:54 2001
@@ -335,10 +335,10 @@
 static void scc_delay (void)
 {
 	int n;
-	char i;
+	volatile int trash;
 
 	for (n = 0; n < 20; n++)
-		i = *(volatile char *)0;
+		trash = n;
 }
 
 static void scc_write (char ch)
diff -urN linux-2.2.8-pre7/arch/m68k/q40/Makefile linux/arch/m68k/q40/Makefile
--- linux-2.2.8-pre7/arch/m68k/q40/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/q40/Makefile	Mon Dec  3 18:46:54 2001
@@ -0,0 +1,14 @@
+#
+# Makefile for Linux arch/m68k/q40 source directory
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+O_TARGET := q40.o
+O_OBJS   := config.o q40ints.o 
+
+
+include $(TOPDIR)/Rules.make
diff -urN linux-2.2.8-pre7/arch/m68k/q40/README linux/arch/m68k/q40/README
--- linux-2.2.8-pre7/arch/m68k/q40/README	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/q40/README	Mon Dec  3 18:46:54 2001
@@ -0,0 +1,121 @@
+Linux for the Q40
+=================
+
+You may try http://www.geocities.com/SiliconValley/Bay/2602/ for
+some up to date information. Booter and other tools will be also
+available from this place and ftp.uni-erlangen.de/linux/680x0/q40/
+and mirrors.
+
+Hints to documentation usually refer to the linux source tree in
+/usr/src/linux unless URL given.
+
+It seems IRQ unmasking can't be safely done on a Q40. Autoprobing is 
+not yet implemented - do not try it! (See below)
+
+For a list of kernel commandline options read the documentation for the
+particular device drivers.
+
+The floppy imposes a very high interrupt load on the CPU, approx 30K/s.
+When something blocks interrupts (HD) it will loose some of them, so far 
+this is not known to have caused any data loss. On hihgly loaded systems
+it can make the floppy very slow. Other Q40 OS' simply poll the floppy
+for this reason - something that can't be done in Linux.
+Only possible cure is getting a 82072 contoler with fifo instead of 
+the 8272A
+
+drivers used by the Q40, appart from the very obvious (console etc.):
+	drivers/char/q40_keyb.c		# use PC keymaps for national keyboards
+		     serial.c		# normal PC driver - any speed
+	             lp.c		# printer driver
+		char/joystick/*		# most of this should work
+	        block/q40ide.c		# startup for ide
+		      ide*		# see Documentation/ide.txt
+		      floppy.c		# normal PC driver, DMA emu in asm/floppy.h
+					# and arch/m68k/kernel/entry.S
+					# see drivers/block/README.fd
+		video/q40fb.c
+		misc/parport_pc.c
+
+Various other PC drivers can be enabled simply by adding them to 
+arch/m68k/config.in, especially 8 bit devices should be without any
+problems. For cards using 16bit io/mem more care is required, like 
+checking byteorder issues, hacking memcpy_*_io etc.
+
+
+Debugging
+=========
+
+Upon startup the kernel will usually output "ABCQGHIJ" into the SRAM, 
+preceded by the booter signature. This is a trace just in case something 
+went wrong during earliest setup stages. 
+*Changed* to preserve SRAM contents by default, this is only done when 
+requested - SRAM must start with '%LX$' signature to do this. '-d' option 
+to 'lxx' loader enables this.
+
+SRAM can also be used as additional console device, use debug=mem.
+This will save kernel startup msgs into SRAM, the screen will display 
+only the penguin - and shell prompt if it gets that far..
+
+Serial console works and can also be used for debugging, provided serial
+initialisation works.
+
+Most problems seem to be caused by fawlty or badly configured io-cards or 
+harddrives anyway..there are so many things that can go wrong here.
+Make sure to configure the parallel port as SPP for first testing..the
+Q40 may have trouble with parallel interrupts.
+
+
+Q40 Hardware Description
+========================
+
+This is just an overview, see asm-m68k/* for details ask if you have any 
+questions.
+
+The Q40 consists of a 68040@40 MHz, 1MB video RAM, up to 32MB RAM, AT-style
+keyboard interface, 1 Programmable LED, 2 8bit DACs and up to 1MB ROM, 1MB
+shadow ROM.
+
+Most interfacing like floppy, hd, serial, parallel ports is done via ISA 
+slots. The ISA io and mem range is mapped (sparse&byteswapped!) into separate 
+regions of the memory.
+The main interrupt register IIRQ_REG will indicate whether an IRQ was internal 
+or from some ISA devices, EIRQ_REG can distinguish up to 8 ISA IRQs.
+
+The Q40 custom chip is programmable to provide 2 periodic timers:
+	- 50 or 200 Hz - level 2,  !!THIS CANT BE DISABLED!!
+	- 10 or 20 KHz - level 4 (and possibly 6 - hardware decoding..)
+
+Linux uses the 200 Hz interrupt for timer and beep by default.
+
+
+Interrupts
+==========
+
+q40 master chip handles only level triggered interrupts :-((
+further limitation is no disabling etc. Unless someone finds 
+some ingenious clue this means autoprobing will never work.
+Parallel port interrupts cause most trouble..
+
+IRQ sharing is not yet implemented.
+
+
+Keyboard
+========
+
+q40 receives AT make/break codes from the keyboard, these are translated to
+the PC scancodes x86 Linux uses. So by theory every national keyboard should
+work just by loading the apropriate x86 keytable - see any national-HOWTO.
+
+Unfortunately the AT->PC translation isn't quite trivial and even worse, my 
+documentation of it is absolutely minimal - thus some exotic keys may not 
+behave exactly as expected.
+
+There is still hope that it can be fixed completely though. If you encounter 
+problems, email me idealy this:
+	- exact keypress/release sequence
+	- 'showkey -s' run on q40, non-X session
+	- 'showkey -s' run on a PC, non-X session
+	- AT codes as displayed by the q40 debuging ROM
+btw if the showkey output from PC and Q40 doesn't differ then you have some
+classic configuration problem - don't send me anything in this case
+
diff -urN linux-2.2.8-pre7/arch/m68k/q40/config.c linux/arch/m68k/q40/config.c
--- linux-2.2.8-pre7/arch/m68k/q40/config.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/q40/config.c	Mon Dec  3 18:46:54 2001
@@ -0,0 +1,425 @@
+/*
+ *  arch/m68k/q40/config.c
+ *
+ * originally based on:
+ *
+ *  linux/bvme/config.c
+ *
+ *  Copyright (C) 1993 Hamish Macdonald
+ *
+ * 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.
+ */
+
+#include <stdarg.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/kd.h>
+#include <linux/tty.h>
+#include <linux/console.h>
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <linux/major.h>
+
+#include <asm/bootinfo.h>
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/setup.h>
+#include <asm/irq.h>
+#include <asm/traps.h>
+#include <asm/machdep.h>
+#include <asm/q40_master.h>
+#include <asm/keyboard.h>
+
+extern void fd_floppy_eject(void);
+extern void fd_floppy_setup(char *str, int *ints);
+
+extern void q40_process_int (int level, struct pt_regs *regs);
+extern void (*q40_sys_default_handler[]) (int, void *, struct pt_regs *);  /* added just for debugging */
+extern void q40_init_IRQ (void);
+extern void q40_free_irq (unsigned int, void *);
+extern int  q40_get_irq_list (char *);
+extern void q40_enable_irq (unsigned int);
+extern void q40_disable_irq (unsigned int);
+static void q40_get_model(char *model);
+static int  q40_get_hardware_list(char *buffer);
+extern int  q40_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id);
+extern void q40_sched_init(void (*handler)(int, void *, struct pt_regs *));
+extern int  q40_keyb_init(void);
+extern int  q40_kbdrate (struct kbd_repeat *);
+extern unsigned long q40_gettimeoffset (void);
+extern void q40_gettod (int *year, int *mon, int *day, int *hour,
+                           int *min, int *sec);
+extern int q40_hwclk (int, struct hwclk_time *);
+extern int q40_set_clock_mmss (unsigned long);
+extern void q40_reset (void);
+extern void q40_waitbut(void);
+void q40_set_vectors (void);
+extern void (*kd_mksound)(unsigned int, unsigned int);
+void q40_mksound(unsigned int /*freq*/, unsigned int /*ticks*/ );
+
+extern char *saved_command_line;
+extern char m68k_debug_device[];
+static void q40_mem_console_write(struct console *co, const char *b,
+				    unsigned int count);
+
+static int ql_ticks=0;
+static int sound_ticks=0;
+
+static unsigned char bcd2bin (unsigned char b);
+static unsigned char bin2bcd (unsigned char b);
+
+static int q40_wait_key(struct console *co){return 0;}
+static struct console q40_console_driver = {
+	"debug",
+	NULL,			/* write */
+	NULL,			/* read */
+	NULL,			/* device */
+	q40_wait_key,		/* wait_key */
+	NULL,			/* unblank */
+	NULL,			/* setup */
+	CON_PRINTBUFFER,
+	-1,
+	0,
+	NULL
+};
+
+
+/* Save tick handler routine pointer, will point to do_timer() in
+ * kernel/sched.c */
+
+/* static void (*tick_handler)(int, void *, struct pt_regs *); */
+
+
+/* early debugging function:*/
+extern char *q40_mem_cptr; /*=(char *)0xff020000;*/
+static int _cpleft;
+
+static void q40_mem_console_write(struct console *co, const char *s,
+				  unsigned int count)
+{
+  char *p=(char *)s;
+
+  if (count<_cpleft)
+    while (count-- >0){
+      *q40_mem_cptr=*p++;
+      q40_mem_cptr+=4;
+      _cpleft--;
+    }
+}
+#if 0
+void printq40(char *str)
+{
+  int l=strlen(str);
+  char *p=q40_mem_cptr;
+
+  while (l-- >0 && _cpleft-- >0)
+    {
+      *p=*str++;
+      p+=4;
+    }
+  q40_mem_cptr=p;
+}
+#endif
+
+#if 0
+int q40_kbdrate (struct kbd_repeat *k)
+{
+	return 0;
+}
+#endif
+
+void q40_reset()
+{
+
+	printk ("\n\n*******************************************\n"
+                     "Called q40_reset : press the RESET button!! \n");
+	printk(     "*******************************************\n");
+
+	while(1)
+		;
+}
+
+static void q40_get_model(char *model)
+{
+    sprintf(model, "Q40");
+}
+
+
+/* No hardware options on Q40? */
+
+static int q40_get_hardware_list(char *buffer)
+{
+    *buffer = '\0';
+    return 0;
+}
+
+
+__initfunc(void config_q40(void))
+{
+    mach_sched_init      = q40_sched_init;           /* ok */
+    /*mach_kbdrate         = q40_kbdrate;*/          /* unneeded ?*/
+    mach_keyb_init       = q40_keyb_init;            /* OK */
+    mach_init_IRQ        = q40_init_IRQ;   
+    mach_gettimeoffset   = q40_gettimeoffset; 
+    mach_gettod  	 = q40_gettod;
+    mach_hwclk           = q40_hwclk; 
+    mach_set_clock_mmss	 = q40_set_clock_mmss;
+/*  mach_mksound         = q40_mksound; */
+    mach_reset		 = q40_reset;           /* use reset button instead !*/
+    mach_free_irq	 = q40_free_irq; 
+    mach_process_int	 = q40_process_int;
+    mach_get_irq_list	 = q40_get_irq_list;
+    mach_request_irq	 = q40_request_irq;
+    enable_irq		 = q40_enable_irq;
+    disable_irq          = q40_disable_irq;
+    mach_default_handler = &q40_sys_default_handler;
+    mach_get_model       = q40_get_model; /* no use..*/
+    mach_get_hardware_list = q40_get_hardware_list; /* no use */
+    kd_mksound             = q40_mksound;
+    /*mach_kbd_leds        = q40kbd_leds;*/
+#ifdef CONFIG_MAGIC_SYSRQ
+    mach_sysrq_key       = 0x54;
+#endif
+    conswitchp = &dummy_con;
+#ifdef CONFIG_BLK_DEV_FD
+    mach_floppy_setup    = fd_floppy_setup;
+    mach_floppy_eject    = fd_floppy_eject;
+    /**/
+#endif
+
+    mach_max_dma_address = 0;   /* no DMA at all */
+
+
+/* userfull for early debuging stages writes kernel messages into SRAM */
+
+    if (!strncmp( m68k_debug_device,"mem",3 ))
+      {
+	/*printk("using NVRAM debug, q40_mem_cptr=%p\n",q40_mem_cptr);*/
+	_cpleft=2000-((long)q40_mem_cptr-0xff020000)/4;
+	q40_console_driver.write = q40_mem_console_write;
+	register_console(&q40_console_driver);
+      }
+}
+
+
+int q40_parse_bootinfo(const struct bi_record *rec)
+{
+  return 1;  /* unknown */
+}
+
+#define DAC_LEFT  ((unsigned char *)0xff008000)
+#define DAC_RIGHT ((unsigned char *)0xff008004)
+void q40_mksound(unsigned int hz, unsigned int ticks)
+{
+  /* for now ignore hz, except that hz==0 switches off sound */
+  /* simply alternate the ampl 0-255-0-.. at 200Hz */
+  if (hz==0)
+    {
+      if (sound_ticks)
+	sound_ticks=1; /* atomic - no irq spinlock used */
+
+      *DAC_LEFT=0;
+      *DAC_RIGHT=0;
+
+      return;
+    }
+  /* sound itself is done in q40_timer_int */
+  if (sound_ticks == 0) sound_ticks=1000; /* pretty long beep */
+  sound_ticks=ticks<<1;
+}
+
+static void (*q40_timer_routine)(int, void *, struct pt_regs *);
+
+static void q40_timer_int (int irq, void *dev_id, struct pt_regs *fp)
+{
+#if (HZ==10000)
+    master_outb(-1,SAMPLE_CLEAR_REG);
+#else /* must be 50 or 100 */
+    master_outb(-1,FRAME_CLEAR_REG);
+#endif
+
+#if (HZ==100)
+    ql_ticks = ql_ticks ? 0 : 1;
+    if (sound_ticks)
+      {
+	unsigned char sval=(sound_ticks & 1) ? 0 : 255;
+	sound_ticks--;
+	*DAC_LEFT=sval;
+	*DAC_RIGHT=sval;
+      }
+    if (ql_ticks) return;
+#endif
+    q40_timer_routine(irq, dev_id, fp);
+}
+
+
+void q40_sched_init (void (*timer_routine)(int, void *, struct pt_regs *))
+{
+    int timer_irq;
+
+    q40_timer_routine = timer_routine;
+
+#if (HZ==10000)
+    timer_irq=Q40_IRQ_TIMER;
+#else
+    timer_irq=Q40_IRQ_FRAME;
+#endif
+
+    /*printk("registering sched/timer IRQ %d\n", timer_irq);*/
+
+    if (request_irq(timer_irq, q40_timer_int, 0,
+				"timer", q40_timer_int))
+	panic ("Couldn't register timer int");
+
+#if (HZ==10000)
+    master_outb(SAMPLE_LOW,SAMPLE_RATE_REG);
+    master_outb(-1,SAMPLE_CLEAR_REG);
+    master_outb(1,SAMPLE_ENABLE_REG);
+#else
+    master_outb(-1,FRAME_CLEAR_REG);   /* not necessary ? */
+#if (HZ==100)
+    master_outb( 1,FRAME_RATE_REG);
+#endif
+#endif
+}
+
+
+unsigned long q40_gettimeoffset (void)
+{
+#if (HZ==100)
+    return 5000*(ql_ticks!=0);
+#else
+    return 0;
+#endif
+}
+
+extern void q40_gettod (int *year, int *mon, int *day, int *hour,
+                           int *min, int *sec)
+{
+	RTC_CTRL |= RTC_READ;
+	*year = bcd2bin (RTC_YEAR);
+	*mon = bcd2bin (RTC_MNTH)-1;
+	*day = bcd2bin (RTC_DATE);
+	*hour = bcd2bin (RTC_HOUR);
+	*min = bcd2bin (RTC_MINS);
+	*sec = bcd2bin (RTC_SECS);
+	RTC_CTRL &= ~(RTC_READ);
+
+}
+
+static unsigned char bcd2bin (unsigned char b)
+{
+	return ((b>>4)*10 + (b&15));
+}
+
+static unsigned char bin2bcd (unsigned char b)
+{
+	return (((b/10)*16) + (b%10));
+}
+
+
+/*
+ * Looks like op is non-zero for setting the clock, and zero for
+ * reading the clock.
+ *
+ *  struct hwclk_time {
+ *         unsigned        sec;       0..59
+ *         unsigned        min;       0..59
+ *         unsigned        hour;      0..23
+ *         unsigned        day;       1..31
+ *         unsigned        mon;       0..11
+ *         unsigned        year;      00...
+ *         int             wday;      0..6, 0 is Sunday, -1 means unknown/don't set
+ * };
+ */
+
+int q40_hwclk(int op, struct hwclk_time *t)
+{
+        if (op)
+	{	/* Write.... */
+	        RTC_CTRL |= RTC_WRITE;
+
+		RTC_SECS = bin2bcd(t->sec);
+		RTC_MINS = bin2bcd(t->min);
+		RTC_HOUR = bin2bcd(t->hour);
+		RTC_DATE = bin2bcd(t->day);
+		RTC_MNTH = bin2bcd(t->mon + 1);
+		RTC_YEAR = bin2bcd(t->year%100);
+		if (t->wday >= 0)
+			RTC_DOW = bin2bcd(t->wday+1);
+
+	        RTC_CTRL &= ~(RTC_WRITE);
+	}
+	else
+	{	/* Read....  */
+	  RTC_CTRL |= RTC_READ;
+
+	  t->year = bcd2bin (RTC_YEAR);
+	  t->mon  = bcd2bin (RTC_MNTH)-1;
+	  t->day  = bcd2bin (RTC_DATE);
+	  t->hour = bcd2bin (RTC_HOUR);
+	  t->min  = bcd2bin (RTC_MINS);
+	  t->sec  = bcd2bin (RTC_SECS);
+
+	  RTC_CTRL &= ~(RTC_READ);
+	  
+	  if (t->year < 70)
+	    t->year += 100;
+	  t->wday = bcd2bin(RTC_DOW)-1;
+
+	}
+
+	return 0;
+}
+
+/*
+ * Set the minutes and seconds from seconds value 'nowtime'.  Fail if
+ * clock is out by > 30 minutes.  Logic lifted from atari code.
+ * Algorithm is to wait for the 10ms register to change, and then to
+ * wait a short while, and then set it.
+ */
+
+int q40_set_clock_mmss (unsigned long nowtime)
+{
+	int retval = 0;
+	short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
+
+	int rtc_minutes;
+
+
+	rtc_minutes = bcd2bin (RTC_MINS);
+
+	if ((rtc_minutes < real_minutes
+		? real_minutes - rtc_minutes
+			: rtc_minutes - real_minutes) < 30)
+	{	   
+	        RTC_CTRL |= RTC_WRITE;
+		RTC_MINS = bin2bcd(real_minutes);
+		RTC_SECS = bin2bcd(real_seconds);
+		RTC_CTRL &= ~(RTC_WRITE);
+	}
+	else
+		retval = -1;
+
+
+	return retval;
+}
+
+extern void q40kbd_init_hw(void);
+
+int q40_keyb_init (void)
+{
+        q40kbd_init_hw();
+	return 0;
+}
+
+#if 0
+/* dummy to cause */
+void q40_slow_io()
+{
+  return;
+}
+#endif
diff -urN linux-2.2.8-pre7/arch/m68k/q40/q40ints.c linux/arch/m68k/q40/q40ints.c
--- linux-2.2.8-pre7/arch/m68k/q40/q40ints.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/q40/q40ints.c	Mon Dec  3 18:46:54 2001
@@ -0,0 +1,347 @@
+/*
+ * arch/m68k/q40/q40ints.c
+ *
+ * Copyright (C) 1999 Richard Zidlicky
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ *
+ * losely based on bvme6000ints.c
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+
+#include <asm/ptrace.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/traps.h>
+
+#include <asm/q40_master.h>
+#include <asm/q40ints.h>
+
+/* 
+ * Q40 IRQs are defined as follows: 
+ *            3,4,5,6,7,10,11,14,15 : ISA dev IRQs
+ *            16-31: reserved
+ *            32   : keyboard int
+ *            33   : frame int (50 Hz periodic timer)
+ *            34   : sample int (10/20 KHz periodic timer)
+ *          
+*/
+
+extern int ints_inited;
+
+
+void q40_irq2_handler (int, void *, struct pt_regs *fp);
+
+
+extern void (*q40_sys_default_handler[]) (int, void *, struct pt_regs *);  /* added just for debugging */
+
+static void q40_defhand (int irq, void *dev_id, struct pt_regs *fp);
+static void sys_default_handler(int lev, void *dev_id, struct pt_regs *regs);
+
+/*
+ * This should ideally be 4 elements only, for speed.
+ */
+
+#define DEVNAME_SIZE 24
+
+static struct {
+	void		(*handler)(int, void *, struct pt_regs *);
+	unsigned long	flags;
+	void		*dev_id;
+        char	        devname[DEVNAME_SIZE];
+	unsigned	count;
+} irq_tab[Q40_IRQ_MAX+1];
+
+/*
+ * void q40_init_IRQ (void)
+ *
+ * Parameters:	None
+ *
+ * Returns:	Nothing
+ *
+ * This function is called during kernel startup to initialize
+ * the q40 IRQ handling routines.
+ */
+
+void q40_init_IRQ (void)
+{
+	int i;
+
+	for (i = 0; i <= Q40_IRQ_MAX; i++) {
+		irq_tab[i].handler = q40_defhand;
+		irq_tab[i].flags = IRQ_FLG_STD;
+		irq_tab[i].dev_id = NULL;
+		irq_tab[i].devname[0] = 0;
+		irq_tab[i].count = 0;
+	}
+
+	/* setup handler for ISA ints */
+	sys_request_irq(IRQ2,q40_irq2_handler, IRQ_FLG_LOCK, "q40 ISA and master chip", NULL);
+
+	/* now enable some ints.. */
+
+#if 0  /* has been abandoned */
+	master_outb(1,SER_ENABLE_REG);
+#endif
+	master_outb(1,EXT_ENABLE_REG);
+
+	/* would be spurious ints by now, q40kbd_init_hw() does that */
+	master_outb(0,KEY_IRQ_ENABLE_REG);
+}
+
+int q40_request_irq(unsigned int irq,
+		void (*handler)(int, void *, struct pt_regs *),
+                unsigned long flags, const char *devname, void *dev_id)
+{
+  /*printk("q40_request_irq %d, %s\n",irq,devname);*/
+
+	if (irq > Q40_IRQ_MAX || (irq>15 && irq<32)) {
+		printk("%s: Incorrect IRQ %d from %s\n", __FUNCTION__, irq, devname);
+		return -ENXIO;
+	}
+
+	/* test for ISA ints not implemented by HW */
+	if (irq<15) 
+	  {
+	    switch (irq){
+	    case 1: case 2: case 8: case 9:
+	    case 12: case 13:
+	      printk("%s: ISA IRQ %d from %s not implemented by HW\n", __FUNCTION__, irq, devname);
+	      return -ENXIO;
+	    default:
+	    }
+	  }
+
+	if (irq<Q40_IRQ_TIMER)
+	  {
+	    if (irq==11) {
+	      printk("warning IRQ 10 and 11 not distinguishable\n");
+	      irq=10;
+	    }
+	    if (!(irq_tab[irq].flags & IRQ_FLG_STD)) 
+	      {
+		if (irq_tab[irq].flags & IRQ_FLG_LOCK) 
+		  {
+		    printk("%s: IRQ %d from %s is not replaceable\n",
+			   __FUNCTION__, irq, irq_tab[irq].devname);
+		    return -EBUSY;
+		  }
+		if (flags & IRQ_FLG_REPLACE) 
+		  {
+		    printk("%s: %s can't replace IRQ %d from %s\n",
+			   __FUNCTION__, devname, irq, irq_tab[irq].devname);
+		    return -EBUSY;
+		  }
+	      }
+	    /*printk("IRQ %d set to handler %p\n",irq,handler);*/
+	    irq_tab[irq].handler = handler;
+	    irq_tab[irq].flags   = flags;
+	    irq_tab[irq].dev_id  = dev_id;
+	    strncpy(irq_tab[irq].devname,devname,DEVNAME_SIZE);
+	    return 0;
+	  }
+	else {
+	  /* Q40_IRQ_TIMER :somewhat special actions required here ..*/
+	  sys_request_irq(4,handler,flags,devname,dev_id);
+	  sys_request_irq(6,handler,flags,devname,dev_id);
+	  return 0;
+	}
+}
+
+void q40_free_irq(unsigned int irq, void *dev_id)
+{
+	if (irq > Q40_IRQ_MAX || (irq>15 && irq<32)) {
+		printk("%s: Incorrect IRQ %d, dev_id %x \n", __FUNCTION__, irq, (unsigned)dev_id);
+		return;
+	}
+
+	/* test for ISA ints not implemented by HW */
+	if (irq<15) {
+	  switch (irq){
+	  case 1: case 2: case 8: case 9:
+	  case 12: case 13:
+	        printk("%s: ISA IRQ %d from %x illegal\n", __FUNCTION__, irq, (unsigned)dev_id);
+		return;
+	  default:
+		  }
+	}
+	
+	if (irq<Q40_IRQ_TIMER){
+	  if (irq==11) irq=10;
+	  if (irq_tab[irq].dev_id != dev_id)
+	    printk("%s: Removing probably wrong IRQ %d from %s\n",
+		   __FUNCTION__, irq, irq_tab[irq].devname);
+	  
+	  irq_tab[irq].handler = q40_defhand;
+	  irq_tab[irq].flags   = IRQ_FLG_STD;
+	  irq_tab[irq].dev_id  = NULL;
+	  /* irq_tab[irq].devname = NULL; */
+	} else { /* == Q40_IRQ_TIMER */
+	  sys_free_irq(4,dev_id);
+	  sys_free_irq(6,dev_id);
+	}
+}
+
+#if 1
+void q40_process_int (int level, struct pt_regs *fp)
+{
+  printk("unexpected interrupt %x\n",level);
+}
+#endif
+
+/* 
+ * tables to translate bits into IRQ numbers 
+ * it is a good idea to order the entries by priority
+ * 
+*/
+
+struct IRQ_TABLE{ unsigned mask; int irq ;};
+
+static struct IRQ_TABLE iirqs[]={
+  {IRQ_FRAME_MASK,Q40_IRQ_FRAME},
+  {IRQ_KEYB_MASK,Q40_IRQ_KEYBOARD},
+  {0,0}};
+static struct IRQ_TABLE eirqs[]={
+  {IRQ3_MASK,3},                   /* ser 1 */
+  {IRQ4_MASK,4},                   /* ser 2 */
+  {IRQ14_MASK,14},                 /* IDE 1 */
+  {IRQ15_MASK,15},                 /* IDE 2 */
+  {IRQ6_MASK,6},                   /* floppy */
+  {IRQ7_MASK,7},                   /* par */
+
+  {IRQ5_MASK,5},
+  {IRQ10_MASK,10},
+
+
+
+
+  {0,0}};
+
+/* complaiun only this many times about spurious ints : */
+static int ccleirq=60;    /* ISA dev IRQ's*/
+static int cclirq=60;     /* internal */
+
+/* FIX: add IRQ_INPROGRESS,mask,unmask,probing.... */
+
+void q40_irq2_handler (int vec, void *devname, struct pt_regs *fp)
+{
+  /* got level 2 interrupt, dispatch to ISA or keyboard IRQs */
+
+        unsigned mir=master_inb(IIRQ_REG);
+	unsigned mer;
+	int irq,i;
+
+	/*
+	 *  more than 1 bit might be set, must handle atmost 1 int source,
+	 *  - handle only those with explicitly set handler
+	 */
+
+	if ((mir&IRQ_SER_MASK) || (mir&IRQ_EXT_MASK)) 
+	  {
+	    
+	    /* some ISA dev caused the int */
+	    
+	    mer=master_inb(EIRQ_REG);
+	    
+	    for (i=0; eirqs[i].mask; i++)
+	      {
+		if (mer&(eirqs[i].mask)) 
+		  {
+		    irq=eirqs[i].irq;
+		    irq_tab[irq].count++;
+		    if (irq_tab[irq].handler == q40_defhand )
+		      continue; /* ignore uninited INTs :-( */
+		    
+		    irq_tab[irq].handler(irq,irq_tab[irq].dev_id,fp);
+		    return;
+		  }
+	      }
+	    if (ccleirq>0) 
+	      printk("ISA interrupt from unknown source? EIRQ_REG = %x\n",mer),ccleirq--;
+	  } 
+	else 
+	  {
+	    /* internal */
+
+	    for (i=0; iirqs[i].mask; i++)
+	      {
+		if (mir&(iirqs[i].mask)) 
+		  {
+		    irq=iirqs[i].irq;
+		    irq_tab[irq].count++;
+		    if (irq_tab[irq].handler == q40_defhand )
+		      continue; /* ignore uninited INTs :-( */
+		    
+		    irq_tab[irq].handler(irq,irq_tab[irq].dev_id,fp);
+		    return;
+		  }
+	      }
+	    if (cclirq>0)
+	      printk("internal level 2 interrupt from unknown source ? IIRQ_REG=%x\n",mir),cclirq--;
+	  }
+}
+
+int q40_get_irq_list (char *buf)
+{
+	int i, len = 0;
+
+	for (i = 0; i <= Q40_IRQ_MAX; i++) {
+		if (irq_tab[i].count)
+			len += sprintf (buf+len, "Vec 0x%02x: %8d  %s%s\n",
+			    i, irq_tab[i].count,
+			    irq_tab[i].devname[0] ? irq_tab[i].devname : "?",
+			    irq_tab[i].handler == q40_defhand ? 
+					" (now unassigned)" : "");
+	}
+	return len;
+}
+
+
+static void q40_defhand (int irq, void *dev_id, struct pt_regs *fp)
+{
+#if 0
+	printk ("Unknown q40 interrupt 0x%02x\n", irq);
+#endif
+}
+static void sys_default_handler(int lev, void *dev_id, struct pt_regs *regs)
+{
+#if 0
+        if (ints_inited)
+#endif
+	  printk ("Uninitialised interrupt level %d\n", lev);
+#if 0
+	else
+	  printk ("Interrupt before interrupt initialisation\n");
+#endif
+}
+
+ void (*q40_sys_default_handler[SYS_IRQS]) (int, void *, struct pt_regs *) = {
+   sys_default_handler,sys_default_handler,sys_default_handler,sys_default_handler,
+   sys_default_handler,sys_default_handler,sys_default_handler,sys_default_handler
+ };
+
+void q40_enable_irq (unsigned int irq)
+{
+}
+
+
+void q40_disable_irq (unsigned int irq)
+{
+}
+
+unsigned long q40_probe_irq_on (void)
+{
+  printk("sorry, irq probing not yet implemented - reconfigure the driver to avoid this\n");
+  return 0;
+}
+int q40_probe_irq_off (unsigned long irqs)
+{
+  return -1;
+}
diff -urN linux-2.2.8-pre7/arch/m68k/sun3x/Makefile linux/arch/m68k/sun3x/Makefile
--- linux-2.2.8-pre7/arch/m68k/sun3x/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/sun3x/Makefile	Mon Dec  3 18:46:54 2001
@@ -0,0 +1,14 @@
+#
+# Makefile for Linux arch/m68k/sun3x source directory
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+O_TARGET := sun3x.o
+O_OBJS   := config.o time.o dvma.o sbus.o
+OX_OBJS  := 
+
+include $(TOPDIR)/Rules.make
diff -urN linux-2.2.8-pre7/arch/m68k/sun3x/config.c linux/arch/m68k/sun3x/config.c
--- linux-2.2.8-pre7/arch/m68k/sun3x/config.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/sun3x/config.c	Mon Dec  3 18:46:54 2001
@@ -0,0 +1,128 @@
+/*
+ * Setup kernel for a Sun3x machine
+ *
+ * (C) 1999 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
+ *
+ * based on code from Oliver Jowett <oliver@jowett.manawatu.gen.nz>
+ */
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/console.h>
+#include <linux/init.h>
+
+#include <asm/system.h>
+#include <asm/machdep.h>
+#include <asm/irq.h>
+#include <asm/sun3x.h>
+
+#include "time.h"
+
+static volatile unsigned char *sun3x_intreg = (unsigned char *)SUN3X_INTREG;
+extern int serial_console;
+
+void sun3x_halt(void)
+{
+    /* Disable interrupts */
+    cli();
+
+    /* we can't drop back to PROM, so we loop here */
+    for (;;);
+}
+
+void sun3x_reboot(void)
+{
+    /* This never returns, don't bother saving things */
+    cli();
+
+    /* no idea, whether this works */
+    asm ("reset");
+}
+
+__initfunc(int sun3x_keyb_init(void))
+{
+    return 0;
+}
+
+int sun3x_kbdrate(struct kbd_repeat *r)
+{
+    return 0;
+}
+
+void sun3x_kbd_leds(unsigned int i)
+{
+
+}
+
+static void sun3x_badint (int irq, void *dev_id, struct pt_regs *fp)
+{
+    printk ("received spurious interrupt %d\n",irq);
+    num_spurious += 1;
+}
+
+void (*sun3x_default_handler[SYS_IRQS])(int, void *, struct pt_regs *) = {
+    sun3x_badint, sun3x_badint, sun3x_badint, sun3x_badint,
+    sun3x_badint, sun3x_badint, sun3x_badint, sun3x_badint
+};
+
+void sun3x_enable_irq(unsigned int irq)
+{
+    *sun3x_intreg |= (1 << irq);
+}
+
+void sun3x_disable_irq(unsigned int irq)
+{
+    *sun3x_intreg &= ~(1 << irq);
+}
+
+__initfunc(void sun3x_init_IRQ(void))
+{
+    /* disable all interrupts initially */
+    *sun3x_intreg = 1;  /* master enable only */
+}
+
+int sun3x_get_irq_list(char *buf)
+{
+    return 0;
+}
+
+/*
+ *  Setup the sun3x configuration info
+ */
+__initfunc(void config_sun3x(void))
+{
+    mach_get_irq_list	 = sun3x_get_irq_list;
+    mach_max_dma_address = 0xffffffff; /* we can DMA anywhere, whee */
+
+    mach_keyb_init       = sun3x_keyb_init;
+    mach_kbdrate         = sun3x_kbdrate;
+    mach_kbd_leds        = sun3x_kbd_leds;
+
+    mach_sched_init      = sun3x_sched_init;
+    mach_init_IRQ        = sun3x_init_IRQ;
+    enable_irq           = sun3x_enable_irq;
+    disable_irq          = sun3x_disable_irq;
+    mach_request_irq     = sys_request_irq;
+    mach_free_irq        = sys_free_irq;
+    mach_default_handler = &sun3x_default_handler;
+    mach_gettimeoffset   = sun3x_gettimeoffset;
+    mach_reset           = sun3x_reboot;
+
+    mach_gettod          = sun3x_gettod;
+    
+    switch (*(unsigned char *)SUN3X_EEPROM_CONS) {
+	case 0x10:
+	    serial_console = 1;
+	    conswitchp = NULL;
+	    break;
+	case 0x11:
+	    serial_console = 2;
+	    conswitchp = NULL;
+	    break;
+	default:
+	    serial_console = 0;
+	    conswitchp = &dummy_con;
+	    break;
+    }
+
+}
diff -urN linux-2.2.8-pre7/arch/m68k/sun3x/dvma.c linux/arch/m68k/sun3x/dvma.c
--- linux-2.2.8-pre7/arch/m68k/sun3x/dvma.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/sun3x/dvma.c	Mon Dec  3 18:46:54 2001
@@ -0,0 +1,162 @@
+/*
+ * Virtual DMA allocation
+ *
+ * (C) 1999 Thomas Bogendoerfer (tsbogend@alpha.franken.de) 
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/mm.h>
+
+#include <asm/sun3x.h>
+#include <asm/dvma.h>
+#include <asm/io.h>
+#include <asm/page.h>
+
+/* IOMMU support */
+
+#define IOMMU_ENTRIES		   2048
+#define IOMMU_ADDR_MASK            0x03ffe000
+#define IOMMU_CACHE_INHIBIT        0x00000040
+#define IOMMU_FULL_BLOCK           0x00000020
+#define IOMMU_MODIFIED             0x00000010
+#define IOMMU_USED                 0x00000008
+#define IOMMU_WRITE_PROTECT        0x00000004
+#define IOMMU_DT_MASK              0x00000003
+#define IOMMU_DT_INVALID           0x00000000
+#define IOMMU_DT_VALID             0x00000001
+#define IOMMU_DT_BAD               0x00000002
+
+#define DVMA_PAGE_SHIFT	13
+#define DVMA_PAGE_SIZE	(1UL << DVMA_PAGE_SHIFT)
+#define DVMA_PAGE_MASK	(~(DVMA_PAGE_SIZE-1))
+
+
+static volatile unsigned long *iommu_pte = (unsigned long *)SUN3X_IOMMU;
+static unsigned long iommu_use[IOMMU_ENTRIES];
+static unsigned long iommu_bitmap[IOMMU_ENTRIES/32];
+
+
+#define dvma_entry_paddr(index) 	(iommu_pte[index] & IOMMU_ADDR_MASK)
+#define dvma_entry_vaddr(index,paddr) 	((index << DVMA_PAGE_SHIFT) |  \
+					 (paddr & (DVMA_PAGE_SIZE-1)))
+#define dvma_entry_set(index,addr)	(iommu_pte[index] =            \
+					    (addr & IOMMU_ADDR_MASK) | \
+				             IOMMU_DT_VALID)
+#define dvma_entry_clr(index)		(iommu_pte[index] = IOMMU_DT_INVALID)
+#define dvma_entry_use(index)		(iommu_use[index])
+#define dvma_entry_inc(index)		(iommu_use[index]++)
+#define dvma_entry_dec(index)		(iommu_use[index]--)
+#define dvma_entry_hash(addr)		((addr >> DVMA_PAGE_SHIFT) ^ \
+					 ((addr & 0x03c00000) >>     \
+						(DVMA_PAGE_SHIFT+4)))
+#define dvma_map			iommu_bitmap
+#define dvma_map_size			(IOMMU_ENTRIES/2)
+#define dvma_slow_offset		(IOMMU_ENTRIES/2)
+#define dvma_is_slow(addr)		((addr) & 		      \
+					 (dvma_slow_offset << DVMA_PAGE_SHIFT))
+
+static int fixed_dvma;
+
+void __init dvma_init(void)
+{
+    unsigned long tmp;
+
+    if ((unsigned long)high_memory < (IOMMU_ENTRIES << DVMA_PAGE_SHIFT)) {
+	printk ("Sun3x fixed DVMA mapping\n");
+	fixed_dvma = 1;
+	for (tmp = 0; tmp < (unsigned long)high_memory; tmp += DVMA_PAGE_SIZE)
+	dvma_entry_set (tmp >> DVMA_PAGE_SHIFT, virt_to_phys((void *)tmp));
+	fixed_dvma = 1;
+    } else {
+	printk ("Sun3x variable DVMA mapping\n");
+	for (tmp = 0; tmp < IOMMU_ENTRIES; tmp++)
+	    dvma_entry_clr (tmp);
+	fixed_dvma = 0;
+    }
+}
+
+unsigned long dvma_slow_alloc (unsigned long paddr, int npages)
+{
+    int scan, base;
+    
+    scan = 0;
+    for (;;) {
+	scan = find_next_zero_bit(dvma_map, dvma_map_size, scan);
+	if ((base = scan) + npages > dvma_map_size) {
+	    printk ("dvma_slow_alloc failed for %d pages\n",npages);
+	    return 0;
+	}
+	for  (;;) {
+	    if (scan >= base + npages) goto found;
+	    if (test_bit(scan, dvma_map)) break;
+	    scan++;
+	}
+    }
+
+found:
+    for (scan = base; scan < base+npages; scan++) {
+	dvma_entry_set(scan+dvma_slow_offset, paddr);
+	paddr += DVMA_PAGE_SIZE;
+	set_bit(scan, dvma_map);
+    }
+    return (dvma_entry_vaddr((base+dvma_slow_offset),paddr));
+}
+
+unsigned long dvma_alloc (unsigned long paddr, unsigned long size)
+{
+    int index;
+    int pages = ((paddr & ~DVMA_PAGE_MASK) + size + (DVMA_PAGE_SIZE-1)) >>
+		DVMA_PAGE_SHIFT;
+
+    if (fixed_dvma)
+	return ((unsigned long)phys_to_virt (paddr));
+
+    if (pages > 1) /* multi page, allocate from slow pool */
+	return dvma_slow_alloc (paddr, pages);
+    
+    index = dvma_entry_hash (paddr);
+
+    if (dvma_entry_use(index)) {
+	if (dvma_entry_paddr(index) == (paddr & DVMA_PAGE_MASK)) {
+	    dvma_entry_inc(index);
+	    return dvma_entry_vaddr(index,paddr);
+	}
+	/* collision, allocate from slow pool */
+	return dvma_slow_alloc (paddr, pages);
+    }
+    
+    dvma_entry_set(index,paddr); 
+    dvma_entry_inc(index);
+    return dvma_entry_vaddr(index,paddr);
+}
+
+void dvma_free (unsigned long dvma_addr, unsigned long size)
+{
+    int npages;
+    int index;
+    
+    if (fixed_dvma)
+	return;
+
+    if (!dvma_is_slow(dvma_addr)) {
+	index = (dvma_addr >> DVMA_PAGE_SHIFT);
+	if (dvma_entry_use(index) == 0) {
+	    printk ("dvma_free: %lx entry already free\n",dvma_addr);
+	    return;
+	}
+        dvma_entry_dec(index);
+	if (dvma_entry_use(index) == 0)
+	    dvma_entry_clr(index);
+	return;
+    }
+
+    /* free in slow pool */
+    npages = ((dvma_addr & ~DVMA_PAGE_MASK) + size + (DVMA_PAGE_SIZE-1)) >>
+	    DVMA_PAGE_SHIFT;
+    for (index = (dvma_addr >> DVMA_PAGE_SHIFT); npages--; index++) {
+	dvma_entry_clr(index);
+	clear_bit (index,dvma_map);
+    }
+}
diff -urN linux-2.2.8-pre7/arch/m68k/sun3x/sbus.c linux/arch/m68k/sun3x/sbus.c
--- linux-2.2.8-pre7/arch/m68k/sun3x/sbus.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/sun3x/sbus.c	Mon Dec  3 18:46:54 2001
@@ -0,0 +1,44 @@
+/*
+ * SBus helper functions
+ *
+ * Sun3x don't have a sbus, but many of the used devices are also
+ * used on Sparc machines with sbus. To avoid having a lot of
+ * duplicate code, we provide necessary glue stuff to make using
+ * of the sbus driver code possible.
+ *
+ * (C) 1999 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+
+__initfunc(void sbus_init(void))
+{
+
+}
+
+void *sparc_alloc_io (u32 address, void *virtual, int len, char *name,
+                      u32 bus_type, int rdonly)
+{
+	return (void *)address;
+}
+
+int prom_getintdefault(int node, char *property, int deflt)
+{
+	return deflt;
+}
+
+int prom_getbool (int node, char *prop)
+{
+	return 1;
+}
+
+void prom_printf(char *fmt, ...)
+{
+
+}
+
+void prom_halt (void)
+{
+
+}
diff -urN linux-2.2.8-pre7/arch/m68k/sun3x/time.c linux/arch/m68k/sun3x/time.c
--- linux-2.2.8-pre7/arch/m68k/sun3x/time.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/sun3x/time.c	Mon Dec  3 18:46:54 2001
@@ -0,0 +1,83 @@
+/*
+ *  linux/arch/m68k/sun3x/time.c
+ *
+ *  Sun3x-specific time handling
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/kernel_stat.h>
+#include <linux/interrupt.h>
+
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/traps.h>
+#include <asm/sun3x.h>
+
+#include "time.h"
+
+#define M_CONTROL 0xf8
+#define M_SEC     0xf9
+#define M_MIN     0xfa
+#define M_HOUR    0xfb
+#define M_DAY     0xfc
+#define M_DATE    0xfd
+#define M_MONTH   0xfe
+#define M_YEAR    0xff
+
+#define C_WRITE   0x80
+#define C_READ    0x40
+#define C_SIGN    0x20
+#define C_CALIB   0x1f
+
+#define BCD_TO_BIN(val) (((val)&15) + ((val)>>4)*10)
+
+/* Read the Mostek */
+void sun3x_gettod (int *yearp, int *monp, int *dayp,
+                   int *hourp, int *minp, int *secp)
+{
+    volatile unsigned char *eeprom = (unsigned char *)SUN3X_EEPROM;
+
+    /* Stop updates */
+    *(eeprom + M_CONTROL) |= C_READ;
+
+    /* Read values */
+    *yearp = BCD_TO_BIN(*(eeprom + M_YEAR));
+    *monp  = BCD_TO_BIN(*(eeprom + M_MONTH));
+    *dayp  = BCD_TO_BIN(*(eeprom + M_DATE));
+    *hourp = BCD_TO_BIN(*(eeprom + M_HOUR));
+    *minp  = BCD_TO_BIN(*(eeprom + M_MIN));
+    *secp  = BCD_TO_BIN(*(eeprom + M_SEC));
+
+    /* Restart updates */
+    *(eeprom + M_CONTROL) &= ~C_READ;
+}
+
+/* Not much we can do here */
+unsigned long sun3x_gettimeoffset (void)
+{
+    return 0L;
+}
+
+static void sun3x_timer_tick(int irq, void *dev_id, struct pt_regs *regs)
+{
+    void (*vector)(int, void *, struct pt_regs *) = dev_id;
+
+    /* Clear the pending interrupt - pulse the enable line low */
+    disable_irq(5);
+    enable_irq(5);
+    
+    vector(irq, NULL, regs);
+}
+
+__initfunc(void sun3x_sched_init(void (*vector)(int, void *, struct pt_regs *)))
+{
+    sys_request_irq(5, sun3x_timer_tick, IRQ_FLG_STD, "timer tick", vector);
+
+    /* Pulse enable low to get the clock started */
+    disable_irq(5);
+    enable_irq(5);
+}
diff -urN linux-2.2.8-pre7/arch/m68k/sun3x/time.h linux/arch/m68k/sun3x/time.h
--- linux-2.2.8-pre7/arch/m68k/sun3x/time.h	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/sun3x/time.h	Mon Dec  3 18:46:54 2001
@@ -0,0 +1,9 @@
+#ifndef SUN3X_TIME_H
+#define SUN3X_TIME_H
+
+void sun3x_gettod (int *yearp, int *monp, int *dayp,
+                   int *hourp, int *minp, int *secp);
+unsigned long sun3x_gettimeoffset (void);
+void sun3x_sched_init(void (*vector)(int, void *, struct pt_regs *));
+
+#endif
diff -urN linux-2.2.8-pre7/arch/ppc/boot/misc.c linux/arch/ppc/boot/misc.c
--- linux-2.2.8-pre7/arch/ppc/boot/misc.c	Mon Dec  3 18:46:19 2001
+++ linux/arch/ppc/boot/misc.c	Mon Dec  3 18:46:54 2001
@@ -1,7 +1,7 @@
 /*
  * misc.c
  *
- * $Id: misc.c,v 1.63 1999/04/05 21:48:20 cort Exp $
+ * $Id: misc.c,v 1.64 1999/04/30 05:52:46 cort Exp $
  * 
  * Adapted for PowerPC by Gary Thomas
  *
@@ -362,8 +362,9 @@
 			 */
 			if (board_type == 0xe0) {	
 				base_mod = inb(0x803);
-				/* if a MVME2300 or a MCME2400 then no keyboard */
-				if((base_mod == 0x9) || (base_mod == 0xF9)) {
+				/* if a MVME2300/2400 or a Sitka then no keyboard */
+				if((base_mod == 0x9) || (base_mod == 0xF9) ||
+				   (base_mod == 0xE1)) {
 					keyb_present = 0;	/* no keyboard */
 				}
 			}
@@ -471,6 +472,7 @@
 	{
 		puts("initrd at:     "); puthex(initrd_start);
 		puts(" "); puthex(initrd_end); puts("\n");
+#ifdef OMIT
 		avail_ram = (char *)PAGE_ALIGN(
 			(unsigned long)zimage_size+(unsigned long)zimage_start);
 		memcpy ((void *)avail_ram, (void *)initrd_start, INITRD_SIZE );
@@ -478,6 +480,7 @@
 		initrd_end = initrd_start + INITRD_SIZE;
 		puts("relocated to:  "); puthex(initrd_start);
 		puts(" "); puthex(initrd_end); puts("\n");
+#endif
 	}
 
 	avail_ram = (char *)0x00400000;
diff -urN linux-2.2.8-pre7/arch/ppc/common_defconfig linux/arch/ppc/common_defconfig
--- linux-2.2.8-pre7/arch/ppc/common_defconfig	Mon Dec  3 18:46:19 2001
+++ linux/arch/ppc/common_defconfig	Mon Dec  3 18:46:54 2001
@@ -14,7 +14,7 @@
 CONFIG_ALL_PPC=y
 # CONFIG_APUS is not set
 # CONFIG_MBX is not set
-CONFIG_SMP=y
+# CONFIG_SMP is not set
 
 #
 # General setup
@@ -42,6 +42,7 @@
 CONFIG_MAC_KEYBOARD=y
 CONFIG_MAC_FLOPPY=y
 CONFIG_MAC_SERIAL=y
+# CONFIG_SERIAL_CONSOLE is not set
 CONFIG_ADBMOUSE=y
 CONFIG_PROC_DEVICETREE=y
 # CONFIG_TOTALMP is not set
@@ -336,7 +337,7 @@
 #
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
-# CONFIG_SERIAL is not set
+CONFIG_SERIAL=m
 # CONFIG_SERIAL_EXTENDED is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
 CONFIG_UNIX98_PTYS=y
@@ -474,6 +475,6 @@
 #
 # Kernel hacking
 #
-# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_MAGIC_SYSRQ=y
 # CONFIG_KGDB is not set
 # CONFIG_XMON is not set
diff -urN linux-2.2.8-pre7/arch/ppc/config.in linux/arch/ppc/config.in
--- linux-2.2.8-pre7/arch/ppc/config.in	Mon Dec  3 18:46:19 2001
+++ linux/arch/ppc/config.in	Mon Dec  3 18:46:54 2001
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.91 1999/04/09 07:07:47 cort Exp $
+# $Id: config.in,v 1.92 1999/04/30 05:41:43 cort Exp $
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
@@ -89,9 +89,9 @@
 bool 'Support for early boot text console (BootX only)' CONFIG_BOOTX_TEXT
 bool 'Support for Motorola Hot Swap' CONFIG_MOTOROLA_HOTSWAP
 if [ "$CONFIG_PREP" = "y" -o "$CONFIG_ALL_PPC" = "y" ]; then
-  bool 'PReP bootloader ernel arguments' CONFIG_CMDLINE_BOOL n
+  bool 'PReP bootloader kernel arguments' CONFIG_CMDLINE_BOOL y
   if [ "$CONFIG_CMDLINE_BOOL" = "y" ] ; then
-    string 'Initial kernel command string' CONFIG_CMDLINE ""
+    string 'Initial kernel command string' CONFIG_CMDLINE console=ttyS0,9600 console=tty0 root=/dev/sda2
   fi
 fi
 
diff -urN linux-2.2.8-pre7/arch/ppc/defconfig linux/arch/ppc/defconfig
--- linux-2.2.8-pre7/arch/ppc/defconfig	Wed Mar 10 21:30:31 1999
+++ linux/arch/ppc/defconfig	Mon Dec  3 18:46:54 2001
@@ -8,13 +8,12 @@
 CONFIG_PPC=y
 CONFIG_6xx=y
 # CONFIG_8xx is not set
-CONFIG_PMAC=y
+# CONFIG_PMAC is not set
 # CONFIG_PREP is not set
 # CONFIG_CHRP is not set
-# CONFIG_ALL_PPC is not set
+CONFIG_ALL_PPC=y
 # CONFIG_APUS is not set
 # CONFIG_MBX is not set
-CONFIG_MACH_SPECIFIC=y
 # CONFIG_SMP is not set
 
 #
@@ -36,20 +35,20 @@
 CONFIG_BINFMT_MISC=m
 # CONFIG_BINFMT_JAVA is not set
 # CONFIG_PARPORT is not set
-# CONFIG_VGA_CONSOLE is not set
+CONFIG_VGA_CONSOLE=y
 CONFIG_FB=y
 CONFIG_FB_COMPAT_XPMAC=y
 CONFIG_PMAC_PBOOK=y
 CONFIG_MAC_KEYBOARD=y
 CONFIG_MAC_FLOPPY=y
 CONFIG_MAC_SERIAL=y
+# CONFIG_SERIAL_CONSOLE is not set
 CONFIG_ADBMOUSE=y
-CONFIG_BLK_DEV_IDE_PMAC=y
 CONFIG_PROC_DEVICETREE=y
-# CONFIG_KGDB is not set
-# CONFIG_XMON is not set
 # CONFIG_TOTALMP is not set
 CONFIG_BOOTX_TEXT=y
+# CONFIG_MOTOROLA_HOTSWAP is not set
+# CONFIG_CMDLINE_BOOL is not set
 
 #
 # Plug and Play support
@@ -76,15 +75,13 @@
 # CONFIG_BLK_DEV_IDEPCI is not set
 # CONFIG_BLK_DEV_SL82C105 is not set
 CONFIG_BLK_DEV_IDE_PMAC=y
-CONFIG_BLK_DEV_IDEDMA_PMAC=y
-CONFIG_BLK_DEV_IDEDMA=y
-CONFIG_PMAC_IDEDMA_AUTO=y
+# CONFIG_BLK_DEV_IDEDMA_PMAC is not set
 # CONFIG_IDE_CHIPSETS is not set
 
 #
 # Additional Block Devices
 #
-# CONFIG_BLK_DEV_LOOP is not set
+CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_MD is not set
 CONFIG_BLK_DEV_RAM=y
@@ -119,7 +116,6 @@
 # (it is safe to leave these untouched)
 #
 CONFIG_INET_RARP=y
-CONFIG_IP_NOSR=y
 CONFIG_SKB_LARGE=y
 # CONFIG_IPV6 is not set
 
@@ -155,12 +151,12 @@
 CONFIG_CHR_DEV_ST=y
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
-# CONFIG_CHR_DEV_SG is not set
+CONFIG_CHR_DEV_SG=y
 
 #
 # Some SCSI devices (e.g. CD jukebox) support multiple LUNs
 #
-# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_MULTI_LUN=y
 CONFIG_SCSI_CONSTANTS=y
 # CONFIG_SCSI_LOGGING is not set
 
@@ -188,16 +184,28 @@
 # CONFIG_SCSI_FUTURE_DOMAIN is not set
 # CONFIG_SCSI_GDTH is not set
 # CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_G_NCR5380_PORT is not set
+# CONFIG_SCSI_G_NCR5380_MEM is not set
 # CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
 # CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_SYM53C416 is not set
 # CONFIG_SCSI_NCR53C7xx is not set
-# CONFIG_SCSI_NCR53C8XX is not set
+CONFIG_SCSI_NCR53C8XX=y
+# CONFIG_SCSI_SYM53C8XX is not set
+CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
+CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
+CONFIG_SCSI_NCR53C8XX_SYNC=20
+# CONFIG_SCSI_NCR53C8XX_PROFILE is not set
+# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set
+# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set
 # CONFIG_SCSI_PAS16 is not set
 # CONFIG_SCSI_PCI2000 is not set
 # CONFIG_SCSI_PCI2220I is not set
 # CONFIG_SCSI_PSI240I is not set
 # CONFIG_SCSI_QLOGIC_FAS is not set
 # CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_SEAGATE is not set
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_T128 is not set
@@ -228,7 +236,7 @@
 # CONFIG_ACENIC is not set
 # CONFIG_NET_ISA is not set
 CONFIG_NET_EISA=y
-# CONFIG_PCNET32 is not set
+CONFIG_PCNET32=y
 # CONFIG_AC3200 is not set
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
@@ -275,7 +283,7 @@
 # CONFIG_ISDN is not set
 
 #
-# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
+# Old CD-ROM drivers (not SCSI, not IDE)
 #
 # CONFIG_CD_NO_IDESCSI is not set
 
@@ -283,22 +291,37 @@
 # Console drivers
 #
 CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FB_PM2 is not set
 CONFIG_FB_OF=y
 CONFIG_FB_CONTROL=y
 CONFIG_FB_PLATINUM=y
 CONFIG_FB_VALKYRIE=y
-CONFIG_FB_ATY=y
+# CONFIG_FB_ATY is not set
 CONFIG_FB_IMSTT=y
 CONFIG_FB_CT65550=y
 # CONFIG_FB_S3TRIO is not set
-# CONFIG_FB_MATROX is not set
-CONFIG_FB_ATY=y
+CONFIG_FB_MATROX=y
+CONFIG_FB_MATROX_MILLENIUM=y
+CONFIG_FB_MATROX_MYSTIQUE=y
+CONFIG_FB_MATROX_G100=y
+# CONFIG_FB_MATROX_MULTIHEAD is not set
+# CONFIG_FB_ATY is not set
 # CONFIG_FB_VIRTUAL is not set
-# CONFIG_FBCON_ADVANCED is not set
+CONFIG_FBCON_ADVANCED=y
+# CONFIG_FBCON_MFB is not set
+# CONFIG_FBCON_CFB2 is not set
+# CONFIG_FBCON_CFB4 is not set
 CONFIG_FBCON_CFB8=y
 CONFIG_FBCON_CFB16=y
 CONFIG_FBCON_CFB24=y
 CONFIG_FBCON_CFB32=y
+# CONFIG_FBCON_AFB is not set
+# CONFIG_FBCON_ILBM is not set
+# CONFIG_FBCON_IPLAN2P2 is not set
+# CONFIG_FBCON_IPLAN2P4 is not set
+# CONFIG_FBCON_IPLAN2P8 is not set
+# CONFIG_FBCON_MAC is not set
+# CONFIG_FBCON_VGA is not set
 # CONFIG_FBCON_FONTWIDTH8_ONLY is not set
 CONFIG_FBCON_FONTS=y
 # CONFIG_FONT_8x8 is not set
@@ -314,15 +337,25 @@
 #
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
-# CONFIG_SERIAL is not set
+CONFIG_SERIAL=m
 # CONFIG_SERIAL_EXTENDED is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_UNIX98_PTY_COUNT=256
-# CONFIG_MOUSE is not set
+CONFIG_MOUSE=y
+
+#
+# Mice
+#
+# CONFIG_ATIXL_BUSMOUSE is not set
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MS_BUSMOUSE is not set
+CONFIG_PSMOUSE=y
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
 # CONFIG_QIC02_TAPE is not set
 # CONFIG_WATCHDOG is not set
-CONFIG_NVRAM=y
+# CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 
 #
@@ -334,11 +367,20 @@
 # Joystick support
 #
 # CONFIG_JOYSTICK is not set
+# CONFIG_DTLK is not set
 
 #
 # Ftape, the floppy tape device driver
 #
 # CONFIG_FTAPE is not set
+# CONFIG_FT_NORMAL_DEBUG is not set
+# CONFIG_FT_FULL_DEBUG is not set
+# CONFIG_FT_NO_TRACE is not set
+# CONFIG_FT_NO_TRACE_AT_ALL is not set
+# CONFIG_FT_STD_FDC is not set
+# CONFIG_FT_MACH2 is not set
+# CONFIG_FT_PROBE_FC10 is not set
+# CONFIG_FT_ALT_FDC is not set
 
 #
 # Filesystems
@@ -429,3 +471,10 @@
 # CONFIG_SOUND_MSNDCLAS is not set
 # CONFIG_SOUND_MSNDPIN is not set
 # CONFIG_SOUND_OSS is not set
+
+#
+# Kernel hacking
+#
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_KGDB is not set
+# CONFIG_XMON is not set
diff -urN linux-2.2.8-pre7/arch/ppc/kernel/chrp_pci.c linux/arch/ppc/kernel/chrp_pci.c
--- linux-2.2.8-pre7/arch/ppc/kernel/chrp_pci.c	Mon Dec  3 18:46:19 2001
+++ linux/arch/ppc/kernel/chrp_pci.c	Mon Dec  3 18:46:54 2001
@@ -96,11 +96,12 @@
 #define python_config_data(bus) ((0xfef00000+0xf8010)-(bus*0x100000))
 #define PYTHON_CFA(b, d, o)	(0x80 | ((b<<6) << 8) | ((d) << 16) \
 				 | (((o) & ~3) << 24))
-     
+unsigned int python_busnr = 1;
+
 int python_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
 				    unsigned char offset, unsigned char *val)
 {
-	if (bus > 2) {
+	if (bus > python_busnr) {
 		*val = 0xff;
 		return PCIBIOS_DEVICE_NOT_FOUND;
 	}
@@ -112,7 +113,7 @@
 int python_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
 				    unsigned char offset, unsigned short *val)
 {
-	if (bus > 2) {
+	if (bus > python_busnr) {
 		*val = 0xffff;
 		return PCIBIOS_DEVICE_NOT_FOUND;
 	}
@@ -125,7 +126,7 @@
 int python_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
 				     unsigned char offset, unsigned int *val)
 {
-	if (bus > 2) {
+	if (bus > python_busnr) {
 		*val = 0xffffffff;
 		return PCIBIOS_DEVICE_NOT_FOUND;
 	}
@@ -137,7 +138,7 @@
 int python_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
 				     unsigned char offset, unsigned char val)
 {
-	if (bus > 2)
+	if (bus > python_busnr)
 		return PCIBIOS_DEVICE_NOT_FOUND;
 	out_be32( python_config_address( bus ), PYTHON_CFA(bus,dev_fn,offset));
 	out_8((volatile unsigned char *)python_config_data(bus) + (offset&3), val);
@@ -147,7 +148,7 @@
 int python_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
 				     unsigned char offset, unsigned short val)
 {
-	if (bus > 2)
+	if (bus > python_busnr)
 		return PCIBIOS_DEVICE_NOT_FOUND;
 	out_be32( python_config_address( bus ), PYTHON_CFA(bus,dev_fn,offset));
 	out_le16((volatile unsigned short *)python_config_data(bus) + (offset&3),
@@ -158,7 +159,7 @@
 int python_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
 				      unsigned char offset, unsigned int val)
 {
-	if (bus > 2)
+	if (bus > python_busnr)
 		return PCIBIOS_DEVICE_NOT_FOUND;
 	out_be32( python_config_address( bus ), PYTHON_CFA(bus,dev_fn,offset));
 	out_le32((unsigned *)python_config_data(bus) + (offset&3), val);
@@ -217,9 +218,9 @@
 {
 	struct pci_dev *dev;
 	
-	/* get the other 2 busses on the F50 */
-	if ( !strncmp("F5", get_property(find_path_device("/"),
-					 "ibm,model-class", NULL),2) )
+	/* some of IBM chrps have > 1 bus */
+	if ( !strncmp("IBM", get_property(find_path_device("/"),
+					 "name", NULL),3) )
 	{
 		pci_scan_peer_bridge(1);
 		pci_scan_peer_bridge(2);
@@ -258,6 +259,8 @@
 void __init
 chrp_setup_pci_ptrs(void)
 {
+	struct device_node *py;
+	
         if ( !strncmp("MOT",
                       get_property(find_path_device("/"), "model", NULL),3) )
         {
@@ -268,16 +271,28 @@
         }
         else
         {
-		if ( find_compatible_devices( "pci", "IBM,python" ) )
+		if ( (py = find_compatible_devices( "pci", "IBM,python" )) )
 		{
+			/* find out how many pythons */
+			while ( (py = py->next) ) python_busnr++;
+                        set_config_access_method(python);
 			/*
-			 * We assume these values but should someday get them
-			 * from the device tree or python itself instead -- Cort
+			 * We base these values on the machine type but should
+			 * try to read them from the python controller itself.
+			 * -- Cort
 			 */
-			pci_dram_offset = 0x80000000;
-			isa_mem_base = 0xa0000000;
-			isa_io_base = 0x88000000;
-                        set_config_access_method(python);
+			if ( !strncmp("IBM,7025-F50", get_property(find_path_device("/"), "name", NULL),12) )
+			{
+				pci_dram_offset = 0x80000000;
+				isa_mem_base = 0xa0000000;
+				isa_io_base = 0x88000000;
+			} else if ( !strncmp("IBM,7043-260",
+			   get_property(find_path_device("/"), "name", NULL),12) )
+			{
+				pci_dram_offset = 0x80000000;
+				isa_mem_base = 0xc0000000;
+				isa_io_base = 0xf8000000;
+			}
                 }
                 else
                 {
diff -urN linux-2.2.8-pre7/arch/ppc/kernel/chrp_setup.c linux/arch/ppc/kernel/chrp_setup.c
--- linux-2.2.8-pre7/arch/ppc/kernel/chrp_setup.c	Mon Dec  3 18:46:19 2001
+++ linux/arch/ppc/kernel/chrp_setup.c	Mon Dec  3 18:46:54 2001
@@ -400,7 +400,10 @@
                  *
                  * This should go in the above mask/ack code soon. -- Cort
                  */
-                irq = *chrp_int_ack_special;
+		if ( chrp_int_ack_special )
+			irq = *chrp_int_ack_special;
+		else
+			irq = i8259_irq(0);
                 /*
                  * Acknowledge as soon as possible to allow i8259
                  * interrupt nesting                         */
diff -urN linux-2.2.8-pre7/arch/ppc/kernel/head.S linux/arch/ppc/kernel/head.S
--- linux-2.2.8-pre7/arch/ppc/kernel/head.S	Mon Dec  3 18:46:19 2001
+++ linux/arch/ppc/kernel/head.S	Mon Dec  3 18:46:54 2001
@@ -1,7 +1,7 @@
 /*
  *  arch/ppc/kernel/head.S
  *
- *  $Id: head.S,v 1.127 1999/04/07 07:26:55 paulus Exp $
+ *  $Id: head.S,v 1.130 1999/05/09 19:16:43 cort Exp $
  *
  *  PowerPC version 
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
@@ -2045,8 +2045,9 @@
 	stw	r0,GPR0(r1)
 	lwz	r0,0(r1)
 	stw	r0,GPR1(r1)
-	SAVE_10GPRS(2, r1)
-	SAVE_10GPRS(12, r1)
+	/* r3-r13 are caller saved -- Cort */
+	SAVE_GPR(2, r1)
+	SAVE_8GPRS(14, r1)
 	SAVE_10GPRS(22, r1)
 	mflr	r20		/* Return to switch caller */
 	mfmsr	r22
@@ -2069,6 +2070,8 @@
 	mtspr	SPRG3,r0	/* Update current TSS phys addr */
 	SYNC
 	lwz	r1,KSP(r4)	/* Load new stack pointer */
+	/* save the old current 'last' for return value */
+	mr	r3,r2
 	addi	r2,r4,-TSS	/* Update current */
 #ifndef CONFIG_8xx
 	/* Set up segment registers for new task */
@@ -2076,39 +2079,62 @@
 	addis	r5,r5,0x6000	/* Set Ks, Ku bits */
 	li	r0,12		/* TASK_SIZE / SEGMENT_SIZE */
 	mtctr	r0
-	li	r3,0
-3:	mtsrin	r5,r3
+	li	r9,0
+3:	mtsrin	r5,r9
 	addi	r5,r5,1		/* next VSID */
-	addis	r3,r3,0x1000	/* address of next segment */
+	addis	r9,r9,0x1000	/* address of next segment */
 	bdnz	3b
 #else
 /* On the MPC8xx, we place the physical address of the new task
  * page directory loaded into the MMU base register, and set the
  * ASID compare register with the new "context".
  */
-        lwz     r3,MM-TSS(r4)           /* Get virtual address of mm */
-        lwz     r3,PGD(r3)              /* get new->mm->pgd */
-        addis   r3,r3,-KERNELBASE@h     /* convert to phys addr */
-        mtspr   M_TWB, r3               /* Update MMU base address */
+        lwz     r9,MM-TSS(r4)           /* Get virtual address of mm */
+        lwz     r9,PGD(r9)              /* get new->mm->pgd */
+        addis   r9,r9,-KERNELBASE@h     /* convert to phys addr */
+        mtspr   M_TWB, r9               /* Update MMU base address */
         mtspr   M_CASID, r5             /* Update context */
         tlbia
 #endif
 	SYNC
-
-/* FALL THROUGH into int_return */
-#ifdef __SMP__
-	/* call schedule_tail if this is the first time for a child process */
-	lwz	r5,TSS_SMP_FORK_RET(r4)
-	cmpi	0,r5,0
-	beq+	int_return
-	li	r3,0
-	stw	r3,TSS_SMP_FORK_RET(r4)
-	bl	schedule_tail
-#endif /* __SMP__ */
+2:	lwz	r9,_MSR(r1)	/* Returning to user mode? */
+	andi.	r9,r9,MSR_PR
+	beq+	10f		/* if not, don't adjust kernel stack */
+8:	addi	r4,r1,INT_FRAME_SIZE+STACK_UNDERHEAD	/* size of frame */
+	stw	r4,TSS+KSP(r2)	/* save kernel stack pointer */
+	tophys(r9,r1,r9)
+	mtspr	SPRG2,r9	/* phys exception stack pointer */
+10:	lwz	r2,_CTR(r1)
+	lwz	r0,_LINK(r1)
+	mtctr	r2
+	mtlr	r0
+	lwz	r2,_XER(r1)
+	lwz	r0,_CCR(r1)
+	mtspr	XER,r2
+	mtcrf	0xFF,r0
+	/* r3-r13 are destroyed -- Cort */
+	REST_GPR(14, r1)
+	REST_8GPRS(15, r1)
+	REST_8GPRS(23, r1)
+	REST_GPR(31, r1)
+	lwz	r2,_NIP(r1)	/* Restore environment */
+	lwz	r0,_MSR(r1)
+	mtspr	SRR0,r2
+	mtspr	SRR1,r0
+	lwz	r0,GPR0(r1)
+	lwz	r2,GPR2(r1)
+	lwz	r1,GPR1(r1)
+	SYNC
+	rfi
 
 /*
  * Trap exit.
  */
+#ifdef __SMP__	
+	.globl	ret_from_smpfork
+ret_from_smpfork:
+	bl	schedule_tail
+#endif	
 	.globl	ret_from_syscall
 ret_from_syscall:	
 	.globl	int_return
diff -urN linux-2.2.8-pre7/arch/ppc/kernel/i8259.c linux/arch/ppc/kernel/i8259.c
--- linux-2.2.8-pre7/arch/ppc/kernel/i8259.c	Mon Dec  3 18:46:19 2001
+++ linux/arch/ppc/kernel/i8259.c	Mon Dec  3 18:46:54 2001
@@ -10,6 +10,40 @@
 #define cached_A1 (cached_8259[0])
 #define cached_21 (cached_8259[1])
 
+int i8259_irq(int cpu)
+{
+	int irq;
+	
+        /*
+         * Perform an interrupt acknowledge cycle on controller 1
+         */                                                             
+        outb(0x0C, 0x20);
+        irq = inb(0x20) & 7;                                   
+        if (irq == 2)                                                     
+        {                                                                   
+                /*                                     
+                 * Interrupt is cascaded so perform interrupt
+                 * acknowledge on controller 2
+                 */
+                outb(0x0C, 0xA0);                      
+                irq = (inb(0xA0) & 7) + 8;
+        }
+        else if (irq==7)                                
+        {
+                /*                               
+                 * This may be a spurious interrupt
+                 *                         
+                 * Read the interrupt status register. If the most
+                 * significant bit is not set then there is no valid
+		 * interrupt
+		 */
+		outb(0x0b, 0x20);
+		if(~inb(0x20)&0x80)
+			return -1;
+	}
+	return irq;
+}
+
 static void i8259_mask_and_ack_irq(unsigned int irq_nr)
 {
         if ( irq_nr >= i8259_pic.irq_offset )
diff -urN linux-2.2.8-pre7/arch/ppc/kernel/i8259.h linux/arch/ppc/kernel/i8259.h
--- linux-2.2.8-pre7/arch/ppc/kernel/i8259.h	Mon Dec  3 18:46:19 2001
+++ linux/arch/ppc/kernel/i8259.h	Mon Dec  3 18:46:54 2001
@@ -7,5 +7,6 @@
 extern struct hw_interrupt_type i8259_pic;
 
 void i8259_init(void);
+int i8259_irq(int);
 
 #endif /* _PPC_KERNEL_i8259_H */
diff -urN linux-2.2.8-pre7/arch/ppc/kernel/indirect_pci.c linux/arch/ppc/kernel/indirect_pci.c
--- linux-2.2.8-pre7/arch/ppc/kernel/indirect_pci.c	Mon Dec  3 18:46:19 2001
+++ linux/arch/ppc/kernel/indirect_pci.c	Mon Dec  3 18:46:54 2001
@@ -103,7 +103,7 @@
 }
 
 int indirect_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
-			     unsigned char offset, unsigned short val)
+			     unsigned char offset, unsigned int val)
 {
 	unsigned flags;
 
diff -urN linux-2.2.8-pre7/arch/ppc/kernel/mk_defs.c linux/arch/ppc/kernel/mk_defs.c
--- linux-2.2.8-pre7/arch/ppc/kernel/mk_defs.c	Mon Dec  3 18:46:19 2001
+++ linux/arch/ppc/kernel/mk_defs.c	Mon Dec  3 18:46:54 2001
@@ -48,7 +48,6 @@
 	DEFINE(NEED_RESCHED, offsetof(struct task_struct, need_resched));
 	DEFINE(TSS_FPR0, offsetof(struct thread_struct, fpr[0]));
 	DEFINE(TSS_FPSCR, offsetof(struct thread_struct, fpscr));
-	DEFINE(TSS_SMP_FORK_RET, offsetof(struct thread_struct, smp_fork_ret));
 	/* Interrupt register frame */
 	DEFINE(TASK_UNION_SIZE, sizeof(union task_union));
 	DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD);
diff -urN linux-2.2.8-pre7/arch/ppc/kernel/open_pic.c linux/arch/ppc/kernel/open_pic.c
--- linux-2.2.8-pre7/arch/ppc/kernel/open_pic.c	Mon Dec  3 18:46:19 2001
+++ linux/arch/ppc/kernel/open_pic.c	Mon Dec  3 18:46:54 2001
@@ -14,13 +14,13 @@
 }
 #endif /* __SMP__ */
 
-void __openfirmware chrp_mask_and_ack_irq(unsigned int irq_nr)
+void chrp_mask_and_ack_irq(unsigned int irq_nr)
 {
 	if (is_8259_irq(irq_nr))
 	    i8259_pic.mask_and_ack(irq_nr);
 }
 
-static void __openfirmware chrp_mask_irq(unsigned int irq_nr)
+static void chrp_mask_irq(unsigned int irq_nr)
 {
 	if (is_8259_irq(irq_nr))
 		i8259_pic.disable(irq_nr);
@@ -28,7 +28,7 @@
 		openpic_disable_irq(irq_to_openpic(irq_nr));
 }
 
-static void __openfirmware chrp_unmask_irq(unsigned int irq_nr)
+static void chrp_unmask_irq(unsigned int irq_nr)
 {
 	if (is_8259_irq(irq_nr))
 		i8259_pic.enable(irq_nr);
diff -urN linux-2.2.8-pre7/arch/ppc/kernel/pmac_pic.c linux/arch/ppc/kernel/pmac_pic.c
--- linux-2.2.8-pre7/arch/ppc/kernel/pmac_pic.c	Mon Dec  3 18:46:19 2001
+++ linux/arch/ppc/kernel/pmac_pic.c	Mon Dec  3 18:46:54 2001
@@ -1,4 +1,4 @@
-#include <linux/config.h>
+
 #include <linux/stddef.h>
 #include <linux/init.h>
 #include <linux/sched.h>
diff -urN linux-2.2.8-pre7/arch/ppc/kernel/pmac_setup.c linux/arch/ppc/kernel/pmac_setup.c
--- linux-2.2.8-pre7/arch/ppc/kernel/pmac_setup.c	Mon Dec  3 18:46:19 2001
+++ linux/arch/ppc/kernel/pmac_setup.c	Mon Dec  3 18:46:54 2001
@@ -75,7 +75,9 @@
 extern char mackbd_unexpected_up(unsigned char keycode);
 extern void mackbd_leds(unsigned char leds);
 extern void mackbd_init_hw(void);
-extern unsigned char mackbd_sysrq_xlate[128];
+#ifdef CONFIG_MAGIC_SYSRQ
+unsigned char mackbd_sysrq_xlate[128];
+#endif /* CONFIG_MAGIC_SYSRQ */
 extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
 extern int pckbd_getkeycode(unsigned int scancode);
 extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
@@ -575,7 +577,7 @@
 	ppc_md.get_rtc_time   = pmac_get_rtc_time;
 	ppc_md.calibrate_decr = pmac_calibrate_decr;
 
-#ifdef CONFIG_VT
+#if defined(CONFIG_VT) && defined(CONFIG_MAC_KEYBOARD)
 	ppc_md.kbd_setkeycode    = mackbd_setkeycode;
 	ppc_md.kbd_getkeycode    = mackbd_getkeycode;
 	ppc_md.kbd_translate     = mackbd_translate;
@@ -584,7 +586,7 @@
 	ppc_md.kbd_init_hw       = mackbd_init_hw;
 #ifdef CONFIG_MAGIC_SYSRQ
 	ppc_md.kbd_sysrq_xlate	 = mackbd_sysrq_xlate;
-#endif	
+#endif
 #endif
 
 #if defined(CONFIG_BLK_DEV_IDE_PMAC)
diff -urN linux-2.2.8-pre7/arch/ppc/kernel/prep_pci.c linux/arch/ppc/kernel/prep_pci.c
--- linux-2.2.8-pre7/arch/ppc/kernel/prep_pci.c	Mon Dec  3 18:46:19 2001
+++ linux/arch/ppc/kernel/prep_pci.c	Mon Dec  3 18:46:54 2001
@@ -1,5 +1,5 @@
 /*
- * $Id: prep_pci.c,v 1.31 1999/04/21 18:21:37 cort Exp $
+ * $Id: prep_pci.c,v 1.33 1999/05/09 20:15:54 cort Exp $
  * PReP pci functions.
  * Originally by Gary Thomas
  * rewritten and updated by Cort Dougan (cort@cs.nmt.edu)
@@ -35,6 +35,9 @@
 /* How is the 82378 PIRQ mapping setup? */
 unsigned char *Motherboard_routes;
 
+/* Used for Motorola to store system config register */
+static unsigned long	*ProcInfo;
+
 /* Tables for known hardware */   
 
 /* Motorola PowerStackII - Utah */
@@ -42,38 +45,39 @@
 {
         0,   /* Slot 0  - unused */
         0,   /* Slot 1  - unused */
-        4,   /* Slot 2  - SCSI - NCR825A  */
+        5,   /* Slot 2  - SCSI - NCR825A  */
         0,   /* Slot 3  - unused */
         1,   /* Slot 4  - Ethernet - DEC2114x */
         0,   /* Slot 5  - unused */
-        2,   /* Slot 6  - PCI Card slot #1 */
-        3,   /* Slot 7  - PCI Card slot #2 */
-        4,   /* Slot 8  - PCI Card slot #3 */
-        4,   /* Slot 9  - PCI Bridge */
+        3,   /* Slot 6  - PCI Card slot #1 */
+        4,   /* Slot 7  - PCI Card slot #2 */
+        5,   /* Slot 8  - PCI Card slot #3 */
+        5,   /* Slot 9  - PCI Bridge */
              /* added here in case we ever support PCI bridges */
              /* Secondary PCI bus cards are at slot-9,6 & slot-9,7 */
         0,   /* Slot 10 - unused */
         0,   /* Slot 11 - unused */
-        4,   /* Slot 12 - SCSI - NCR825A */
+        5,   /* Slot 12 - SCSI - NCR825A */
         0,   /* Slot 13 - unused */
-        2,   /* Slot 14 - enet */
+        3,   /* Slot 14 - enet */
         0,   /* Slot 15 - unused */
-        0,
-        0,
-        0,
-        0,
-        0,
-        0,
-        0,
+        2,   /* Slot 16 - unused */
+        3,   /* Slot 17 - unused */
+        5,   /* Slot 18 - unused */
+        0,   /* Slot 19 - unused */
+        0,   /* Slot 20 - unused */
+        0,   /* Slot 21 - unused */
+        0,   /* Slot 22 - unused */
 };
 
 static char Utah_pci_IRQ_routes[] __prepdata =
 {
         0,   /* Line 0 - Unused */
         9,   /* Line 1 */
-        11,  /* Line 2 */
-        14,  /* Line 3 */
-        15,  /* Line 4 */
+	10,  /* Line 2 */
+        11,  /* Line 3 */
+        14,  /* Line 4 */
+        15,  /* Line 5 */
 };
 
 /* Motorola PowerStackII - Omaha */
@@ -133,9 +137,9 @@
   	0,	/* Slot 13 - unused */
   	1,	/* Slot 14 - Ethernet */
   	0,	/* Slot 15 - unused */
-  	1,	/* Slot P7 */
-  	2,	/* Slot P6 */
-  	3,	/* Slot P5 */
+ 	1,	/* Slot P7 */
+ 	2,	/* Slot P6 */
+ 	3,	/* Slot P5 */
 };
 
 static char Blackhawk_pci_IRQ_routes[] __prepdata =
@@ -147,6 +151,122 @@
    	15	/* Line 4 */
 };
    
+/* Motorola Mesquite */
+static char Mesquite_pci_IRQ_map[23] __prepdata =
+{
+	0,	/* Slot 0  - unused */
+	0,	/* Slot 1  - unused */
+	0,	/* Slot 2  - unused */
+	0,	/* Slot 3  - unused */
+	0,	/* Slot 4  - unused */
+	0,	/* Slot 5  - unused */
+	0,	/* Slot 6  - unused */
+	0,	/* Slot 7  - unused */
+	0,	/* Slot 8  - unused */
+	0,	/* Slot 9  - unused */
+	0,	/* Slot 10 - unxued */
+	0,	/* Slot 11 - unused */
+	0,	/* Slot 12 - unused */
+	0,	/* Slot 13 - unused */
+	2,	/* Slot 14 - Ethernet */
+	0,	/* Slot 15 - unused */
+	3,	/* Slot 16 - PMC */
+	0,	/* Slot 17 - unused */
+	0,	/* Slot 18 - unused */
+	0,	/* Slot 19 - unused */
+	0,	/* Slot 20 - unused */
+	0,	/* Slot 21 - unused */
+	0,	/* Slot 22 - unused */
+};
+
+/* Motorola Sitka */
+static char Sitka_pci_IRQ_map[21] __prepdata =
+{
+	0,      /* Slot 0  - unused */
+	0,      /* Slot 1  - unused */
+	0,      /* Slot 2  - unused */
+	0,      /* Slot 3  - unused */
+	0,      /* Slot 4  - unused */
+	0,      /* Slot 5  - unused */
+	0,      /* Slot 6  - unused */
+	0,      /* Slot 7  - unused */
+	0,      /* Slot 8  - unused */
+	0,      /* Slot 9  - unused */
+	0,      /* Slot 10 - unxued */
+	0,      /* Slot 11 - unused */
+	0,      /* Slot 12 - unused */
+	0,      /* Slot 13 - unused */
+	2,      /* Slot 14 - Ethernet */
+	0,      /* Slot 15 - unused */
+	9,      /* Slot 16 - PMC 1  */
+	12,     /* Slot 17 - PMC 2  */
+	0,      /* Slot 18 - unused */
+	0,      /* Slot 19 - unused */
+	4,      /* Slot 20 - NT P2P bridge */
+};
+
+/* Motorola MTX */
+static char MTX_pci_IRQ_map[23] __prepdata =
+{
+	0,	/* Slot 0  - unused */
+	0,	/* Slot 1  - unused */
+	0,	/* Slot 2  - unused */
+	0,	/* Slot 3  - unused */
+	0,	/* Slot 4  - unused */
+	0,	/* Slot 5  - unused */
+	0,	/* Slot 6  - unused */
+	0,	/* Slot 7  - unused */
+	0,	/* Slot 8  - unused */
+	0,	/* Slot 9  - unused */
+	0,	/* Slot 10 - unused */
+	0,	/* Slot 11 - unused */
+	3,	/* Slot 12 - SCSI */
+	0,	/* Slot 13 - unused */
+	2,	/* Slot 14 - Ethernet */
+	0,	/* Slot 15 - unused */
+	9,      /* Slot 16 - PCI/PMC slot 1 */
+	10,     /* Slot 17 - PCI/PMC slot 2 */
+	11,     /* Slot 18 - PCI slot 3 */
+	0,	/* Slot 19 - unused */
+	0,	/* Slot 20 - unused */
+	0,	/* Slot 21 - unused */
+	0,	/* Slot 22 - unused */
+};
+
+/* Motorola MTX Plus */
+/* Secondary bus interrupt routing is not supported yet */
+static char MTXplus_pci_IRQ_map[23] __prepdata =
+{
+        0,      /* Slot 0  - unused */
+        0,      /* Slot 1  - unused */
+        0,      /* Slot 2  - unused */
+        0,      /* Slot 3  - unused */
+        0,      /* Slot 4  - unused */
+        0,      /* Slot 5  - unused */
+        0,      /* Slot 6  - unused */
+        0,      /* Slot 7  - unused */
+        0,      /* Slot 8  - unused */
+        0,      /* Slot 9  - unused */
+        0,      /* Slot 10 - unused */
+        0,      /* Slot 11 - unused */
+        3,      /* Slot 12 - SCSI */
+        0,      /* Slot 13 - unused */
+        2,      /* Slot 14 - Ethernet 1 */
+        0,      /* Slot 15 - unused */
+        9,      /* Slot 16 - PCI slot 1P */
+        10,     /* Slot 17 - PCI slot 2P */
+        11,     /* Slot 18 - PCI slot 3P */
+        10,     /* Slot 19 - Ethernet 2 */
+        0,      /* Slot 20 - P2P Bridge */
+        0,      /* Slot 21 - unused */
+        0,      /* Slot 22 - unused */
+};
+
+static char Raven_pci_IRQ_routes[] __prepdata =
+{
+   	0,	/* This is a dummy structure */
+};
+   
 /* Motorola MVME16xx */
 static char Genesis_pci_IRQ_map[16] __prepdata =
 {
@@ -177,48 +297,35 @@
    	15	/* Line 4 */
 };
    
-/* Motorola Genesis2 MVME26XX, MVME 36XX */
-/* The final version for these boards should use the Raven PPC/PCI bridge 
-interrupt controller which is much sophisticated and allows more
-devices on the PCI bus. */
 static char Genesis2_pci_IRQ_map[23] __prepdata =
-  {
-        0,	/* Slot 0  - ECC memory controller/PCI bridge */
+{
+	0,	/* Slot 0  - unused */
 	0,	/* Slot 1  - unused */
-  	0,	/* Slot 2  - unused */
-  	0,	/* Slot 3  - unused */
-  	0,	/* Slot 4  - unused */
-  	0,	/* Slot 5  - unused */
-  	0,	/* Slot 6  - unused */
-  	0,	/* Slot 7  - unused */
-  	0,	/* Slot 8  - unused */
-  	0,	/* Slot 9  - unused */
-  	0,	/* Slot 10 - unused */
-  	0,	/* Slot 11 - ISA bridge */
-	3,	/* Slot 12 - SCSI */
-  	2,	/* Slot 13 - Universe PCI/VME bridge (and 22..24) */
-  	1,	/* Slot 14 - Ethernet */
-  	0,	/* Slot 15 - Unused (graphics on 3600, would be 20 ?) */
-	4,      /* Slot 16 - PMC slot, assume uses INTA */
-	0,      /* Slot 17 */
-	0,      /* Slot 18 */
-	0,      /* Slot 19 */
-	0,      /* Slot 20 */
-	0,      /* Slot 21 */
-	0,      /* Slot 22 */
-  };
+	0,	/* Slot 2  - unused */
+	0,	/* Slot 3  - unused */
+	0,	/* Slot 4  - unused */
+	0,	/* Slot 5  - unused */
+	0,	/* Slot 6  - unused */
+	0,	/* Slot 7  - unused */
+	0,	/* Slot 8  - unused */
+	0,	/* Slot 9  - unused */
+	0,	/* Slot 10 - Ethernet */
+	0,	/* Slot 11 - Universe PCI - VME Bridge */
+	3,	/* Slot 12 - unused */
+	0,	/* Slot 13 - unused */
+	2,	/* Slot 14 - SCSI */
+	0,	/* Slot 15 - graphics on 3600 */
+	9,	/* Slot 16 - PMC */
+	12,	/* Slot 17 - pci */
+	11,	/* Slot 18 - pci */
+	10,	/* Slot 19 - pci */
+	0,	/* Slot 20 - pci */
+	0,	/* Slot 21 - unused */
+	0,	/* Slot 22 - unused */
+};
 
-static char Genesis2_pci_IRQ_routes[] __prepdata=
-   {
-   	0,	/* Line 0 - Unused */
-   	10,	/* Line 1 - INTA */
-   	11,	/* Line 2 - INTB */
-   	14,	/* Line 3 - INTC */
-   	15	/* Line 4 - INTD */
-   };
-   
 /* Motorola Series-E */
-static char Comet_pci_IRQ_map[16] __prepdata =
+static char Comet_pci_IRQ_map[23] __prepdata =
 {
   	0,	/* Slot 0  - unused */
   	0,	/* Slot 1  - unused */
@@ -236,6 +343,13 @@
   	0,	/* Slot 13 - unused */
   	1,	/* Slot 14 - Ethernet */
   	0,	/* Slot 15 - unused */
+	1,	/* Slot 16 - PCI slot 1 */
+	2,	/* Slot 17 - PCI slot 2 */
+	3,	/* Slot 18 - PCI slot 3 */
+	4,	/* Slot 19 - PCI bridge */
+	0,
+	0,
+	0,
 };
 
 static char Comet_pci_IRQ_routes[] __prepdata =
@@ -247,6 +361,43 @@
    	15	/* Line 4 */
 };
 
+/* Motorola Series-EX */
+static char Comet2_pci_IRQ_map[23] __prepdata =
+{
+	0,	/* Slot 0  - unused */
+	0,	/* Slot 1  - unused */
+	3,	/* Slot 2  - SCSI - NCR825A */
+	0,	/* Slot 3  - unused */
+	1,	/* Slot 4  - Ethernet - DEC2104X */
+	0,	/* Slot 5  - unused */
+	1,	/* Slot 6  - PCI slot 1 */
+	2,	/* Slot 7  - PCI slot 2 */
+	3,	/* Slot 8  - PCI slot 3 */
+	4,	/* Slot 9  - PCI bridge  */
+	0,	/* Slot 10 - unused */
+	0,	/* Slot 11 - unused */
+	3,	/* Slot 12 - SCSI - NCR825A */
+	0,	/* Slot 13 - unused */
+	1,	/* Slot 14 - Ethernet - DEC2104X */
+	0,	/* Slot 15 - unused */
+	1,	/* Slot 16 - PCI slot 1 */
+	2,	/* Slot 17 - PCI slot 2 */
+	3,	/* Slot 18 - PCI slot 3 */
+	4,	/* Slot 19 - PCI bridge */
+	0,
+	0,
+	0,
+};
+
+static char Comet2_pci_IRQ_routes[] __prepdata =
+{
+	0,	/* Line 0 - Unused */
+	10,	/* Line 1 */
+	11,	/* Line 2 */
+	14,	/* Line 3 */
+	15,	/* Line 4 */
+};
+
 /*
  * ibm 830 (and 850?).
  * This is actually based on the Carolina motherboard
@@ -502,6 +653,137 @@
 	return PCIBIOS_SUCCESSFUL;
 }
 
+#define MOTOROLA_CPUTYPE_REG	0x800
+#define MOTOROLA_BASETYPE_REG	0x803
+#define MPIC_RAVEN_ID		0x48010000
+#define	MPIC_HAWK_ID		0x48030000
+#define	MOT_PROC2_BIT		0x800
+
+static u_char mvme2600_openpic_initsenses[] __initdata = {
+    1,	/* MVME2600_INT_SIO */
+    0,	/* MVME2600_INT_FALCN_ECC_ERR */
+    1,	/* MVME2600_INT_PCI_ETHERNET */
+    1,	/* MVME2600_INT_PCI_SCSI */
+    1,	/* MVME2600_INT_PCI_GRAPHICS */
+    1,	/* MVME2600_INT_PCI_VME0 */
+    1,	/* MVME2600_INT_PCI_VME1 */
+    1,	/* MVME2600_INT_PCI_VME2 */
+    1,	/* MVME2600_INT_PCI_VME3 */
+    1,	/* MVME2600_INT_PCI_INTA */
+    1,	/* MVME2600_INT_PCI_INTB */
+    1,	/* MVME2600_INT_PCI_INTC */
+    1,	/* MVME2600_INT_PCI_INTD */
+    1,	/* MVME2600_INT_LM_SIG0 */
+    1,	/* MVME2600_INT_LM_SIG1 */
+};
+
+#define MOT_RAVEN_PRESENT	0x1
+#define MOT_HAWK_PRESENT	0x2
+
+int prep_keybd_present = 1;
+int MotMPIC = 0;
+
+__initfunc(int raven_init(void))
+{
+	unsigned int	devid;
+	unsigned int	pci_membase;
+	unsigned char	base_mod;
+
+	/* Check to see if the Raven chip exists. */
+	if ( _prep_type != _PREP_Motorola) {
+		OpenPIC = NULL;
+		return 0;
+	}
+
+	/* Check to see if this board is a type that might have a Raven. */
+	if ((inb(MOTOROLA_CPUTYPE_REG) & 0xF0) != 0xE0) {
+		OpenPIC = NULL;
+		return 0;
+	}
+
+	/* Check the first PCI device to see if it is a Raven. */
+	pcibios_read_config_dword(0, 0, PCI_VENDOR_ID, &devid);
+
+	switch (devid & 0xffff0000) {
+	case MPIC_RAVEN_ID:
+		MotMPIC = MOT_RAVEN_PRESENT;
+		break;
+	case MPIC_HAWK_ID:
+		MotMPIC = MOT_HAWK_PRESENT;
+		break;
+	default:
+		OpenPIC = NULL;
+		return 0;
+	}
+
+
+	/* Read the memory base register. */
+	pcibios_read_config_dword(0, 0, PCI_BASE_ADDRESS_1, &pci_membase);
+
+	if (pci_membase == 0) {
+		OpenPIC = NULL;
+		return 0;
+	}
+
+	/* Map the Raven MPIC registers to virtual memory. */
+	OpenPIC = (struct OpenPIC *)ioremap(pci_membase+0xC0000000, 0x22000);
+
+	OpenPIC_InitSenses = mvme2600_openpic_initsenses;
+	OpenPIC_NumInitSenses = sizeof(mvme2600_openpic_initsenses);
+
+	/* If raven is present on Motorola store the system config register
+	 * for later use.
+	 */
+	ProcInfo = (unsigned long *)ioremap(0xfef80400, 4);
+
+	/* This is a hack.  If this is a 2300 or 2400 mot board then there is
+	 * no keyboard controller and we have to indicate that.
+	 */
+	base_mod = inb(MOTOROLA_BASETYPE_REG);
+	if ((MotMPIC == MOT_HAWK_PRESENT) || (base_mod == 0xF9) ||
+	    (base_mod == 0xFA) || (base_mod == 0xE1))
+		prep_keybd_present = 0;
+
+	return 1;
+}
+
+struct mot_info {
+	int		cpu_type;	/* 0x100 mask assumes for Raven and Hawk boards that the level/edge are set */
+					/* 0x200 if this board has a Hawk chip. */
+	int		base_type;
+	int		max_cpu;	/* ored with 0x80 if this board should be checked for multi CPU */
+	const char	*name;
+	unsigned char	*map;
+	unsigned char	*routes;
+} mot_info[] = {
+	{0x300, 0x00, 0x00, "MVME 2400",			Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes},
+	{0x010, 0x00, 0x00, "Genesis",				Genesis_pci_IRQ_map,	Genesis_pci_IRQ_routes},
+	{0x020, 0x00, 0x00, "Powerstack (Series E)",		Comet_pci_IRQ_map,	Comet_pci_IRQ_routes},
+	{0x040, 0x00, 0x00, "Blackhawk (Powerstack)",		Blackhawk_pci_IRQ_map,	Blackhawk_pci_IRQ_routes},
+	{0x050, 0x00, 0x00, "Omaha (PowerStack II Pro3000)",	Omaha_pci_IRQ_map,	Omaha_pci_IRQ_routes},
+	{0x060, 0x00, 0x00, "Utah (Powerstack II Pro4000)",	Utah_pci_IRQ_map,	Utah_pci_IRQ_routes},
+	{0x0A0, 0x00, 0x00, "Powerstack (Series EX)",		Comet2_pci_IRQ_map,	Comet2_pci_IRQ_routes},
+	{0x1E0, 0xE0, 0x00, "Mesquite cPCI (MCP750)",		Mesquite_pci_IRQ_map,	Raven_pci_IRQ_routes},
+	{0x1E0, 0xE1, 0x00, "Sitka cPCI (MCPN750)",		Sitka_pci_IRQ_map,	Raven_pci_IRQ_routes},
+	{0x1E0, 0xE2, 0x00, "Mesquite cPCI (MCP750) w/ HAC",	Mesquite_pci_IRQ_map,	Raven_pci_IRQ_routes},
+	{0x1E0, 0xF6, 0x80, "MTX Plus",				MTXplus_pci_IRQ_map,	Raven_pci_IRQ_routes},
+	{0x1E0, 0xF6, 0x81, "Dual MTX Plus",			MTXplus_pci_IRQ_map,	Raven_pci_IRQ_routes},
+	{0x1E0, 0xF7, 0x80, "MTX wo/ Parallel Port",		MTX_pci_IRQ_map,	Raven_pci_IRQ_routes},
+	{0x1E0, 0xF7, 0x81, "Dual MTX wo/ Parallel Port",	MTX_pci_IRQ_map,	Raven_pci_IRQ_routes},
+	{0x1E0, 0xF8, 0x80, "MTX w/ Parallel Port",		MTX_pci_IRQ_map,	Raven_pci_IRQ_routes},
+	{0x1E0, 0xF8, 0x81, "Dual MTX w/ Parallel Port",	MTX_pci_IRQ_map,	Raven_pci_IRQ_routes},
+	{0x1E0, 0xF9, 0x00, "MVME 2300",			Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes},
+	{0x1E0, 0xFA, 0x00, "MVME 2300SC/2600",			Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes},
+	{0x1E0, 0xFB, 0x00, "MVME 2600 with MVME712M",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes},
+	{0x1E0, 0xFC, 0x00, "MVME 2600/2700 with MVME761",	Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes},
+	{0x1E0, 0xFD, 0x80, "MVME 3600 with MVME712M",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes},
+	{0x1E0, 0xFD, 0x81, "MVME 4600 with MVME712M",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes},
+	{0x1E0, 0xFE, 0x80, "MVME 3600 with MVME761",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes},
+	{0x1E0, 0xFE, 0x81, "MVME 4600 with MVME761",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes},
+	{0x1E0, 0xFF, 0x00, "MVME 1600-001 or 1600-011",	Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes},
+	{0x000, 0x00, 0x00, "",					NULL,			NULL}
+};
+
 __initfunc(unsigned long prep_route_pci_interrupts(void))
 {
 	unsigned char *ibc_pirq = (unsigned char *)0x80800860;
@@ -511,53 +793,66 @@
 	if ( _prep_type == _PREP_Motorola)
 	{
 		unsigned short irq_mode;
+		unsigned char  cpu_type;
+		unsigned char  base_mod;
+		int	       entry;
+		int	       mot_entry = -1;
+
+		cpu_type = inb(MOTOROLA_CPUTYPE_REG) & 0xF0;
+		base_mod = inb(MOTOROLA_BASETYPE_REG);
+
+		for (entry = 0; mot_info[entry].cpu_type != 0; entry++) {
+			if (mot_info[entry].cpu_type & 0x200) {		 	/* Check for Hawk chip */
+				if (!(MotMPIC & MOT_HAWK_PRESENT))
+					continue;
+			} else {						/* Check non hawk boards */
+				if ((mot_info[entry].cpu_type & 0xff) != cpu_type)
+					continue;
+
+				if (mot_info[entry].base_type == 0) {
+					mot_entry = entry;
+					break;
+				}
 
-		switch (inb(0x800) & 0xF0)
-		{
-		case 0x10: /* MVME16xx */
-			Motherboard_map_name = "Genesis";
-			Motherboard_map = Genesis_pci_IRQ_map;
-			Motherboard_routes = Genesis_pci_IRQ_routes;
-			break;
-		case 0x20: /* Series E */
-			Motherboard_map_name = "Powerstack (Series E)";
-			Motherboard_map = Comet_pci_IRQ_map;
-			Motherboard_routes = Comet_pci_IRQ_routes;
-			break;
-		case 0x50: /* PowerStackII Pro3000 */
-			Motherboard_map_name = "Omaha (PowerStack II Pro3000)";
-			Motherboard_map = Omaha_pci_IRQ_map;
-			Motherboard_routes = Omaha_pci_IRQ_routes;
-			break;
-		case 0x60: /* PowerStackII Pro4000 */
-			Motherboard_map_name = "Utah (Powerstack II Pro4000)";
-			Motherboard_map = Utah_pci_IRQ_map;
-			Motherboard_routes = Utah_pci_IRQ_routes;
-			break;
-		case 0xE0: /* MVME 26xx, 36xx, MTX ? */
-			Motherboard_map_name = "Genesis2";
-			Motherboard_map = Genesis2_pci_IRQ_map;
-			Motherboard_routes = Genesis2_pci_IRQ_routes;
-
-			/* Return: different ibc_pcicon and
-			   pirq already set up by firmware. */
-			return 0; 
-			break;
-		case 0x40: /* PowerStack */
-		default: /* Can't hurt, can it? */
-			Motherboard_map_name = "Blackhawk (Powerstack)";
-			Motherboard_map = Blackhawk_pci_IRQ_map;
-			Motherboard_routes = Blackhawk_pci_IRQ_routes;
-			break;
+				if (mot_info[entry].base_type != base_mod)
+					continue;
+			}
+
+			if (!(mot_info[entry].max_cpu & 0x80)) {
+				mot_entry = entry;
+				break;
+			}
+
+			/* processor 1 not present and max processor zero indicated */
+			if ((*ProcInfo & MOT_PROC2_BIT) && !(mot_info[entry].max_cpu & 0x7f)) {
+				mot_entry = entry;
+				break;
+			}
+
+			/* processor 1 present and max processor zero indicated */
+			if (!(*ProcInfo & MOT_PROC2_BIT) && (mot_info[entry].max_cpu & 0x7f)) {
+				mot_entry = entry;
+				break;
+			}
 		}
-		/* AJF adjust level/edge control according to routes */
-		irq_mode = 0;
-		for (i = 1;  i <= 4;  i++)
-		{
-			irq_mode |= ( 1 << Motherboard_routes[i] );
+
+		if (mot_entry == -1) 	/* No particular cpu type found - assume Blackhawk */
+			mot_entry = 3;
+
+		Motherboard_map_name = (unsigned char *)mot_info[mot_entry].name;
+		Motherboard_map = mot_info[mot_entry].map;
+		Motherboard_routes = mot_info[mot_entry].routes;
+
+		if (!(mot_info[entry].cpu_type & 0x100)) {
+			/* AJF adjust level/edge control according to routes */
+			irq_mode = 0;
+			for (i = 1;  i <= 4;  i++)
+			{
+				irq_mode |= ( 1 << Motherboard_routes[i] );
+			}
+			outb( irq_mode & 0xff, 0x4d0 );
+			outb( (irq_mode >> 8) & 0xff, 0x4d1 );
 		}
-		outb( irq_mode & 0xff, 0x4d0 );
-		outb( (irq_mode >> 8) & 0xff, 0x4d1 );
 	} else if ( _prep_type == _PREP_IBM )
 	{
 		unsigned char pl_id;
@@ -678,71 +973,6 @@
 }
 
 __initfunc(
-static inline void fixup_pci_interrupts(PnP_TAG_PACKET *pkt)) {
-#define data pkt->L4_Pack.L4_Data.L4_PPCPack.PPCData
-        u_int bus = data[16];
-        u_char *End, *p;
-
-        End = data + ld_le16((u_short *)(&pkt->L4_Pack.Count0)) - 1;
-        printk("Interrupt mapping from %d to %d\n", 20, End-data);
-        for (p=data+20; p<End; p+=12){
-                struct pci_dev *dev;
-                for (dev=pci_devices; dev; dev=dev->next) {
-                        unsigned code, irq;
-                        u_char pin;
-
-                        if ( dev->bus->number != bus ||
-                             PCI_SLOT(dev->devfn) != PCI_SLOT(p[1]))
-                                continue;
-                        pci_read_config_byte(dev,  PCI_INTERRUPT_PIN, &pin);
-                        if(!pin) continue;
-                        code=ld_le16((unsigned short *)
-                                    (p+4+2*(pin-1)));
-                        /* Set vector to 0 for unrouted PCI ints. This code
-                         * is ugly but handles correctly the special case of
-                         * interrupt 0 (8259 cascade) on OpenPIC
-                         */
-
-                        irq = (code == 0xffff) ? 0 : code&0x7fff;
-                        if (p[2] == 2) { /* OpenPIC */
-                                if (irq) {
-                                        openpic_set_sense(irq, code<0x8000);
-                                        irq=openpic_to_irq(irq);
-                                } else continue;
-                        } else if (p[2] != 1){ /* Not 8259 */
-                                printk("Unknown or unsupported "
-                                       "interrupt controller"
-                                       "type %d.\n",  p[2]);
-                                continue;
-                        }
-                        dev->irq=irq;
-                }
-
-        }
-}
-
-__initfunc(
-static inline void fixup_bases(struct pci_dev *dev)) {
-        int k;
-        for (k=0; k<6; k++) {
-		/* FIXME: get the base address physical offset from 
-			the Raven instead of hard coding it.
-				-- Troy */
-                if (dev->base_address[k] &&
-                    (dev->base_address[k]&PCI_BASE_ADDRESS_SPACE)
-                    == PCI_BASE_ADDRESS_SPACE_MEMORY)
-                        dev->base_address[k]+=0xC0000000;
-                if ((dev->base_address[k] &
-                     (PCI_BASE_ADDRESS_SPACE |
-                      PCI_BASE_ADDRESS_MEM_TYPE_MASK))
-                     == (PCI_BASE_ADDRESS_SPACE_MEMORY |
-                         PCI_BASE_ADDRESS_MEM_TYPE_64))
-                        k++;
-        }
-}
-
-
-__initfunc(
 void
 prep_pcibios_fixup(void))
 {
@@ -754,44 +984,57 @@
         if ( _prep_type == _PREP_Radstone )
         {
                 printk("Radstone boards require no PCI fixups\n");
+		return;
         }
-        else
-        {
-	        prep_route_pci_interrupts();
-                for(dev=pci_devices; dev; dev=dev->next)
-                {
-                        /*
-                         * Use our old hard-coded kludge to figure out what
-                         * irq this device uses.  This is necessary on things
-                         * without residual data. -- Cort
-                         */
-                        unsigned char d = PCI_SLOT(dev->devfn);
-                        dev->irq = Motherboard_routes[Motherboard_map[d]];
-                        for ( i = 0 ; i <= 5 ; i++ )
-                        {
-                                if ( dev->base_address[i] > 0x10000000 )
-                                {
-                                        printk("Relocating PCI address %lx -> %lx\n",
-                                               dev->base_address[i],
-                                               (dev->base_address[i] & 0x00FFFFFF)
-                                               | 0x01000000);
-                                        dev->base_address[i] =
-                                          (dev->base_address[i] & 0x00FFFFFF) | 0x01000000;
-                                        pci_write_config_dword(dev,
-                                                PCI_BASE_ADDRESS_0+(i*0x4),
-                                               dev->base_address[i] );
-                                }
-                        }
+
+	prep_route_pci_interrupts();
+
+	printk("Setting PCI interrupts for a \"%s\"\n", Motherboard_map_name);
+	if (OpenPIC) {
+		/* PCI interrupts are controlled by the OpenPIC */
+		for(dev=pci_devices; dev; dev=dev->next) {
+			if (dev->bus->number == 0) {
+                       		dev->irq = openpic_to_irq(Motherboard_map[PCI_SLOT(dev->devfn)]);
+				pcibios_write_config_byte(dev->bus->number, dev->devfn, PCI_INTERRUPT_PIN, dev->irq);
+			}
+		}
+		return;
+	}
+
+	for(dev=pci_devices; dev; dev=dev->next)
+	{
+		/*
+		 * Use our old hard-coded kludge to figure out what
+		 * irq this device uses.  This is necessary on things
+		 * without residual data. -- Cort
+		 */
+		unsigned char d = PCI_SLOT(dev->devfn);
+		dev->irq = Motherboard_routes[Motherboard_map[d]];
+
+		for ( i = 0 ; i <= 5 ; i++ )
+		{
+		        if ( dev->base_address[i] > 0x10000000 )
+		        {
+		                printk("Relocating PCI address %lx -> %lx\n",
+		                       dev->base_address[i],
+		                       (dev->base_address[i] & 0x00FFFFFF)
+		                       | 0x01000000);
+		                dev->base_address[i] =
+		                  (dev->base_address[i] & 0x00FFFFFF) | 0x01000000;
+		                pci_write_config_dword(dev,
+		                        PCI_BASE_ADDRESS_0+(i*0x4),
+		                       dev->base_address[i] );
+		        }
+		}
 #if 0
-                        /*
-                         * If we have residual data and if it knows about this
-                         * device ask it what the irq is.
-                         *  -- Cort
-                         */
-                        ppcd = residual_find_device_id( ~0L, dev->device,
-                                                        -1,-1,-1, 0);
+		/*
+		 * If we have residual data and if it knows about this
+		 * device ask it what the irq is.
+		 *  -- Cort
+		 */
+		ppcd = residual_find_device_id( ~0L, dev->device,
+		                                -1,-1,-1, 0);
 #endif
-		}
 	}
 }
 
diff -urN linux-2.2.8-pre7/arch/ppc/kernel/prep_setup.c linux/arch/ppc/kernel/prep_setup.c
--- linux-2.2.8-pre7/arch/ppc/kernel/prep_setup.c	Mon Dec  3 18:46:19 2001
+++ linux/arch/ppc/kernel/prep_setup.c	Mon Dec  3 18:46:54 2001
@@ -45,6 +45,8 @@
 #include <asm/machdep.h>
 #include <asm/mk48t59.h>
 #include <asm/prep_nvram.h>
+#include <asm/raven.h>
+
 
 #include "time.h"
 #include "local_irq.h"
@@ -82,15 +84,7 @@
 extern unsigned char pckbd_sysrq_xlate[128];
 
 extern void prep_setup_pci_ptrs(void);
-
-/* these need to be here since PReP uses them for OpenPIC support */
-/* Maybe move these to a 'openpic_irq.c' file instead? --Troy */
-extern void chrp_mask_and_ack_irq(unsigned int irq_nr);
-extern void chrp_mask_irq(unsigned int irq_nr);
-extern void chrp_unmask_irq(unsigned int irq_nr);
 extern void chrp_do_IRQ(struct pt_regs *regs, int cpu, int isfake);
-extern volatile unsigned char *chrp_int_ack_special;
-
 extern char saved_command_line[256];
 
 int _prep_type;
@@ -355,6 +349,8 @@
 	request_region(0x80,0x10,"dma page reg");
 	request_region(0xc0,0x20,"dma2");
 
+	raven_init();
+
 #ifdef CONFIG_VGA_CONSOLE
 	/* remap the VGA memory */
 	vgacon_remap_base = 0xf0000000;
@@ -595,39 +591,13 @@
 prep_do_IRQ(struct pt_regs *regs, int cpu, int isfake)
 {
         int irq;
-	
-        /*
-         * Perform an interrupt acknowledge cycle on controller 1
-         */                                                             
-        outb(0x0C, 0x20);
-        irq = inb(0x20) & 7;                                   
-        if (irq == 2)                                                     
-        {                                                                   
-                /*                                     
-                 * Interrupt is cascaded so perform interrupt
-                 * acknowledge on controller 2
-                 */
-                outb(0x0C, 0xA0);                      
-                irq = (inb(0xA0) & 7) + 8;
-        }
-        else if (irq==7)                                
-        {
-                /*                               
-                 * This may be a spurious interrupt
-                 *                         
-                 * Read the interrupt status register. If the most
-                 * significant bit is not set then there is no valid
-		 * interrupt
-		 */
-		outb(0x0b, 0x20);
-		 
-		if(~inb(0x20)&0x80)
-		{
-			printk(KERN_DEBUG "Bogus interrupt from PC = %lx\n",
-			       regs->nip);
-                        ppc_spurious_interrupts++;
-                        return;
-                }
+
+	if ( (irq = i8259_irq(0)) < 0 )
+	{
+		printk(KERN_DEBUG "Bogus interrupt from PC = %lx\n",
+		       regs->nip);
+		ppc_spurious_interrupts++;
+		return;
 	}
         ppc_irq_dispatch_handler( regs, irq );
 }		
@@ -637,9 +607,19 @@
 {
 	int i;
 
+	if (OpenPIC != NULL) {
+		for ( i = 16 ; i < 36 ; i++ )
+			irq_desc[i].ctl = &open_pic;
+		openpic_init(1);
+	}
+	
         for ( i = 0 ; i < 16  ; i++ )
                 irq_desc[i].ctl = &i8259_pic;
         i8259_init();
+#ifdef __SMP__
+	request_irq(openpic_to_irq(OPENPIC_VEC_SPURIOUS), openpic_ipi_action,
+		    0, "IPI0", 0);
+#endif /* __SMP__ */
 }
 
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
@@ -728,8 +708,6 @@
 prep_init(unsigned long r3, unsigned long r4, unsigned long r5,
 	  unsigned long r6, unsigned long r7))
 {
-	int tmp;
-
 	/* make a copy of residual data */
 	if ( r3 )
 	{
@@ -784,27 +762,15 @@
 		strcpy(cmd_line, (char *)(r6+KERNELBASE));
 	}
 
-	if ( is_powerplus ) {	/* look for a Raven OpenPIC */
-		pcibios_read_config_dword(0, 0, 0, &tmp);
-		if (tmp == PCI_VENDOR_ID_MOTOROLA + (PCI_DEVICE_ID_MOTOROLA_RAVEN<<16)) {
-			pcibios_read_config_dword(0, 0, PCI_BASE_ADDRESS_1, &tmp);
-			if (tmp) {
-				OpenPIC=(volatile struct OpenPIC *)
-					(tmp + isa_mem_base);
-				/* printk("OpenPIC found at %p: \n", OpenPIC);*/
-			}
-		} else {
-			printk ("prep_init: WARNING: can't find an OpenPIC on what looks like a PowerPlus board\n");
-		}
-	}
-
-
 	ppc_md.setup_arch     = prep_setup_arch;
 	ppc_md.setup_residual = prep_setup_residual;
 	ppc_md.get_cpuinfo    = prep_get_cpuinfo;
 	ppc_md.irq_cannonicalize = prep_irq_cannonicalize;
 	ppc_md.init_IRQ       = prep_init_IRQ;
-	ppc_md.do_IRQ         = prep_do_IRQ;
+	if ( !OpenPIC )
+		ppc_md.do_IRQ         = prep_do_IRQ;
+	else
+		ppc_md.do_IRQ         = chrp_do_IRQ;
 	ppc_md.init           = NULL;
 
 	ppc_md.restart        = prep_restart;
@@ -858,9 +824,8 @@
         ppc_ide_md.release_region = prep_ide_release_region;
         ppc_ide_md.fix_driveid = prep_ide_fix_driveid;
         ppc_ide_md.ide_init_hwif = prep_ide_init_hwif_ports;
-
-        ppc_ide_md.io_base = _IO_BASE;
 #endif		
+        ppc_ide_md.io_base = _IO_BASE;
 
 #ifdef CONFIG_VT
 	ppc_md.kbd_setkeycode    = pckbd_setkeycode;
diff -urN linux-2.2.8-pre7/arch/ppc/kernel/process.c linux/arch/ppc/kernel/process.c
--- linux-2.2.8-pre7/arch/ppc/kernel/process.c	Mon Dec  3 18:46:19 2001
+++ linux/arch/ppc/kernel/process.c	Mon Dec  3 18:46:54 2001
@@ -1,5 +1,5 @@
 /*
- * $Id: process.c,v 1.78 1999/04/07 07:27:00 paulus Exp $
+ * $Id: process.c,v 1.83 1999/05/10 04:43:43 cort Exp $
  *
  *  linux/arch/ppc/kernel/process.c
  *
@@ -43,10 +43,7 @@
 #include <asm/prom.h>
 
 int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs);
-void switch_to(struct task_struct *, struct task_struct *);
-
 extern unsigned long _get_SP(void);
-extern spinlock_t scheduler_lock;
 
 struct task_struct *last_task_used_math = NULL;
 static struct vm_area_struct init_mmap = INIT_MMAP;
@@ -160,7 +157,8 @@
 }
 
 void
-switch_to(struct task_struct *prev, struct task_struct *new)
+_switch_to(struct task_struct *prev, struct task_struct *new,
+	  struct task_struct **last)
 {
 	struct thread_struct *new_tss, *old_tss;
 	int s = _disable_interrupts();
@@ -170,10 +168,10 @@
 #endif
 
 #ifdef SHOW_TASK_SWITCHES
-	printk("%s/%d -> %s/%d NIP %08lx cpu %d lock %x root %x/%x\n",
+	printk("%s/%d -> %s/%d NIP %08lx cpu %d root %x/%x\n",
 	       prev->comm,prev->pid,
 	       new->comm,new->pid,new->tss.regs->nip,new->processor,
-	       scheduler_lock.lock,new->fs->root,prev->fs->root);
+	       new->fs->root,prev->fs->root);
 #endif
 #ifdef __SMP__
 	/* avoid complexity of lazy save/restore of fpu
@@ -181,7 +179,8 @@
 	 * this task used the fpu during the last quantum.
 	 * 
 	 * If it tries to use the fpu again, it'll trap and
-	 * reload its fp regs.
+	 * reload its fp regs.  So we don't have to do a restore
+	 * every switch, just a save.
 	 *  -- Cort
 	 */
 	if (prev->tss.regs && (prev->tss.regs->msr & MSR_FP))
@@ -192,7 +191,7 @@
 #endif /* __SMP__ */
 	new_tss = &new->tss;
 	old_tss = &current->tss;
-	_switch(old_tss, new_tss, new->mm->context);
+	*last = _switch(old_tss, new_tss, new->mm->context);
 	_enable_interrupts(s);
 }
 
@@ -278,8 +277,12 @@
 copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
 	    struct task_struct * p, struct pt_regs * regs)
 {
-	struct pt_regs * childregs;
-	
+	struct pt_regs * childregs, *kregs;
+#ifdef __SMP__
+	extern void ret_from_smpfork(void);
+#else
+	extern void ret_from_syscall(void);
+#endif
 	/* Copy registers */
 	childregs = ((struct pt_regs *)
 		     ((unsigned long)p + sizeof(union task_union)
@@ -288,8 +291,19 @@
 	if ((childregs->msr & MSR_PR) == 0)
 		childregs->gpr[2] = (unsigned long) p;	/* `current' in new task */
 	childregs->gpr[3] = 0;  /* Result from fork() */
+	p->tss.regs = childregs;
 	p->tss.ksp = (unsigned long) childregs - STACK_FRAME_OVERHEAD;
-	p->tss.regs = childregs;	
+	p->tss.ksp -= sizeof(struct pt_regs ) + STACK_FRAME_OVERHEAD;
+	kregs = (struct pt_regs *)(p->tss.ksp + STACK_FRAME_OVERHEAD);
+#ifdef __SMP__
+	kregs->nip = (unsigned long)ret_from_smpfork;
+#else	
+	kregs->nip = (unsigned long)ret_from_syscall;
+#endif	
+	kregs->msr = MSR_KERNEL;
+	kregs->gpr[1] = (unsigned long)childregs - STACK_FRAME_OVERHEAD;
+	kregs->gpr[2] = (unsigned long)p;
+	
 	if (usp >= (unsigned long) regs) {
 		/* Stack is in kernel space - must adjust */
 		childregs->gpr[1] = (unsigned long)(childregs + 1);
@@ -311,8 +325,6 @@
 	childregs->msr &= ~MSR_FP;
 
 #ifdef __SMP__
-	if ( (p->pid != 0) || !(clone_flags & CLONE_PID) )
-		p->tss.smp_fork_ret = 1;
 	p->last_processor = NO_PROC_ID;
 #endif /* __SMP__ */
 	return 0;
@@ -379,11 +391,6 @@
 	int res;
 	lock_kernel();
 	res = do_fork(clone_flags, regs->gpr[1], regs);
-	/*
-	 * only parent returns here, child returns to either
-	 * syscall_ret_1() or kernel_thread()
-	 * -- Cort
-	 */
 #ifdef __SMP__
 	/* When we clone the idle task we keep the same pid but
 	 * the return value of 0 for both causes problems.
@@ -403,7 +410,6 @@
 	int res;
 	
 	res = do_fork(SIGCHLD, regs->gpr[1], regs);
-	/* only parent returns here */
 #ifdef __SMP__
 	/* When we clone the idle task we keep the same pid but
 	 * the return value of 0 for both causes problems.
diff -urN linux-2.2.8-pre7/arch/ppc/kernel/prom.c linux/arch/ppc/kernel/prom.c
--- linux-2.2.8-pre7/arch/ppc/kernel/prom.c	Mon Dec  3 18:46:19 2001
+++ linux/arch/ppc/kernel/prom.c	Mon Dec  3 18:46:54 2001
@@ -1,5 +1,5 @@
 /*
- * $Id: prom.c,v 1.53 1999/04/22 22:45:42 cort Exp $
+ * $Id: prom.c,v 1.54 1999/05/10 04:43:46 cort Exp $
  *
  * Procedures for interfacing to the Open Firmware PROM on
  * Power Macintosh computers.
@@ -457,7 +457,7 @@
 	 * a holding pattern controlled by the kernel (not OF) before
 	 * we destroy the OF.
 	 *
-	 * This used a chunk of high memory, puts some holding pattern
+	 * This uses a chunk of high memory, puts some holding pattern
 	 * code there and sends the other processors off to there until
 	 * smp_boot_cpus tells them to do something.  We do that by using
 	 * physical address 0x0.  The holding pattern checks that address
diff -urN linux-2.2.8-pre7/arch/ppc/mm/fault.c linux/arch/ppc/mm/fault.c
--- linux-2.2.8-pre7/arch/ppc/mm/fault.c	Tue Jan  5 11:13:56 1999
+++ linux/arch/ppc/mm/fault.c	Mon Dec  3 18:46:54 2001
@@ -140,7 +140,8 @@
 		if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
 			goto bad_area;
 	}
-	handle_mm_fault(current, vma, address, error_code & 0x02000000);
+	if (!handle_mm_fault(current, vma, address, error_code & 0x02000000))
+		goto bad_area;
 	up(&mm->mmap_sem);
 	/*
 	 * keep track of tlb+htab misses that are good addrs but
diff -urN linux-2.2.8-pre7/arch/ppc/mm/init.c linux/arch/ppc/mm/init.c
--- linux-2.2.8-pre7/arch/ppc/mm/init.c	Mon Dec  3 18:46:19 2001
+++ linux/arch/ppc/mm/init.c	Mon Dec  3 18:46:54 2001
@@ -1,5 +1,5 @@
 /*
- *  $Id: init.c,v 1.163 1999/04/09 06:37:13 cort Exp $
+ *  $Id: init.c,v 1.164 1999/05/05 17:33:55 cort Exp $
  *
  *  PowerPC version 
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
@@ -119,12 +119,19 @@
 PTE *Hash, *Hash_end;
 unsigned long Hash_size, Hash_mask;
 #ifndef CONFIG_8xx
+#ifdef CONFIG_PPC64
+unsigned long long _SDR1;
+#else
 unsigned long _SDR1;
+#endif
 static void hash_init(void);
 union ubat {			/* BAT register values to be loaded */
 	BAT	bat;
-	P601_BAT bat_601;
+#ifdef CONFIG_PPC64
+	u64	word[2];
+#else
 	u32	word[2];
+#endif	
 } BATS[4][2];			/* 4 pairs of IBAT, DBAT */
 
 struct batrange {		/* stores address ranges mapped by BATs */
@@ -146,7 +153,6 @@
 /* optimization for 603 to load the tlb directly from the linux table -- Cort */
 #define NO_RELOAD_HTAB 1 /* change in kernel/head.S too! */
 
-
 void __bad_pte(pmd_t *pmd)
 {
 	printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
@@ -354,7 +360,6 @@
 		return NULL;
 
 #ifndef CONFIG_8xx
-#if 0	
 	/*
 	 * Is it already mapped?  Perhaps overlapped by a previous
 	 * BAT mapping.  If the whole area is mapped then we're done,
@@ -368,7 +373,6 @@
 	 */
 	if ( (v = p_mapped_by_bats(addr)) /*&& p_mapped_by_bats(addr+(size-1))*/ )
 		goto out;
-#endif	
 #endif /* CONFIG_8xx */
 	
 	if (mem_init_done) {
@@ -397,7 +401,8 @@
 	
 	for (i = 0; i < size; i += PAGE_SIZE)
 		map_page(&init_task, v+i, p+i, flags);
-	return (void *) (v + (addr & ~PAGE_MASK));
+out:	
+	return (void *) (v + (p & ~PAGE_MASK));
 }
 
 void iounmap(void *addr)
@@ -1500,10 +1505,18 @@
 	 * up to a maximum of 2MB.
 	 */
 	ramsize = (ulong)end_of_DRAM - KERNELBASE;
+#ifdef CONFIG_PPC64	
+	Hash_mask = 0;
+	for (h = 256<<10; h < ramsize / 256 && h < 4<<20; h *= 2, Hash_mask++)
+		;
+	Hash_size = h;
+	Hash_mask << 10;  /* so setting _SDR1 works the same -- Cort */
+#else
 	for (h = 64<<10; h < ramsize / 256 && h < 2<<20; h *= 2)
 		;
 	Hash_size = h;
 	Hash_mask = (h >> 6) - 1;
+#endif	
 	
 #ifdef NO_RELOAD_HTAB
 	/* shrink the htab since we don't use it on 603's -- Cort */
diff -urN linux-2.2.8-pre7/arch/sparc/kernel/entry.S linux/arch/sparc/kernel/entry.S
--- linux-2.2.8-pre7/arch/sparc/kernel/entry.S	Wed Apr 28 08:47:39 1999
+++ linux/arch/sparc/kernel/entry.S	Mon Dec  3 18:46:54 2001
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.158 1999/04/27 14:35:07 davem Exp $
+/* $Id: entry.S,v 1.159 1999/05/08 03:00:03 davem Exp $
  * arch/sparc/kernel/entry.S:  Sparc trap low-level entry points.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -1476,7 +1476,7 @@
 	wr	%l0, PSR_ET, %psr
 	WRITE_PAUSE
 	call	schedule_tail
-	 nop
+	 mov	%g3, %o0
 	b	C_LABEL(ret_sys_call)
 	 ld	[%sp + REGWIN_SZ + PT_I0], %o0
 #endif
diff -urN linux-2.2.8-pre7/arch/sparc/kernel/process.c linux/arch/sparc/kernel/process.c
--- linux-2.2.8-pre7/arch/sparc/kernel/process.c	Thu Apr 22 19:24:51 1999
+++ linux/arch/sparc/kernel/process.c	Mon Dec  3 18:46:54 2001
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.136 1999/04/16 01:20:33 anton Exp $
+/*  $Id: process.c,v 1.137 1999/05/08 03:00:10 davem Exp $
  *  linux/arch/sparc/kernel/process.c
  *
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -63,6 +63,8 @@
 	/* endless idle loop with no priority at all */
 	current->priority = 0;
 	current->counter = -100;
+	init_idle();
+
 	for (;;) {
 		if (ARCH_SUN4C_SUN4) {
 			static int count = HZ;
@@ -111,6 +113,8 @@
 	/* endless idle loop with no priority at all */
 	current->priority = 0;
 	current->counter = -100;
+	init_idle();
+
 	while(1) {
 		if(current->need_resched) {
 			schedule();
diff -urN linux-2.2.8-pre7/arch/sparc/kernel/sun4d_smp.c linux/arch/sparc/kernel/sun4d_smp.c
--- linux-2.2.8-pre7/arch/sparc/kernel/sun4d_smp.c	Mon Nov 16 10:37:28 1998
+++ linux/arch/sparc/kernel/sun4d_smp.c	Mon Dec  3 18:46:54 2001
@@ -190,6 +190,7 @@
 	current->processor = boot_cpu_id;
 	smp_store_cpu_info(boot_cpu_id);
 	smp_setup_percpu_timer();
+	init_idle();
 	local_flush_cache_all();
 	if(linux_num_cpus == 1)
 		return;  /* Not an MP box. */
@@ -211,6 +212,7 @@
 			p = task[++cpucount];
 
 			p->processor = i;
+			p->has_cpu = 1; /* we schedule the first task manually */
 			current_set[i] = p;
 			
 			for (no = 0; no < linux_num_cpus; no++)
diff -urN linux-2.2.8-pre7/arch/sparc/kernel/sun4m_smp.c linux/arch/sparc/kernel/sun4m_smp.c
--- linux-2.2.8-pre7/arch/sparc/kernel/sun4m_smp.c	Thu Apr 22 19:24:51 1999
+++ linux/arch/sparc/kernel/sun4m_smp.c	Mon Dec  3 18:46:54 2001
@@ -161,6 +161,7 @@
 	smp_store_cpu_info(boot_cpu_id);
 	set_irq_udt(mid_xlate[boot_cpu_id]);
 	smp_setup_percpu_timer();
+	init_idle();
 	local_flush_cache_all();
 	if(linux_num_cpus == 1)
 		return;  /* Not an MP box. */
@@ -180,6 +181,7 @@
 			p = task[++cpucount];
 
 			p->processor = i;
+			p->has_cpu = 1; /* we schedule the first task manually */
 			current_set[i] = p;
 
 			/* See trampoline.S for details... */
diff -urN linux-2.2.8-pre7/arch/sparc/kernel/sys_sparc.c linux/arch/sparc/kernel/sys_sparc.c
--- linux-2.2.8-pre7/arch/sparc/kernel/sys_sparc.c	Sun Mar 21 07:23:38 1999
+++ linux/arch/sparc/kernel/sys_sparc.c	Mon Dec  3 18:46:54 2001
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc.c,v 1.51 1999/03/20 22:02:00 davem Exp $
+/* $Id: sys_sparc.c,v 1.52 1999/05/08 08:09:48 anton Exp $
  * linux/arch/sparc/kernel/sys_sparc.c
  *
  * This file contains various random system calls that
@@ -231,7 +231,7 @@
 	
 	if (count++ > 5) return -ENOSYS;
 	lock_kernel();
-	printk ("Unimplemented SPARC system call %d\n",(int)regs->u_regs[1]);
+	printk ("%s[%d]: Unimplemented SPARC system call %d\n", current->comm, current->pid, (int)regs->u_regs[1]);
 #ifdef DEBUG_UNIMP_SYSCALL	
 	show_regs (regs);
 #endif
diff -urN linux-2.2.8-pre7/arch/sparc/mm/iommu.c linux/arch/sparc/mm/iommu.c
--- linux-2.2.8-pre7/arch/sparc/mm/iommu.c	Fri May  8 00:11:28 1998
+++ linux/arch/sparc/mm/iommu.c	Mon Dec  3 18:46:54 2001
@@ -1,4 +1,4 @@
-/* $Id: iommu.c,v 1.9 1998/04/15 14:58:37 jj Exp $
+/* $Id: iommu.c,v 1.10 1999/05/07 17:03:34 jj Exp $
  * iommu.c:  IOMMU specific routines for memory management.
  *
  * Copyright (C) 1995 David S. Miller  (davem@caip.rutgers.edu)
@@ -51,8 +51,7 @@
 	unsigned long tmp;
 	struct iommu_struct *iommu;
 	struct linux_prom_registers iommu_promregs[PROMREG_MAX];
-	int i, j, k, l, m;
-	struct iommu_alloc { unsigned long addr; int next; } *ia;
+	int i;
 
 	iommu = kmalloc(sizeof(struct iommu_struct), GFP_ATOMIC);
 	prom_getproperty(iommund, "reg", (void *) iommu_promregs,
@@ -97,62 +96,18 @@
 	ptsize = (ptsize >> PAGE_SHIFT) * sizeof(iopte_t);
 
 	/* Stupid alignment constraints give me a headache. 
-	   We want to get very large aligned memory area, larger than
-	   maximum what get_free_pages gives us (128K): we need
-	   256K or 512K or 1M or 2M aligned to its size. */
-	ia = (struct iommu_alloc *) kmalloc (sizeof(struct iommu_alloc) * 128, GFP_ATOMIC);
-	for (i = 0; i < 128; i++) {
-		ia[i].addr = 0;
-		ia[i].next = -1;
-	}
-	k = 0;
-	for (i = 0; i < 128; i++) {
-		ia[i].addr = __get_free_pages(GFP_DMA, 5);
-		if (ia[i].addr <= ia[k].addr) {
-			if (i) {
-				ia[i].next = k;
-				k = i;
-			}			
-		} else {
-			for (m = k, l = ia[k].next; l != -1; m = l, l = ia[l].next)
-				if (ia[i].addr <= ia[l].addr) {
-					ia[i].next = l;
-					ia[m].next = i;
-				}
-			if (l == -1)
-				ia[m].next = i;
-		}
-		for (m = -1, j = 0, l = k; l != -1; l = ia[l].next) {
-			if (!(ia[l].addr & (ptsize - 1))) {
-				tmp = ia[l].addr;
-				m = l;
-				j = 128 * 1024;
-			} else if (m != -1) {
-				if (ia[l].addr != tmp + j)
-					m = -1;
-				else {
-					j += 128 * 1024;
-					if (j == ptsize) {
-						break;
-					}
-				}
-			}
-		}
-		if (l != -1)
+	   We need 256K or 512K or 1M or 2M area aligned to
+           its size and current gfp will fortunately give
+           it to us. */
+	for (i = 6; i < 9; i++)
+		if ((1 << (i + PAGE_SHIFT)) == ptsize)
 			break;
-	}
-	if (i == 128) {
+        tmp = __get_free_pages(GFP_DMA, i);
+	if (!tmp) {
 		prom_printf("Could not allocate iopte of size 0x%08x\n", ptsize);
 		prom_halt();
 	}
-	for (l = m, j = 0; j < ptsize; j += 128 * 1024, l = ia[l].next)
-		ia[l].addr = 0;
-	for (l = k; l != -1; l = ia[l].next)
-		if (ia[l].addr)
-			free_pages(ia[l].addr, 5);
-	kfree (ia);
 	iommu->lowest = iommu->page_table = (iopte_t *)tmp;
-	
 
 	/* Initialize new table. */
 	flush_cache_all();
diff -urN linux-2.2.8-pre7/arch/sparc64/kernel/cpu.c linux/arch/sparc64/kernel/cpu.c
--- linux-2.2.8-pre7/arch/sparc64/kernel/cpu.c	Wed Apr 28 08:47:39 1999
+++ linux/arch/sparc64/kernel/cpu.c	Mon Dec  3 18:46:54 2001
@@ -65,7 +65,7 @@
 	long ver, fpu_vers;
 	long fprs;
 	
-	cpuid = smp_processor_id();
+	cpuid = hard_smp_processor_id();
 
 	fprs = fprs_read ();
 	fprs_write (FPRS_FEF);
diff -urN linux-2.2.8-pre7/arch/sparc64/kernel/devices.c linux/arch/sparc64/kernel/devices.c
--- linux-2.2.8-pre7/arch/sparc64/kernel/devices.c	Mon Mar 15 16:10:43 1999
+++ linux/arch/sparc64/kernel/devices.c	Mon Dec  3 18:46:54 2001
@@ -73,6 +73,9 @@
 	
 	prom_cpu_nodes[0] = prom_node_cpu;
 
+	mem_start = central_probe(mem_start);
+
 	cpu_probe();
-	return central_probe(mem_start);
+
+	return mem_start;
 }
diff -urN linux-2.2.8-pre7/arch/sparc64/kernel/ebus.c linux/arch/sparc64/kernel/ebus.c
--- linux-2.2.8-pre7/arch/sparc64/kernel/ebus.c	Wed Mar 10 16:53:37 1999
+++ linux/arch/sparc64/kernel/ebus.c	Mon Dec  3 18:46:54 2001
@@ -1,4 +1,4 @@
-/* $Id: ebus.c,v 1.35 1999/01/26 14:34:11 jj Exp $
+/* $Id: ebus.c,v 1.36 1999/05/04 03:21:42 davem Exp $
  * ebus.c: PCI to EBus bridge device.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -35,9 +35,6 @@
 #ifdef CONFIG_SUN_OPENPROMIO
 extern int openprom_init(void);
 #endif
-#ifdef CONFIG_SPARCAUDIO
-extern int sparcaudio_init(void);
-#endif
 #ifdef CONFIG_SUN_AUXIO
 extern void auxio_probe(void);
 #endif
@@ -398,9 +395,6 @@
 
 #ifdef CONFIG_SUN_OPENPROMIO
 	openprom_init();
-#endif
-#ifdef CONFIG_SPARCAUDIO
-	sparcaudio_init();
 #endif
 #ifdef CONFIG_SUN_BPP
 	bpp_init();
diff -urN linux-2.2.8-pre7/arch/sparc64/kernel/entry.S linux/arch/sparc64/kernel/entry.S
--- linux-2.2.8-pre7/arch/sparc64/kernel/entry.S	Thu Apr 22 19:24:51 1999
+++ linux/arch/sparc64/kernel/entry.S	Mon Dec  3 18:46:54 2001
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.102 1999/03/29 12:38:09 jj Exp $
+/* $Id: entry.S,v 1.103 1999/05/08 03:00:21 davem Exp $
  * arch/sparc64/kernel/entry.S:  Sparc64 trap low-level entry points.
  *
  * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -766,6 +766,7 @@
 		 */
 #ifdef __SMP__
 		andn		%o7, 0x100, %l0
+		mov		%g5, %o0	/* 'prev' */
 		call		schedule_tail
 		 sth		%l0, [%g6 + AOFF_task_tss + AOFF_thread_flags]
 #else
diff -urN linux-2.2.8-pre7/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c
--- linux-2.2.8-pre7/arch/sparc64/kernel/ioctl32.c	Mon Dec  3 18:46:19 2001
+++ linux/arch/sparc64/kernel/ioctl32.c	Mon Dec  3 18:46:54 2001
@@ -1,4 +1,4 @@
-/* $Id: ioctl32.c,v 1.61 1999/04/28 19:44:31 davem Exp $
+/* $Id: ioctl32.c,v 1.62 1999/05/01 09:17:44 davem Exp $
  * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
  *
  * Copyright (C) 1997  Jakub Jelinek  (jj@sunsite.mff.cuni.cz)
@@ -36,6 +36,7 @@
 #include <linux/vt_kern.h>
 #include <linux/fb.h>
 #include <linux/ext2_fs.h>
+#include <linux/videodev.h>
 
 #include <scsi/scsi.h>
 /* Ugly hack. */
@@ -118,6 +119,247 @@
 	return sys_ioctl(fd, cmd, arg);
 }
  
+struct video_tuner32 {
+	s32 tuner;
+	u8 name[32];
+	u32 rangelow, rangehigh;
+	u32 flags;
+	u16 mode, signal;
+};
+
+static int get_video_tuner32(struct video_tuner *kp, struct video_tuner32 *up)
+{
+	int i;
+
+	if(get_user(kp->tuner, &up->tuner))
+		return -EFAULT;
+	for(i = 0; i < 32; i++)
+		__get_user(kp->name[i], &up->name[i]);
+	__get_user(kp->rangelow, &up->rangelow);
+	__get_user(kp->rangehigh, &up->rangehigh);
+	__get_user(kp->flags, &up->flags);
+	__get_user(kp->mode, &up->mode);
+	__get_user(kp->signal, &up->signal);
+	return 0;
+}
+
+static int put_video_tuner32(struct video_tuner *kp, struct video_tuner32 *up)
+{
+	int i;
+
+	if(put_user(kp->tuner, &up->tuner))
+		return -EFAULT;
+	for(i = 0; i < 32; i++)
+		__put_user(kp->name[i], &up->name[i]);
+	__put_user(kp->rangelow, &up->rangelow);
+	__put_user(kp->rangehigh, &up->rangehigh);
+	__put_user(kp->flags, &up->flags);
+	__put_user(kp->mode, &up->mode);
+	__put_user(kp->signal, &up->signal);
+	return 0;
+}
+
+struct video_buffer32 {
+	/* void * */ u32 base;
+	s32 height, width, depth, bytesperline;
+};
+
+static int get_video_buffer32(struct video_buffer *kp, struct video_buffer32 *up)
+{
+	u32 tmp;
+
+	if(get_user(tmp, &up->base))
+		return -EFAULT;
+	kp->base = (void *) ((unsigned long)tmp);
+	__get_user(kp->height, &up->height);
+	__get_user(kp->width, &up->width);
+	__get_user(kp->depth, &up->depth);
+	__get_user(kp->bytesperline, &up->bytesperline);
+	return 0;
+}
+
+static int put_video_buffer32(struct video_buffer *kp, struct video_buffer32 *up)
+{
+	u32 tmp = (u32)((unsigned long)kp->base);
+
+	if(put_user(tmp, &up->base))
+		return -EFAULT;
+	__put_user(kp->height, &up->height);
+	__put_user(kp->width, &up->width);
+	__put_user(kp->depth, &up->depth);
+	__put_user(kp->bytesperline, &up->bytesperline);
+	return 0;
+}
+
+struct video_clip32 {
+	s32 x, y, width, height;
+	/* struct video_clip32 * */ u32 next;
+};
+
+struct video_window32 {
+	u32 x, y, width, height, chromakey, flags;
+	/* struct video_clip32 * */ u32 clips;
+	s32 clipcount;
+};
+
+static void free_kvideo_clips(struct video_window *kp)
+{
+	struct video_clip *cp;
+
+	cp = kp->clips;
+	if(cp != NULL)
+		kfree(cp);
+}
+
+static int get_video_window32(struct video_window *kp, struct video_window32 *up)
+{
+	struct video_clip32 *ucp;
+	struct video_clip *kcp;
+	int nclips, err, i;
+	u32 tmp;
+
+	if(get_user(kp->x, &up->x))
+		return -EFAULT;
+	__get_user(kp->y, &up->y);
+	__get_user(kp->width, &up->width);
+	__get_user(kp->height, &up->height);
+	__get_user(kp->chromakey, &up->chromakey);
+	__get_user(kp->flags, &up->flags);
+	__get_user(kp->clipcount, &up->clipcount);
+	__get_user(tmp, &up->clips);
+	ucp = (struct video_clip32 *)A(tmp);
+	kp->clips = NULL;
+
+	nclips = kp->clipcount;
+	if(nclips == 0)
+		return 0;
+
+	if(ucp == 0)
+		return -EINVAL;
+
+	/* Peculiar interface... */
+	if(nclips < 0)
+		nclips = VIDEO_CLIPMAP_SIZE;
+
+	kcp = kmalloc(nclips * sizeof(struct video_clip), GFP_KERNEL);
+	err = -ENOMEM;
+	if(kcp == NULL)
+		goto cleanup_and_err;
+
+	kp->clips = kcp;
+	for(i = 0; i < nclips; i++) {
+		__get_user(kcp[i].x, &ucp[i].x);
+		__get_user(kcp[i].y, &ucp[i].y);
+		__get_user(kcp[i].width, &ucp[i].width);
+		__get_user(kcp[i].height, &ucp[i].height);
+		kcp[nclips].next = NULL;
+	}
+
+	return 0;
+
+cleanup_and_err:
+	free_kvideo_clips(kp);
+	return err;
+}
+
+/* You get back everything except the clips... */
+static int put_video_window32(struct video_window *kp, struct video_window32 *up)
+{
+	if(put_user(kp->x, &up->x))
+		return -EFAULT;
+	__put_user(kp->y, &up->y);
+	__put_user(kp->width, &up->width);
+	__put_user(kp->height, &up->height);
+	__put_user(kp->chromakey, &up->chromakey);
+	__put_user(kp->flags, &up->flags);
+	__put_user(kp->clipcount, &up->clipcount);
+	return 0;
+}
+
+#define VIDIOCGTUNER32		_IOWR('v',4, struct video_tuner32)
+#define VIDIOCSTUNER32		_IOW('v',5, struct video_tuner32)
+#define VIDIOCGWIN32		_IOR('v',9, struct video_window32)
+#define VIDIOCSWIN32		_IOW('v',10, struct video_window32)
+#define VIDIOCGFBUF32		_IOR('v',11, struct video_buffer32)
+#define VIDIOCSFBUF32		_IOW('v',12, struct video_buffer32)
+#define VIDIOCGFREQ32		_IOR('v',14, u32)
+#define VIDIOCSFREQ32		_IOW('v',15, u32)
+
+static int do_video_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	union {
+		struct video_tuner vt;
+		struct video_buffer vb;
+		struct video_window vw;
+		unsigned long vx;
+	} karg;
+	mm_segment_t old_fs = get_fs();
+	void *up = (void *)arg;
+	int err = 0;
+
+	/* First, convert the command. */
+	switch(cmd) {
+	case VIDIOCGTUNER32: cmd = VIDIOCGTUNER; break;
+	case VIDIOCSTUNER32: cmd = VIDIOCSTUNER; break;
+	case VIDIOCGWIN32: cmd = VIDIOCGWIN; break;
+	case VIDIOCSWIN32: cmd = VIDIOCSWIN; break;
+	case VIDIOCGFBUF32: cmd = VIDIOCGFBUF; break;
+	case VIDIOCSFBUF32: cmd = VIDIOCSFBUF; break;
+	case VIDIOCGFREQ32: cmd = VIDIOCGFREQ; break;
+	case VIDIOCSFREQ32: cmd = VIDIOCSFREQ; break;
+	};
+
+	switch(cmd) {
+	case VIDIOCSTUNER:
+	case VIDIOCGTUNER:
+		err = get_video_tuner32(&karg.vt, up);
+		break;
+
+	case VIDIOCSWIN:
+		err = get_video_window32(&karg.vw, up);
+		break;
+
+	case VIDIOCSFBUF:
+		err = get_video_buffer32(&karg.vb, up);
+		break;
+
+	case VIDIOCSFREQ:
+		err = get_user(karg.vx, (u32 *)up);
+		break;
+	};
+	if(err)
+		goto out;
+
+	set_fs(KERNEL_DS);
+	err = sys_ioctl(fd, cmd, (unsigned long)&karg);
+	set_fs(old_fs);
+
+	if(cmd == VIDIOCSWIN)
+		free_kvideo_clips(&karg.vw);
+
+	if(err == 0) {
+		switch(cmd) {
+		case VIDIOCGTUNER:
+			err = put_video_tuner32(&karg.vt, up);
+			break;
+
+		case VIDIOCGWIN:
+			err = put_video_window32(&karg.vw, up);
+			break;
+
+		case VIDIOCGFBUF:
+			err = put_video_buffer32(&karg.vb, up);
+			break;
+
+		case VIDIOCGFREQ:
+			err = put_user(((u32)karg.vx), (u32 *)up);
+			break;
+		};
+	}
+out:
+	return err;
+}
+
 struct timeval32 {
 	int tv_sec;
 	int tv_usec;
@@ -1601,6 +1843,17 @@
 		error = do_ext2_ioctl(fd, cmd, arg);
 		goto out;
 		
+	case VIDIOCGTUNER32:
+	case VIDIOCSTUNER32:
+	case VIDIOCGWIN32:
+	case VIDIOCSWIN32:
+	case VIDIOCGFBUF32:
+	case VIDIOCSFBUF32:
+	case VIDIOCGFREQ32:
+	case VIDIOCSFREQ32:
+		error = do_video_ioctl(fd, cmd, arg);
+		goto out;
+
 	/* List here exlicitly which ioctl's are known to have
 	 * compatable types passed or none at all...
 	 */
@@ -1793,6 +2046,33 @@
 	/* Little v */
 	case VUIDSFORMAT:
 	case VUIDGFORMAT:
+
+	/* Little v, the video4linux ioctls */
+	case VIDIOCGCAP:
+	case VIDIOCGCHAN:
+	case VIDIOCSCHAN:
+	case VIDIOCGPICT:
+	case VIDIOCSPICT:
+	case VIDIOCCAPTURE:
+	case VIDIOCKEY:
+	case VIDIOCGAUDIO:
+	case VIDIOCSAUDIO:
+	case VIDIOCSYNC:
+	case VIDIOCMCAPTURE:
+	case VIDIOCGMBUF:
+	case VIDIOCGUNIT:
+	case VIDIOCGCAPTURE:
+	case VIDIOCSCAPTURE:
+
+	/* BTTV specific... */
+	case _IOW('v',  BASE_VIDIOCPRIVATE+0, char [256]):
+	case _IOR('v',  BASE_VIDIOCPRIVATE+1, char [256]):
+	case _IOR('v' , BASE_VIDIOCPRIVATE+2, unsigned int):
+	case _IOW('v' , BASE_VIDIOCPRIVATE+3, char [16]): /* struct bttv_pll_info */
+	case _IOR('v' , BASE_VIDIOCPRIVATE+4, int):
+	case _IOR('v' , BASE_VIDIOCPRIVATE+5, int):
+	case _IOR('v' , BASE_VIDIOCPRIVATE+6, int):
+	case _IOR('v' , BASE_VIDIOCPRIVATE+7, int):
 
 	/* Little p (/dev/rtc, /dev/envctrl, etc.) */
 	case RTCGET:
diff -urN linux-2.2.8-pre7/arch/sparc64/kernel/process.c linux/arch/sparc64/kernel/process.c
--- linux-2.2.8-pre7/arch/sparc64/kernel/process.c	Sun Mar 21 18:37:56 1999
+++ linux/arch/sparc64/kernel/process.c	Mon Dec  3 18:46:54 2001
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.90 1999/03/22 02:12:16 davem Exp $
+/*  $Id: process.c,v 1.92 1999/05/08 23:04:48 davem Exp $
  *  arch/sparc64/kernel/process.c
  *
  *  Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -54,6 +54,8 @@
 	/* endless idle loop with no priority at all */
 	current->priority = 0;
 	current->counter = -100;
+	init_idle();
+
 	for (;;) {
 		/* If current->need_resched is zero we should really
 		 * setup for a system wakup event and execute a shutdown
@@ -79,6 +81,8 @@
 {
 	current->priority = 0;
 	current->counter = -100;
+	init_idle();
+
 	while(1) {
 		if (current->need_resched != 0) {
 			unidle_me();
diff -urN linux-2.2.8-pre7/arch/sparc64/kernel/smp.c linux/arch/sparc64/kernel/smp.c
--- linux-2.2.8-pre7/arch/sparc64/kernel/smp.c	Thu Apr 22 19:24:51 1999
+++ linux/arch/sparc64/kernel/smp.c	Mon Dec  3 18:46:54 2001
@@ -97,7 +97,7 @@
 	cpu_data[id].pte_cache			= NULL;
 	cpu_data[id].pgdcache_size		= 0;
 	cpu_data[id].pgd_cache			= NULL;
-	cpu_data[id].idle_volume		= 0;
+	cpu_data[id].idle_volume		= 1;
 
 	for(i = 0; i < 16; i++)
 		cpu_data[id].irq_worklists[i] = 0;
@@ -196,6 +196,7 @@
 	__sti();
 	smp_store_cpu_info(boot_cpu_id);
 	smp_tune_scheduling();
+	init_idle();
 
 	if(linux_num_cpus == 1)
 		return;
@@ -217,6 +218,7 @@
 			kernel_thread(start_secondary, NULL, CLONE_PID);
 			p = task[++cpucount];
 			p->processor = i;
+			p->has_cpu = 1; /* we schedule the first task manually */
 			callin_flag = 0;
 			for (no = 0; no < linux_num_cpus; no++)
 				if (linux_cpus[no].mid == i)
@@ -460,8 +462,6 @@
 			mm->cpu_vm_mask = (1UL << smp_processor_id());
 		goto local_flush_and_out;
 	} else {
-		spin_lock(&scheduler_lock);
-
 		/* Try to handle two special cases to avoid cross calls
 		 * in common scenerios where we are swapping process
 		 * pages out.
@@ -471,16 +471,12 @@
 			/* A dead context cannot ever become "alive" until
 			 * a task switch is done to it.
 			 */
-			spin_unlock(&scheduler_lock);
 			return; /* It's dead, nothing to do. */
 		}
 		if(mm->cpu_vm_mask == (1UL << smp_processor_id())) {
-			spin_unlock(&scheduler_lock);
 			__flush_tlb_page(ctx, page, SECONDARY_CONTEXT);
 			return; /* Only local flush is necessary. */
 		}
-
-		spin_unlock(&scheduler_lock);
 	}
 	smp_cross_call(&xcall_flush_tlb_page, ctx, page, 0);
 
diff -urN linux-2.2.8-pre7/arch/sparc64/kernel/sparc64_ksyms.c linux/arch/sparc64/kernel/sparc64_ksyms.c
--- linux-2.2.8-pre7/arch/sparc64/kernel/sparc64_ksyms.c	Mon Mar 15 16:10:43 1999
+++ linux/arch/sparc64/kernel/sparc64_ksyms.c	Mon Dec  3 18:46:54 2001
@@ -1,4 +1,4 @@
-/* $Id: sparc64_ksyms.c,v 1.57 1999/03/14 20:51:28 davem Exp $
+/* $Id: sparc64_ksyms.c,v 1.58 1999/05/08 03:00:31 davem Exp $
  * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -90,7 +90,6 @@
 extern void dump_thread(struct pt_regs *, struct user *);
 
 #ifdef __SMP__
-extern spinlock_t scheduler_lock;
 extern spinlock_t kernel_flag;
 extern int smp_num_cpus;
 #ifdef SPIN_LOCK_DEBUG
@@ -120,7 +119,6 @@
 /* used by various drivers */
 #ifdef __SMP__
 /* Kernel wide locking */
-EXPORT_SYMBOL(scheduler_lock);
 EXPORT_SYMBOL(kernel_flag);
 
 /* Software-IRQ BH locking */
diff -urN linux-2.2.8-pre7/arch/sparc64/mm/init.c linux/arch/sparc64/mm/init.c
--- linux-2.2.8-pre7/arch/sparc64/mm/init.c	Thu Apr 22 19:24:51 1999
+++ linux/arch/sparc64/mm/init.c	Mon Dec  3 18:46:54 2001
@@ -1,4 +1,4 @@
-/*  $Id: init.c,v 1.126 1999/04/09 16:16:41 jj Exp $
+/*  $Id: init.c,v 1.127 1999/05/08 03:00:38 davem Exp $
  *  arch/sparc64/mm/init.c
  *
  *  Copyright (C) 1996-1999 David S. Miller (davem@caip.rutgers.edu)
@@ -949,8 +949,7 @@
 #define CTX_BMAP_SLOTS (1UL << (CTX_VERSION_SHIFT - 6))
 unsigned long mmu_context_bmap[CTX_BMAP_SLOTS];
 
-/* We are always protected by scheduler_lock under SMP.
- * Caller does TLB context flushing on local CPU if necessary.
+/* Caller does TLB context flushing on local CPU if necessary.
  *
  * We must be careful about boundary cases so that we never
  * let the user have CTX 0 (nucleus) or we ever use a CTX
diff -urN linux-2.2.8-pre7/drivers/block/ide-cd.h linux/drivers/block/ide-cd.h
--- linux-2.2.8-pre7/drivers/block/ide-cd.h	Tue Apr 27 09:56:22 1999
+++ linux/drivers/block/ide-cd.h	Mon Dec  3 18:46:54 2001
@@ -363,7 +363,7 @@
 #endif
 
 #if defined(__BIG_ENDIAN_BITFIELD)
-	__u8 reserved4           : 4;
+	__u8 reserved4           : 1;
 	/* Drive can read multisession discs. */
 	__u8 multisession        : 1;
 	/* Drive can read mode 2, form 2 data. */
diff -urN linux-2.2.8-pre7/drivers/misc/Makefile linux/drivers/misc/Makefile
--- linux-2.2.8-pre7/drivers/misc/Makefile	Thu Jan  7 08:46:59 1999
+++ linux/drivers/misc/Makefile	Mon Dec  3 18:46:55 2001
@@ -34,6 +34,27 @@
       M_OBJS += parport_ax.o
     endif
   endif
+  ifeq ($(CONFIG_PARPORT_AMIGA),y)
+    LX_OBJS += parport_amiga.o
+  else
+    ifeq ($(CONFIG_PARPORT_AMIGA),m)
+      M_OBJS += parport_amiga.o
+    endif
+  endif
+  ifeq ($(CONFIG_PARPORT_MFC3),y)
+    LX_OBJS += parport_mfc3.o
+  else
+    ifeq ($(CONFIG_PARPORT_MFC3),m)
+      M_OBJS += parport_mfc3.o
+    endif
+  endif
+  ifeq ($(CONFIG_PARPORT_ATARI),y)
+    LX_OBJS += parport_atari.o
+  else
+    ifeq ($(CONFIG_PARPORT_ATARI),m)
+      M_OBJS += parport_atari.o
+    endif
+  endif
   LX_OBJS += parport_init.o
 else
   ifeq ($(CONFIG_PARPORT),m)
@@ -49,6 +70,15 @@
   endif
   ifeq ($(CONFIG_PARPORT_AX),m)
     M_OBJS += parport_ax.o
+  endif
+  ifeq ($(CONFIG_PARPORT_AMIGA),m)
+    M_OBJS += parport_amiga.o
+  endif
+  ifeq ($(CONFIG_PARPORT_MFC3),m)
+    M_OBJS += parport_mfc3.o
+  endif
+  ifeq ($(CONFIG_PARPORT_ATARI),m)
+    M_OBJS += parport_atari.o
   endif
 endif
 
diff -urN linux-2.2.8-pre7/drivers/misc/multiface.h linux/drivers/misc/multiface.h
--- linux-2.2.8-pre7/drivers/misc/multiface.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/misc/multiface.h	Mon Dec  3 18:46:55 2001
@@ -0,0 +1,20 @@
+#ifndef _MULTIFACE_H_
+#define _MULTIFACE_H_
+
+/*
+ * Defines for SerialMaster, Multiface Card II and Multiface Card III
+ * The addresses given below are offsets to the board base address
+ * 
+ * 6.11.95 Joerg Dorchain (dorchain@mpi-sb.mpg.de)
+ *
+ */
+
+#define PIA_REG_PADWIDTH 255
+
+#define DUARTBASE 0x0000
+#define PITBASE   0x0100
+#define ROMBASE   0x0200
+#define PIABASE   0x4000
+
+#endif
+
diff -urN linux-2.2.8-pre7/drivers/misc/parport_amiga.c linux/drivers/misc/parport_amiga.c
--- linux-2.2.8-pre7/drivers/misc/parport_amiga.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/misc/parport_amiga.c	Mon Dec  3 18:46:55 2001
@@ -0,0 +1,322 @@
+/* Low-level parallel port routines for the Amiga buildin port
+ *
+ * Author: Joerg Dorchain <dorchain@wirbel.com>
+ *
+ * This is a complete rewrite of the code, but based heaviy upon the old
+ * lp_intern. code.
+ *
+ * The built-in Amiga parallel port provides one port at a fixed address
+ * with 8 bisdirecttional data lines (D0 - D7) and 3 bidirectional status
+ * lines (BUSY, POUT, SEL), 1 output control line /STROBE (raised automatically in
+ * hardware when the data register is accessed), and 1 input control line
+ * /ACK, able to cause an interrupt, but both not directly settable by
+ * software.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/parport.h>
+#include <asm/setup.h>
+#include <asm/amigahw.h>
+#include <asm/irq.h>
+#include <asm/amigaints.h>
+
+#undef DEBUG
+#ifdef DEBUG
+#define DPRINTK printk
+#else
+static inline int DPRINTK() {return 0;}
+#endif
+
+static struct parport *this_port = NULL;
+
+static void amiga_write_data(struct parport *p, unsigned char data)
+{
+DPRINTK("write_data %c\n",data);
+	/* Triggers also /STROBE. This behavior cannot be changed */
+	ciaa.prb = data;
+}
+
+static unsigned char amiga_read_data(struct parport *p)
+{
+	/* Triggers also /STROBE. This behavior cannot be changed */
+	return ciaa.prb;
+}
+
+#if 0
+static unsigned char control_pc_to_amiga(unsigned char control)
+{
+	unsigned char ret = 0;
+
+	if (control & PARPORT_CONTROL_DIRECTION) /* XXX: What is this? */
+		;
+	if (control & PARPORT_CONTROL_INTEN) /* XXX: What is INTEN? */
+		;
+	if (control & PARPORT_CONTROL_SELECT) /* XXX: What is SELECP? */
+		;
+	if (control & PARPORT_CONTROL_INIT) /* INITP */
+		/* reset connected to cpu reset pin */;
+	if (control & PARPORT_CONTROL_AUTOFD) /* AUTOLF */
+		/* Not connected */;
+	if (control & PARPORT_CONTROL_STROBE) /* Strobe */
+		/* Handled only directly by hardware */;
+	return ret;
+}
+#endif
+
+static unsigned char control_amiga_to_pc(unsigned char control)
+{
+	return PARPORT_CONTROL_INTEN | PARPORT_CONTROL_SELECT |
+	      PARPORT_CONTROL_AUTOFD | PARPORT_CONTROL_STROBE;
+	/* fake value: interrupt enable, select in, no reset,
+	no autolf, no strobe - seems to be closest the wiring diagram */
+}
+
+static void amiga_write_control(struct parport *p, unsigned char control)
+{
+DPRINTK("write_control %02x\n",control);
+	/* No implementation possible */
+}
+	
+static unsigned char amiga_read_control( struct parport *p)
+{
+DPRINTK("read_control \n");
+	return control_amiga_to_pc(0);
+}
+
+static unsigned char amiga_frob_control( struct parport *p, unsigned char mask, unsigned char val)
+{
+	unsigned char old;
+
+DPRINTK("frob_control mask %02x, value %02x\n",mask,val);
+	old = amiga_read_control(p);
+	amiga_write_control(p, (old & ~mask) ^ val);
+	return old;
+}
+
+
+static unsigned char status_pc_to_amiga(unsigned char status)
+{
+	unsigned char ret = 1;
+
+	if (status & PARPORT_STATUS_BUSY) /* Busy */
+		ret &= ~1;
+	if (status & PARPORT_STATUS_ACK) /* Ack */
+		/* handled in hardware */;
+	if (status & PARPORT_STATUS_PAPEROUT) /* PaperOut */
+		ret |= 2;
+	if (status & PARPORT_STATUS_SELECT) /* select */
+		ret |= 4;
+	if (status & PARPORT_STATUS_ERROR) /* error */
+		/* not connected */;
+	return ret;
+}
+
+static unsigned char status_amiga_to_pc(unsigned char status)
+{
+	unsigned char ret = PARPORT_STATUS_BUSY | PARPORT_STATUS_ACK | PARPORT_STATUS_ERROR;
+
+	if (status & 1) /* Busy */
+		ret &= ~PARPORT_STATUS_BUSY;
+	if (status & 2) /* PaperOut */
+		ret |= PARPORT_STATUS_PAPEROUT;
+	if (status & 4) /* Selected */
+		ret |= PARPORT_STATUS_SELECT;
+	/* the rest is not connected or handled autonomously in hardware */
+
+	return ret;
+}
+
+static void amiga_write_status( struct parport *p, unsigned char status)
+{
+DPRINTK("write_status %02x\n",status);
+	ciab.pra |= (ciab.pra & 0xf8) | status_pc_to_amiga(status);
+}
+
+static unsigned char amiga_read_status(struct parport *p)
+{
+	unsigned char status;
+
+	status = status_amiga_to_pc(ciab.pra & 7);
+DPRINTK("read_status %02x\n", status);
+	return status;
+}
+
+static void amiga_change_mode( struct parport *p, int m)
+{
+	/* XXX: This port only has one mode, and I am
+	not sure about the corresponding PC-style mode*/
+}
+
+/* as this ports irq handling is already done, we use a generic funktion */
+static void amiga_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	parport_generic_irq(irq, (struct parport *) dev_id, regs);
+}
+
+
+static void amiga_release_resources(struct parport *p)
+{
+DPRINTK("realease_resources\n");
+	if (p->irq != PARPORT_IRQ_NONE)
+		free_irq(IRQ_AMIGA_CIAA_FLG, p);
+}
+
+static int amiga_claim_resources(struct parport *p)
+{
+DPRINTK("claim_resources\n");
+	return request_irq(IRQ_AMIGA_CIAA_FLG, amiga_interrupt, 0, p->name, p);
+}
+
+static void amiga_init_state(struct parport_state *s)
+{
+	s->u.amiga.data = 0;
+	s->u.amiga.datadir = 255;
+	s->u.amiga.status = 0;
+	s->u.amiga.statusdir = 0;
+}
+
+static void amiga_save_state(struct parport *p, struct parport_state *s)
+{
+	s->u.amiga.data = ciaa.prb;
+	s->u.amiga.datadir = ciaa.ddrb;
+	s->u.amiga.status = ciab.pra & 7;
+	s->u.amiga.statusdir = ciab.ddra & 7;
+}
+
+static void amiga_restore_state(struct parport *p, struct parport_state *s)
+{
+	ciaa.prb = s->u.amiga.data;
+	ciaa.ddrb = s->u.amiga.datadir;
+	ciab.pra |= (ciab.pra & 0xf8) | s->u.amiga.status;
+	ciab.ddra |= (ciab.ddra & 0xf8) | s->u.amiga.statusdir;
+}
+
+static void amiga_enable_irq(struct parport *p)
+{
+	enable_irq(IRQ_AMIGA_CIAA_FLG);
+}
+
+static void amiga_disable_irq(struct parport *p)
+{
+	disable_irq(IRQ_AMIGA_CIAA_FLG);
+}
+
+static void amiga_inc_use_count(void)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void amiga_dec_use_count(void)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+static void amiga_fill_inode(struct inode *inode, int fill)
+{
+#ifdef MODULE
+	if (fill)
+		MOD_INC_USE_COUNT;
+	else
+		MOD_DEC_USE_COUNT;
+#endif
+}
+
+static struct parport_operations pp_amiga_ops = {
+	amiga_write_data,
+	amiga_read_data,
+
+	amiga_write_control,
+	amiga_read_control,
+	amiga_frob_control,
+
+	NULL, /* write_econtrol */
+	NULL, /* read_econtrol */
+	NULL, /* frob_econtrol */
+
+	amiga_write_status,
+	amiga_read_status,
+
+	NULL, /* write fifo */
+	NULL, /* read fifo */
+
+	amiga_change_mode,
+
+
+	amiga_release_resources,
+	amiga_claim_resources,
+
+
+	NULL, /* epp_write_data */
+	NULL, /* epp_read_data */
+	NULL, /* epp_write_addr */
+	NULL, /* epp_read_addr */
+	NULL, /* epp_check_timeout */
+
+	NULL, /* epp_write_block */
+	NULL, /* epp_read_block */
+
+	NULL, /* ecp_write_block */
+	NULL, /* ecp_read_block */
+
+	amiga_init_state,
+	amiga_save_state,
+	amiga_restore_state,
+
+	amiga_enable_irq,
+	amiga_disable_irq,
+	amiga_interrupt, 
+
+	amiga_inc_use_count,
+	amiga_dec_use_count,
+	amiga_fill_inode
+};
+
+/* ----------- Initialisation code --------------------------------- */
+
+__initfunc(int parport_amiga_init(void))
+{
+	struct parport *p;
+
+	if (MACH_IS_AMIGA && AMIGAHW_PRESENT(AMI_PARALLEL)) {
+		ciaa.ddrb = 0xff;
+		ciab.ddra &= 0xf8;
+		if (!(p = parport_register_port((unsigned long)&ciaa.prb,
+					IRQ_AMIGA_CIAA_FLG, PARPORT_DMA_NONE,
+					&pp_amiga_ops)))
+			return 0;
+		this_port = p;
+		printk(KERN_INFO "%s: Amiga built-in port using irq\n", p->name);
+		/* XXX: set operating mode */
+		parport_proc_register(p);
+		p->flags |= PARPORT_FLAG_COMA;
+
+		if (parport_probe_hook)
+			(*parport_probe_hook)(p);
+		return 1;
+
+	}
+	return 0;
+}
+
+#ifdef MODULE
+
+MODULE_AUTHOR("Joerg Dorchain");
+MODULE_DESCRIPTION("Parport Driver for Amiga builtin Port");
+MODULE_SUPPORTED_DEVICE("Amiga builtin Parallel Port");
+
+int init_module(void)
+{
+	return ! parport_amiga_init();
+}
+
+void cleanup_module(void)
+{
+	if (!(this_port->flags & PARPORT_FLAG_COMA))
+		parport_quiesce(this_port);
+	parport_proc_unregister(this_port);
+	parport_unregister_port(this_port);
+}
+#endif
+
+
diff -urN linux-2.2.8-pre7/drivers/misc/parport_atari.c linux/drivers/misc/parport_atari.c
--- linux-2.2.8-pre7/drivers/misc/parport_atari.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/misc/parport_atari.c	Mon Dec  3 18:46:55 2001
@@ -0,0 +1,263 @@
+/* Low-level parallel port routines for the Atari builtin port
+ *
+ * Author: Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
+ *
+ * Based on parport_amiga.c.
+ *
+ * The built-in Atari parallel port provides one port at a fixed address
+ * with 8 output data lines (D0 - D7), 1 output control line (STROBE)
+ * and 1 input status line (BUSY) able to cause an interrupt.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/parport.h>
+#include <asm/setup.h>
+#include <asm/atarihw.h>
+#include <asm/irq.h>
+#include <asm/atariints.h>
+
+static struct parport *this_port = NULL;
+
+static unsigned char
+parport_atari_read_data(struct parport *p)
+{
+	unsigned long flags;
+	unsigned char data;
+
+	save_flags(flags);
+	cli();
+	sound_ym.rd_data_reg_sel = 15;
+	data = sound_ym.rd_data_reg_sel;
+	restore_flags(flags);
+	return data;
+}
+
+static void
+parport_atari_write_data(struct parport *p, unsigned char data)
+{
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	sound_ym.rd_data_reg_sel = 15;
+	sound_ym.wd_data = data;
+	restore_flags(flags);
+}
+
+static unsigned char
+parport_atari_read_control(struct parport *p)
+{
+	unsigned long flags;
+	unsigned char control = 0;
+
+	save_flags(flags);
+	cli();
+	sound_ym.rd_data_reg_sel = 14;
+	if (!(sound_ym.rd_data_reg_sel & (1 << 5)))
+		control = PARPORT_CONTROL_STROBE;
+	restore_flags(flags);
+	return control;
+}
+
+static void
+parport_atari_write_control(struct parport *p, unsigned char control)
+{
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	sound_ym.rd_data_reg_sel = 14;
+	if (control & PARPORT_CONTROL_STROBE)
+		sound_ym.wd_data = sound_ym.rd_data_reg_sel & ~(1 << 5);
+	else
+		sound_ym.wd_data = sound_ym.rd_data_reg_sel | (1 << 5);
+	restore_flags(flags);
+}
+
+static unsigned char
+parport_atari_frob_control(struct parport *p, unsigned char mask,
+			   unsigned char val)
+{
+	unsigned char old = parport_atari_read_control(p);
+	parport_atari_write_control(p, (old & ~mask) ^ val);
+	return old;
+}
+
+static unsigned char
+parport_atari_read_status(struct parport *p)
+{
+	return ((mfp.par_dt_reg & 1 ? 0 : PARPORT_STATUS_BUSY) |
+		PARPORT_STATUS_SELECT | PARPORT_STATUS_ERROR);
+}
+
+static void
+parport_atari_write_status(struct parport *p, unsigned char status)
+{
+}
+
+static void
+parport_atari_init_state(struct parport_state *s)
+{
+}
+
+static void
+parport_atari_save_state(struct parport *p, struct parport_state *s)
+{
+}
+
+static void
+parport_atari_restore_state(struct parport *p, struct parport_state *s)
+{
+}
+
+static void
+parport_atari_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	parport_generic_irq(irq, (struct parport *) dev_id, regs);
+}
+
+static void
+parport_atari_release_resources(struct parport *p)
+{
+	if (p->irq != PARPORT_IRQ_NONE)
+		free_irq(IRQ_MFP_BUSY, p);
+}
+
+static int
+parport_atari_claim_resources(struct parport *p)
+{
+	return request_irq(IRQ_MFP_BUSY, parport_atari_interrupt,
+			   IRQ_TYPE_SLOW, p->name, p);
+}
+
+static void
+parport_atari_inc_use_count(void)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void
+parport_atari_dec_use_count(void)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+static void
+parport_atari_fill_inode(struct inode *inode, int fill)
+{
+#ifdef MODULE
+	if (fill)
+		MOD_INC_USE_COUNT;
+	else
+		MOD_DEC_USE_COUNT;
+#endif
+}
+
+static struct parport_operations parport_atari_ops = {
+	parport_atari_write_data,
+	parport_atari_read_data,
+
+	parport_atari_write_control,
+	parport_atari_read_control,
+	parport_atari_frob_control,
+
+	NULL, /* write_econtrol */
+	NULL, /* read_econtrol */
+	NULL, /* frob_econtrol */
+
+	parport_atari_write_status,
+	parport_atari_read_status,
+
+	NULL, /* write fifo */
+	NULL, /* read fifo */
+
+	NULL, /* change_mode */
+
+	parport_atari_release_resources,
+	parport_atari_claim_resources,
+
+	NULL, /* epp_write_data */
+	NULL, /* epp_read_data */
+	NULL, /* epp_write_addr */
+	NULL, /* epp_read_addr */
+	NULL, /* epp_check_timeout */
+
+	NULL, /* epp_write_block */
+	NULL, /* epp_read_block */
+
+	NULL, /* ecp_write_block */
+	NULL, /* ecp_read_block */
+
+	parport_atari_init_state,
+	parport_atari_save_state,
+	parport_atari_restore_state,
+
+	NULL, /* enable_irq */
+	NULL, /* disable_irq */
+	parport_atari_interrupt,
+
+	parport_atari_inc_use_count,
+	parport_atari_dec_use_count,
+	parport_atari_fill_inode
+};
+
+
+int __init
+parport_atari_init(void)
+{
+	struct parport *p;
+	unsigned long flags;
+
+	if (MACH_IS_ATARI) {
+		save_flags(flags);
+		cli();
+		/* Soundchip port A/B as output. */
+		sound_ym.rd_data_reg_sel = 7;
+		sound_ym.wd_data = (sound_ym.rd_data_reg_sel & 0x3f) | 0xc0;
+		/* STROBE high. */
+		sound_ym.rd_data_reg_sel = 14;
+		sound_ym.wd_data = sound_ym.rd_data_reg_sel | (1 << 5);
+		restore_flags(flags);
+		/* MFP port I0 as input. */
+		mfp.data_dir &= ~1;
+		/* MFP port I0 interrupt on high->low edge. */
+		mfp.active_edge &= ~1;
+		p = parport_register_port((unsigned long)&sound_ym.wd_data,
+					  IRQ_MFP_BUSY, PARPORT_DMA_NONE,
+					  &parport_atari_ops);
+		if (!p)
+			return 0;
+		this_port = p;
+		printk(KERN_INFO "%s: Atari built-in port using irq\n", p->name);
+		parport_proc_register(p);
+		p->flags |= PARPORT_FLAG_COMA;
+
+		if (parport_probe_hook)
+			(*parport_probe_hook)(p);
+		return 1;
+	}
+	return 0;
+}
+
+#ifdef MODULE
+
+MODULE_AUTHOR("Andreas Schwab");
+MODULE_DESCRIPTION("Parport Driver for Atari builtin Port");
+MODULE_SUPPORTED_DEVICE("Atari builtin Parallel Port");
+
+int
+init_module(void)
+{
+	return parport_atari_init() ? 0 : -ENODEV;
+}
+
+void
+cleanup_module(void)
+{
+	if (!(this_port->flags & PARPORT_FLAG_COMA))
+		parport_quiesce(this_port);
+	parport_proc_unregister(this_port);
+	parport_unregister_port(this_port);
+}
+#endif
diff -urN linux-2.2.8-pre7/drivers/misc/parport_init.c linux/drivers/misc/parport_init.c
--- linux-2.2.8-pre7/drivers/misc/parport_init.c	Sat Jan  2 17:55:05 1999
+++ linux/drivers/misc/parport_init.c	Mon Dec  3 18:46:55 2001
@@ -126,6 +126,15 @@
 #ifdef CONFIG_PARPORT_AX
 	parport_ax_init();
 #endif
+#ifdef CONFIG_PARPORT_AMIGA
+	parport_amiga_init();
+#endif
+#ifdef CONFIG_PARPORT_MFC3
+	parport_mfc3_init();
+#endif
+#ifdef CONFIG_PARPORT_ATARI
+	parport_atari_init();
+#endif
 	return 0;
 }
 #endif
diff -urN linux-2.2.8-pre7/drivers/misc/parport_mfc3.c linux/drivers/misc/parport_mfc3.c
--- linux-2.2.8-pre7/drivers/misc/parport_mfc3.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/misc/parport_mfc3.c	Mon Dec  3 18:46:55 2001
@@ -0,0 +1,420 @@
+/* Low-level parallel port routines for the Multiface 3 card
+ *
+ * Author: Joerg Dorchain <dorchain@wirbel.com>
+ *
+ * (C) The elitist m68k Users(TM)
+ *
+ * based on the existing parport_amiga and lp_mfc
+ *
+ *
+ * From the MFC3 documentation:
+ * 
+ * Miscellaneous PIA Details
+ * -------------------------
+ * 
+ * 	The two open-drain interrupt outputs /IRQA and /IRQB are routed to
+ * /INT2 of the Z2 bus.
+ * 
+ * 	The CPU data bus of the PIA (D0-D7) is connected to D8-D15 on the Z2
+ * bus. This means that any PIA registers are accessed at even addresses.
+ * 
+ * Centronics Pin Connections for the PIA
+ * --------------------------------------
+ * 
+ * 	The following table shows the connections between the PIA and the
+ * Centronics interface connector. These connections implement a single, but
+ * very complete, Centronics type interface. The Pin column gives the pin
+ * numbers of the PIA. The Centronics pin numbers can be found in the section
+ * "Parallel Connectors".
+ * 
+ * 
+ *    Pin | PIA | Dir | Centronics Names
+ * -------+-----+-----+---------------------------------------------------------
+ *     19 | CB2 | --> | /STROBE (aka /DRDY)
+ *  10-17 | PBx | <-> | DATA0 - DATA7
+ *     18 | CB1 | <-- | /ACK
+ *     40 | CA1 | <-- | BUSY
+ *      3 | PA1 | <-- | PAPER-OUT (aka POUT)
+ *      4 | PA2 | <-- | SELECTED (aka SEL)
+ *      9 | PA7 | --> | /INIT (aka /RESET or /INPUT-PRIME)
+ *      6 | PA4 | <-- | /ERROR (aka /FAULT)
+ *      7 | PA5 | --> | DIR (aka /SELECT-IN)
+ *      8 | PA6 | --> | /AUTO-FEED-XT
+ *     39 | CA2 | --> | open
+ *      5 | PA3 | <-- | /ACK (same as CB1!)
+ *      2 | PA0 | <-- | BUSY (same as CA1!)
+ * -------+-----+-----+---------------------------------------------------------
+ * 
+ * Should be enough to understand some of the driver.
+ */
+
+#include "multiface.h"
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/parport.h>
+#include <linux/delay.h>
+#include <linux/mc6821.h>
+#include <linux/zorro.h>
+#include <asm/setup.h>
+#include <asm/amigahw.h>
+#include <asm/irq.h>
+#include <asm/amigaints.h>
+
+/* Maximum Number of Cards supported */
+#define MAX_MFC 5
+
+#undef DEBUG
+#ifdef DEBUG
+#define DPRINTK printk
+#else
+static inline int DPRINTK() {return 0;}
+#endif
+
+static struct parport *this_port[MAX_MFC] = {NULL, };
+static volatile int dummy; /* for trigger readds */
+
+#define pia(dev) ((struct pia *)(dev->base))
+static struct parport_operations pp_mfc3_ops;
+
+static void mfc3_write_data(struct parport *p, unsigned char data)
+{
+DPRINTK("write_data %c\n",data);
+
+	dummy = pia(p)->pprb; /* clears irq bit */
+	/* Triggers also /STROBE.*/
+	pia(p)->pprb = data;
+}
+
+static unsigned char mfc3_read_data(struct parport *p)
+{
+	/* clears interupt bit. Triggers also /STROBE. */
+	return pia(p)->pprb;
+}
+
+static unsigned char control_pc_to_mfc3(unsigned char control)
+{
+	unsigned char ret = 32|64;
+
+	if (control & PARPORT_CONTROL_DIRECTION) /* XXX: What is this? */
+		;
+	if (control & PARPORT_CONTROL_INTEN) /* XXX: What is INTEN? */
+		;
+	if (control & PARPORT_CONTROL_SELECT) /* XXX: What is SELECP? */
+		ret &= ~32; /* /SELECT_IN */
+	if (control & PARPORT_CONTROL_INIT) /* INITP */
+		ret |= 128;
+	if (control & PARPORT_CONTROL_AUTOFD) /* AUTOLF */
+		ret &= ~64;
+	if (control & PARPORT_CONTROL_STROBE) /* Strobe */
+		/* Handled directly by hardware */;
+	return ret;
+}
+
+static unsigned char control_mfc3_to_pc(unsigned char control)
+{
+	unsigned char ret = PARPORT_CONTROL_INTEN | PARPORT_CONTROL_STROBE 
+			  | PARPORT_CONTROL_AUTOFD | PARPORT_CONTROL_SELECT;
+
+	if (control & 128) /* /INITP */
+		ret |= PARPORT_CONTROL_INIT;
+	if (control & 64) /* /AUTOLF */
+		ret &= ~PARPORT_CONTROL_AUTOFD;
+	if (control & 32) /* /SELECT_IN */
+		ret &= ~PARPORT_CONTROL_SELECT;
+	return ret;
+}
+
+static void mfc3_write_control(struct parport *p, unsigned char control)
+{
+DPRINTK("write_control %02x\n",control);
+	pia(p)->ppra = (pia(p)->ppra & 0x1f) | control_pc_to_mfc3(control);
+}
+	
+static unsigned char mfc3_read_control( struct parport *p)
+{
+DPRINTK("read_control \n");
+	return control_mfc3_to_pc(pia(p)->ppra & 0xe0);
+}
+
+static unsigned char mfc3_frob_control( struct parport *p, unsigned char mask, unsigned char val)
+{
+	unsigned char old;
+
+DPRINTK("frob_control mask %02x, value %02x\n",mask,val);
+	old = mfc3_read_control(p);
+	mfc3_write_control(p, (old & ~mask) ^ val);
+	return old;
+}
+
+
+static unsigned char status_pc_to_mfc3(unsigned char status)
+{
+	unsigned char ret = 1;
+
+	if (status & PARPORT_STATUS_BUSY) /* Busy */
+		ret &= ~1;
+	if (status & PARPORT_STATUS_ACK) /* Ack */
+		ret |= 8;
+	if (status & PARPORT_STATUS_PAPEROUT) /* PaperOut */
+		ret |= 2;
+	if (status & PARPORT_STATUS_SELECT) /* select */
+		ret |= 4;
+	if (status & PARPORT_STATUS_ERROR) /* error */
+		ret |= 16;
+	return ret;
+}
+
+static unsigned char status_mfc3_to_pc(unsigned char status)
+{
+	unsigned char ret = PARPORT_STATUS_BUSY;
+
+	if (status & 1) /* Busy */
+		ret &= ~PARPORT_STATUS_BUSY;
+	if (status & 2) /* PaperOut */
+		ret |= PARPORT_STATUS_PAPEROUT;
+	if (status & 4) /* Selected */
+		ret |= PARPORT_STATUS_SELECT;
+	if (status & 8) /* Ack */
+		ret |= PARPORT_STATUS_ACK;
+	if (status & 16) /* /ERROR */
+		ret |= PARPORT_STATUS_ERROR;
+
+	return ret;
+}
+
+static void mfc3_write_status( struct parport *p, unsigned char status)
+{
+DPRINTK("write_status %02x\n",status);
+	pia(p)->ppra = (pia(p)->ppra & 0xe0) | status_pc_to_mfc3(status);
+}
+
+static unsigned char mfc3_read_status(struct parport *p)
+{
+	unsigned char status;
+
+	status = status_mfc3_to_pc(pia(p)->ppra & 0x1f);
+DPRINTK("read_status %02x\n", status);
+	return status;
+}
+
+static void mfc3_change_mode( struct parport *p, int m)
+{
+	/* XXX: This port only has one mode, and I am
+	not sure about the corresponding PC-style mode*/
+}
+
+static int use_cnt = 0;
+
+static void mfc3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	int i;
+
+	for( i = 0; i < MAX_MFC; i++)
+		if (this_port[i] != NULL)
+			if (pia(this_port[i])->crb & 128) { /* Board caused interrupt */
+				dummy = pia(this_port[i])->pprb; /* clear irq bit */
+				parport_generic_irq(irq, this_port[i], regs);
+			}
+}
+
+static void mfc3_release_resources(struct parport *p)
+{
+DPRINTK("realease_resources\n");
+	if (p->irq != PARPORT_IRQ_NONE) 
+		if (--use_cnt == 0) 
+			free_irq(IRQ_AMIGA_PORTS, &pp_mfc3_ops);
+}
+
+static int mfc3_claim_resources(struct parport *p)
+{
+DPRINTK("claim_resources\n");
+	if (p->irq != PARPORT_IRQ_NONE)
+		if (use_cnt++ == 0)
+			if (request_irq(IRQ_AMIGA_PORTS, mfc3_interrupt, 0, p->name, &pp_mfc3_ops))
+				 return use_cnt--;
+	return 0;
+}
+
+static void mfc3_init_state(struct parport_state *s)
+{
+	s->u.amiga.data = 0;
+	s->u.amiga.datadir = 255;
+	s->u.amiga.status = 0;
+	s->u.amiga.statusdir = 0xe0;
+}
+
+static void mfc3_save_state(struct parport *p, struct parport_state *s)
+{
+	s->u.amiga.data = pia(p)->pprb;
+	pia(p)->crb &= ~PIA_DDR;
+	s->u.amiga.datadir = pia(p)->pddrb;
+	pia(p)->crb |= PIA_DDR;
+	s->u.amiga.status = pia(p)->ppra;
+	pia(p)->cra &= ~PIA_DDR;
+	s->u.amiga.statusdir = pia(p)->pddrb;
+	pia(p)->cra |= PIA_DDR;
+}
+
+static void mfc3_restore_state(struct parport *p, struct parport_state *s)
+{
+	pia(p)->pprb = s->u.amiga.data;
+	pia(p)->crb &= ~PIA_DDR;
+	pia(p)->pddrb = s->u.amiga.datadir;
+	pia(p)->crb |= PIA_DDR;
+	pia(p)->ppra = s->u.amiga.status;
+	pia(p)->cra &= ~PIA_DDR;
+	pia(p)->pddrb = s->u.amiga.statusdir;
+	pia(p)->cra |= PIA_DDR;
+}
+
+static void mfc3_enable_irq(struct parport *p)
+{
+	pia(p)->crb |= PIA_C1_ENABLE_IRQ;
+}
+
+static void mfc3_disable_irq(struct parport *p)
+{
+	pia(p)->crb &= ~PIA_C1_ENABLE_IRQ;
+}
+
+static void mfc3_inc_use_count(void)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void mfc3_dec_use_count(void)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+static void mfc3_fill_inode(struct inode *inode, int fill)
+{
+#ifdef MODULE
+	if (fill)
+		MOD_INC_USE_COUNT;
+	else
+		MOD_DEC_USE_COUNT;
+#endif
+}
+
+static struct parport_operations pp_mfc3_ops = {
+	mfc3_write_data,
+	mfc3_read_data,
+
+	mfc3_write_control,
+	mfc3_read_control,
+	mfc3_frob_control,
+
+	NULL, /* write_econtrol */
+	NULL, /* read_econtrol */
+	NULL, /* frob_econtrol */
+
+	mfc3_write_status,
+	mfc3_read_status,
+
+	NULL, /* write fifo */
+	NULL, /* read fifo */
+
+	mfc3_change_mode,
+
+
+	mfc3_release_resources,
+	mfc3_claim_resources,
+
+
+	NULL, /* epp_write_data */
+	NULL, /* epp_read_data */
+	NULL, /* epp_write_addr */
+	NULL, /* epp_read_addr */
+	NULL, /* epp_check_timeout */
+
+	NULL, /* epp_write_block */
+	NULL, /* epp_read_block */
+
+	NULL, /* ecp_write_block */
+	NULL, /* ecp_read_block */
+
+	mfc3_init_state,
+	mfc3_save_state,
+	mfc3_restore_state,
+
+	mfc3_enable_irq,
+	mfc3_disable_irq,
+	mfc3_interrupt,
+
+	mfc3_inc_use_count,
+	mfc3_dec_use_count,
+	mfc3_fill_inode
+};
+
+/* ----------- Initialisation code --------------------------------- */
+
+__initfunc(int parport_mfc3_init(void))
+{
+	struct parport *p;
+	int pias = 0;
+	struct pia *pp;
+	unsigned int key = 0;
+	const struct ConfigDev *cd;
+
+	if (MACH_IS_AMIGA) {
+		while ((key = zorro_find(ZORRO_PROD_BSC_MULTIFACE_III, 0, key))) {
+			cd = zorro_get_board(key);
+			pp = (struct pia *)ZTWO_VADDR((((u_char *)cd->cd_BoardAddr)+PIABASE));
+			if (pias < MAX_MFC) {
+				pp->crb = 0;
+				pp->pddrb = 255; /* all data pins output */
+				pp->crb = PIA_DDR|32|8;
+				dummy = pp->pddrb; /* reading clears interrupt */
+				pp->cra = 0;
+				pp->pddra = 0xe0; /* /RESET,  /DIR ,/AUTO-FEED output */
+				pp->cra = PIA_DDR;
+				pp->ppra = 0; /* reset printer */
+				udelay(10);
+				pp->ppra = 128;
+				if ((p = parport_register_port((unsigned long)pp,
+					IRQ_AMIGA_PORTS, PARPORT_DMA_NONE,
+					&pp_mfc3_ops))) {
+					this_port[pias++] = p;
+					printk(KERN_INFO "%s: Multiface III port using irq\n", p->name);
+					/* XXX: set operating mode */
+					parport_proc_register(p);
+					p->flags |= PARPORT_FLAG_COMA;
+					if (parport_probe_hook)
+						(*parport_probe_hook)(p);
+					zorro_config_board(key, 0);
+					p->private_data = (void *)key;
+				}
+			}
+		}
+	}
+	return pias;
+}
+
+#ifdef MODULE
+
+MODULE_AUTHOR("Joerg Dorchain");
+MODULE_DESCRIPTION("Parport Driver for Multiface 3 expansion cards Paralllel Port");
+MODULE_SUPPORTED_DEVICE("Multiface 3 Parallel Port");
+
+int init_module(void)
+{
+	return ! parport_mfc3_init();
+}
+
+void cleanup_module(void)
+{
+	int i;
+
+	for (i = 0; i < MAX_MFC; i++)
+		if (this_port[i] != NULL) {
+			if (!(this_port[i]->flags & PARPORT_FLAG_COMA))
+				parport_quiesce(this_port[i]);
+			parport_proc_unregister(this_port[i]);
+			parport_unregister_port(this_port[i]);
+			zorro_unconfig_board((unsigned int)this_port[i]->private_data, 0);
+		}
+}
+#endif
+
+
diff -urN linux-2.2.8-pre7/drivers/net/de4x5.h linux/drivers/net/de4x5.h
--- linux-2.2.8-pre7/drivers/net/de4x5.h	Mon Dec  3 18:46:19 2001
+++ linux/drivers/net/de4x5.h	Mon Dec  3 18:46:55 2001
@@ -1028,4 +1028,4 @@
 
 #define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
 
-#define MOTO_SROM_BUG    ((lp->active == 8) && ((*((s32 *)le32_to_cpu(get_unaligned(dev->dev_addr)))&0x00ffffff)==0x3e0008))
+#define MOTO_SROM_BUG    ((lp->active == 8) && (((le32_to_cpu(get_unaligned(((s32 *)dev->dev_addr))))&0x00ffffff)==0x3e0008))
diff -urN linux-2.2.8-pre7/drivers/net/ethertap.c linux/drivers/net/ethertap.c
--- linux-2.2.8-pre7/drivers/net/ethertap.c	Mon Dec  3 18:46:19 2001
+++ linux/drivers/net/ethertap.c	Mon Dec  3 18:46:55 2001
@@ -98,7 +98,6 @@
 
 	ether_setup(dev);
 
-	dev->hard_header_len = 16;
 	dev->tx_queue_len = 0;
 	dev->flags|=IFF_NOARP;
 	tap_map[dev->base_addr]=dev;
@@ -178,11 +177,21 @@
 #endif
 
 	if (skb_headroom(skb) < 2) {
-		printk(KERN_DEBUG "%s : bug --- xmit with head<2\n", dev->name);
+		static int once;
+	  	struct sk_buff *skb2;
+
+		if (!once) {
+			once = 1;
+			printk(KERN_DEBUG "%s: not aligned xmit by protocol %04x\n", dev->name, skb->protocol);
+		}
+
+		skb2 = skb_realloc_headroom(skb, 2);
 		dev_kfree_skb(skb);
-		return 0;
+		if (skb2 == NULL)
+			return 0;
+		skb = skb2;
 	}
-	skb_push(skb, 2);
+	__skb_push(skb, 2);
 
 	/* Make the same thing, which loopback does. */
 	if (skb_shared(skb)) {
diff -urN linux-2.2.8-pre7/drivers/net/ppp.c linux/drivers/net/ppp.c
--- linux-2.2.8-pre7/drivers/net/ppp.c	Mon Dec  3 18:46:19 2001
+++ linux/drivers/net/ppp.c	Mon Dec  3 18:46:55 2001
@@ -4,7 +4,7 @@
  *  Al Longyear <longyear@netcom.com>
  *  Extensively rewritten by Paul Mackerras <paulus@cs.anu.edu.au>
  *
- *  ==FILEVERSION 990331==
+ *  ==FILEVERSION 990510==
  *
  *  NOTE TO MAINTAINERS:
  *     If you modify this file at all, please set the number above to the
@@ -90,9 +90,6 @@
 #include <linux/kmod.h>
 #endif
 
-typedef ssize_t		rw_ret_t;
-typedef size_t		rw_count_t;
-
 /*
  * Local functions
  */
@@ -109,6 +106,7 @@
 static int ppp_async_encode(struct ppp *ppp);
 static int ppp_async_send(struct ppp *, struct sk_buff *);
 static int ppp_sync_send(struct ppp *, struct sk_buff *);
+static void ppp_tty_flush_output(struct ppp *);
 
 static int ppp_ioctl(struct ppp *, unsigned int, unsigned long);
 static int ppp_set_compression (struct ppp *ppp, struct ppp_option_data *odp);
@@ -191,10 +189,10 @@
  * TTY callbacks
  */
 
-static rw_ret_t ppp_tty_read(struct tty_struct *, struct file *, __u8 *,
-			     rw_count_t);
-static rw_ret_t ppp_tty_write(struct tty_struct *, struct file *, const __u8 *,
-			      rw_count_t);
+static ssize_t ppp_tty_read(struct tty_struct *, struct file *, __u8 *,
+			    size_t);
+static ssize_t ppp_tty_write(struct tty_struct *, struct file *, const __u8 *,
+			     size_t);
 static int ppp_tty_ioctl(struct tty_struct *, struct file *, unsigned int,
 			 unsigned long);
 static unsigned int ppp_tty_poll(struct tty_struct *tty, struct file *filp,
@@ -446,6 +444,7 @@
 		ppp->tty = ppp->backup_tty;
 		if (ppp_tty_push(ppp))
 			ppp_output_wakeup(ppp);
+		wake_up_interruptible(&ppp->read_wait);
 	} else {
 		ppp->tty = 0;
 		ppp->sc_xfer = 0;
@@ -463,13 +462,13 @@
  * Read a PPP frame from the rcv_q list,
  * waiting if necessary
  */
-static rw_ret_t
+static ssize_t
 ppp_tty_read(struct tty_struct *tty, struct file *file, __u8 * buf,
-	     rw_count_t nr)
+	     size_t nr)
 {
 	struct ppp *ppp = tty2ppp (tty);
 	struct sk_buff *skb;
-	rw_ret_t len, err;
+	ssize_t len, err;
 
 	/*
 	 * Validate the pointers
@@ -551,9 +550,9 @@
  * Writing to a tty in ppp line discipline sends a PPP frame.
  * Used by pppd to send control packets (LCP, etc.).
  */
-static rw_ret_t
+static ssize_t
 ppp_tty_write(struct tty_struct *tty, struct file *file, const __u8 * data,
-	      rw_count_t count)
+	      size_t count)
 {
 	struct ppp *ppp = tty2ppp (tty);
 	__u8 *new_data;
@@ -605,7 +604,7 @@
 	 */
 	ppp_send_ctrl(ppp, skb);
 
-	return (rw_ret_t) count;
+	return (ssize_t) count;
 }
 
 /*
@@ -724,6 +723,21 @@
 		error = n_tty_ioctl (tty, file, param2, param3);
 		break;
 
+	case TCFLSH:
+		/*
+		 * Flush our buffers, then call the generic code to
+		 * flush the serial port's buffer.
+		 */
+		if (param3 == TCIFLUSH || param3 == TCIOFLUSH) {
+			struct sk_buff *skb;
+			while ((skb = skb_dequeue(&ppp->rcv_q)) != NULL)
+				kfree_skb(skb);
+		}
+		if (param3 == TCIOFLUSH || param3 == TCOFLUSH)
+			ppp_tty_flush_output(ppp);
+		error = n_tty_ioctl (tty, file, param2, param3);
+		break;
+
 	case FIONREAD:
 		/*
 		 * Returns how many bytes are available for a read().
@@ -882,7 +896,7 @@
 	save_flags(flags);
 	cli();
 	if (ppp->tty_pushing) {
-		/* record wakeup attempt so we don't loose */
+		/* record wakeup attempt so we don't lose */
 		/* a wakeup call while doing push processing */
 		ppp->woke_up=1;
 		restore_flags(flags);
@@ -965,16 +979,20 @@
 	int avail, sent, done = 0;
 	struct tty_struct *tty = ppp2tty(ppp);
 	
-	if ( ppp->flags & SC_SYNC ) 
+	if (ppp->flags & SC_SYNC) 
 		return ppp_tty_sync_push(ppp);
 
 	CHECK_PPP(0);
-	if (ppp->tty_pushing)
+	if (ppp->tty_pushing) {
+		ppp->woke_up = 1;
 		return 0;
+	}
 	if (tty == NULL || tty->disc_data != (void *) ppp)
 		goto flush;
 	while (ppp->optr < ppp->olim || ppp->tpkt != 0) {
 		ppp->tty_pushing = 1;
+		mb();
+		ppp->woke_up = 0;
 		avail = ppp->olim - ppp->optr;
 		if (avail > 0) {
 			tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
@@ -984,18 +1002,24 @@
 			ppp->stats.ppp_obytes += sent;
 			ppp->optr += sent;
 			if (sent < avail) {
+				wmb();
 				ppp->tty_pushing = 0;
+				mb();
+				if (ppp->woke_up)
+					continue;
 				return done;
 			}
 		}
 		if (ppp->tpkt != 0)
 			done = ppp_async_encode(ppp);
+		wmb();
 		ppp->tty_pushing = 0;
 	}
 	return done;
 
 flush:
 	ppp->tty_pushing = 1;
+	mb();
 	ppp->stats.ppp_oerrors++;
 	if (ppp->tpkt != 0) {
 		kfree_skb(ppp->tpkt);
@@ -1003,6 +1027,7 @@
 		done = 1;
 	}
 	ppp->optr = ppp->olim;
+	wmb();
 	ppp->tty_pushing = 0;
 	return done;
 }
@@ -1114,6 +1139,32 @@
 	ppp->tpkt_pos = i;
 	ppp->tfcs = fcs;
 	return 0;
+}
+
+/*
+ * Flush output from our internal buffers.
+ * Called for the TCFLSH ioctl.
+ */
+static void
+ppp_tty_flush_output(struct ppp *ppp)
+{
+	struct sk_buff *skb;
+	int done = 0;
+
+	while ((skb = skb_dequeue(&ppp->xmt_q)) != NULL)
+		kfree_skb(skb);
+	ppp->tty_pushing = 1;
+	mb();
+	ppp->optr = ppp->olim;
+	if (ppp->tpkt != NULL) {
+		kfree_skb(ppp->tpkt);
+		ppp->tpkt = 0;
+		done = 1;
+	}
+	wmb();
+	ppp->tty_pushing = 0;
+	if (done)
+		ppp_output_wakeup(ppp);
 }
 
 /*
diff -urN linux-2.2.8-pre7/drivers/sbus/char/pcikbd.c linux/drivers/sbus/char/pcikbd.c
--- linux-2.2.8-pre7/drivers/sbus/char/pcikbd.c	Wed Apr 28 08:47:39 1999
+++ linux/drivers/sbus/char/pcikbd.c	Mon Dec  3 18:46:55 2001
@@ -1,4 +1,4 @@
-/* $Id: pcikbd.c,v 1.26 1999/04/28 11:55:42 davem Exp $
+/* $Id: pcikbd.c,v 1.27 1999/05/09 06:40:47 ecd Exp $
  * pcikbd.c: Ultra/AX PC keyboard support.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -276,6 +276,7 @@
 		prev_scancode = 0;
 		return 0;
 	}
+	scancode &= 0x7f;
 	if(prev_scancode) {
 		if(prev_scancode != 0xe0) {
 			if(prev_scancode == 0xe1 && scancode == 0x1d) {
diff -urN linux-2.2.8-pre7/drivers/usb/CREDITS linux/drivers/usb/CREDITS
--- linux-2.2.8-pre7/drivers/usb/CREDITS	Sat Apr 24 04:48:49 1999
+++ linux/drivers/usb/CREDITS	Mon Dec  3 18:46:55 2001
@@ -2,14 +2,16 @@
 
 The following people have contributed to this code (in alphabetical
 order by last name).  I'm sure this list should be longer, its
-difficult to maintain.
+difficult to maintain, add yourself with a patch if desired.
 
+  Alan Cox <alan@lxorguk.ukuu.org.uk>
   Johannes Erdfelt <jerdfelt@sventech.com>
   ham <ham@unsuave.com>
   Bradley M Keryan <keryan@andrew.cmu.edu>
   Vojtech Pavlik <vojtech@twilight.ucw.cz>
   Gregory P. Smith <greg@electricrain.com>
   Linus Torvalds <torvalds@transmeta.com>
+  Roman Weissgaerber <weissg@vienna.at>
   <Kazuki.Yasumatsu@fujixerox.co.jp>
 
 Special thanks to:
@@ -20,4 +22,133 @@
 
   The NetBSD & FreeBSD USB developers.  For being on the Linux USB list
   and offering suggestions and sharing implementation experiences.
+
+Additional thanks to the following companies and people for donations
+of hardware, support, time and development (this is from the original
+THANKS file in Inaky's driver):
+
+        The following corporations have helped us in the development
+of Linux USB / UUSBD:
+
+        - USAR Systems provided us with one of their excellent USB
+          Evaluation Kits. It allows us to test the Linux-USB driver
+          for compilance with the latest USB specification. USAR
+          Systems recognized the importance of an up-to-date open
+          Operating System and supports this project with
+          Hardware. Thanks!.
+
+        - Thanks to Intel Corporation for their precious help.
+
+        - We teamed up with Cherry to make Linux the first OS with
+          built-in USB support. Cherry is one of the biggest keyboard
+          makers in the world.
+
+        - CMD Technology, Inc. sponsored us kindly donating a CSA-6700
+          PCI-to-USB Controller Board to test the OHCI implementation.
+
+        - Due to their support to us, Keytronic can be sure that they
+          will sell keyboards to some of the 3 million (at least)
+          Linux users.
+
+        - Many thanks to ing büro h doran [http://www.ibhdoran.com]!
+          It was almost imposible to get a PC backplate USB connector
+          for the motherboard here at Europe (mine, home-made, was
+          quite lowsy :). Now I know where to adquire nice USB stuff!
+
+        - Genius Germany donated a USB mouse to test the mouse boot
+          protocol. They've also donated a F-23 digital joystick and a
+          NetMouse Pro. Thanks! 
+
+        - AVM GmbH Berlin is supporting the development of the Linux
+          USB driver for the AVM ISDN Controller B1 USB. AVM is a
+          leading manufacturer for active and passive ISDN Controllers
+          and CAPI 2.0-based software. The active design of the AVM B1
+          is open for all OS platforms, including Linux.
+
+        - Thanks to Y-E Data, Inc. for donating their FlashBuster-U
+          USB Floppy Disk Drive, so we could test the bulk transfer
+          code.
+
+        - Many thanks to Logitech for contributing a three axis USB
+          mouse. 
+
+          Logitech designs, manufactures and markets
+          Human Interface Devices, having a long history and
+          experience in making devices such as keyboards, mice,
+          trackballs, cameras, loudspeakers and control devices for
+          gaming and professional use.
+
+          Being a recognized vendor and seller for all these devices,
+          they have donated USB mice, a joystick and a scanner, as a
+          way to acknowledge the importance of Linux and to allow
+          Logitech customers to enjoy support in their favorite
+          operating systems and all Linux users to use Logitech and
+          other USB hardware.
+
+          Logitech is official sponsor of the Linux Conference on
+          Feb. 11th 1999 in Vienna, where we'll will present the
+          current state of the Linux USB effort.
+
+        - CATC has provided means to uncover dark corners of the UHCI
+          inner workings with a USB Inspector.
+
+        - Thanks to Entrega for providing PCI to USB cards, hubs and
+          converter products for development. 
+
+
+        And thanks go to (hey! in no particular order :)
+
+        - Oren Tirosh <orenti@hishome.net>, for standing so patiently
+          all my doubts'bout USB and giving lots of cool ideas.
+
+        - Jochen Karrer <karrer@wpfd25.physik.uni-wuerzburg.de>, for
+          pointing out mortal bugs and giving advice.
+
+        - Edmund Humemberger <ed@atnet.at>, for it's great work on
+          public relationships and general management stuff for the
+          Linux-USB effort.
+
+        - Alberto Menegazzi <flash@flash.iol.it> is starting the
+          documentation for the UUSBD. Go for it!
+
+        - Ric Klaren <ia_ric@cs.utwente.nl> for doing nice
+          introductory documents (compiting with Alberto's :).
+
+        - Christian Groessler <cpg@aladdin.de>, for it's help on those
+          itchy bits ... :)
+
+        - Paul MacKerras for polishing OHCI and pushing me harder for
+          the iMac support, giving improvements and enhancements.
+
+        - Fernando Herrera <fherrera@eurielec.etsit.upm.es> has taken
+          charge of composing, maintaining and feeding the
+          long-awaited, unique and marvelous UUSBD FAQ! Tadaaaa!!!
+
+        - Rasca Gmelch <thron@gmx.de> has revived the raw driver and
+          pointed bugs, as well as started the uusbd-utils package.
+
+        - Peter Dettori <dettori@ozy.dec.com> is unconvering bugs like
+          crazy, as well as making cool suggestions, great :)
+
+        - All the Free Software and Linux community, the FSF & the GNU
+          project, the MIT X consortium, the TeX people ... everyone!
+          You know who you are!
+
+        - Big thanks to Richard Stallman for creating Emacs!
+
+        - The people at the linux-usb mailing list, for reading so
+          many messages :) Ok, no more kidding; for all your advices!
+
+        - All the people at the USB Implementors Forum for their
+          help and assistance.
+
+        - Nathan Myers <ncm@cantrip.org>, for his advice! (hope you
+          liked Cibeles' party).
+
+        - Linus Torvalds, for starting, developing and managing Linux.
+
+        - Mike Smith, Craig Keithley, Thierry Giron and Janet Schank
+          for convincing me USB Standard hubs are not that standard
+          and that's good to allow for vendor specific quirks on the
+          standard hub driver.
 
diff -urN linux-2.2.8-pre7/drivers/usb/README.ohci linux/drivers/usb/README.ohci
--- linux-2.2.8-pre7/drivers/usb/README.ohci	Sat Apr 24 04:40:07 1999
+++ linux/drivers/usb/README.ohci	Mon Dec  3 18:46:55 2001
@@ -1,8 +1,26 @@
-April 24, 1999 04:37:42 PST
+May 09, 1999 16:25:58
 
-Okay, I've written a lot more of the OHCI code and actually got it back to
-a compiling state now with all of the recent improvements to the way stuff
-is structured.  It is completely untested.
+Cool, things are working "well" now.  (I'm not getting oops's from the
+OHCI code anyways.. ;).  I can attach a usb hub and mouse in any
+possible arrangement of the two and they get configured properly.
+
+You can see that the mouse Interrupt transfers are occuring and being
+acknowledged because /proc/interrupts usb-ohci goes up accordingly with
+mouse movements/events.  That means the TD at least returns some data
+and requeues itself.
+
+Device attach/detach from the root hub is not working well.  Currently
+every interrupt checks for root hub status changes and frame number
+overflow interrupts are enabled.  This means you shouldn't have to
+wait more than 32-33 seconds for the change to occur, less if there is
+other activity.  (due to checking in the WDH caused interrupts)
+My OHCI controller [SiS 5598 motherboard] doesn't seem to play well
+with the RHSC interrupt so it has been disabled.  The ohci_timer
+should be polling but it not currently working, I haven't had time to
+look into that problem.
+
+However, when I tried telling X to use /dev/psaux for the mouse my
+machine locked up...
 
 - greg@electricrain.com
 
diff -urN linux-2.2.8-pre7/drivers/usb/ohci-debug.c linux/drivers/usb/ohci-debug.c
--- linux-2.2.8-pre7/drivers/usb/ohci-debug.c	Mon Apr 26 12:52:33 1999
+++ linux/drivers/usb/ohci-debug.c	Mon Dec  3 18:46:55 2001
@@ -14,40 +14,58 @@
 	struct ohci_regs regs;
 	int i;
 
-	regs.revision = readl(ohci->regs->revision);
-	regs.control = readl(ohci->regs->control);
-	regs.cmdstatus = readl(ohci->regs->cmdstatus);
-	regs.intrstatus = readl(ohci->regs->intrstatus);
-	regs.intrenable = readl(ohci->regs->intrenable);
-	regs.intrdisable = readl(ohci->regs->intrdisable);
-	regs.hcca = readl(ohci->regs->hcca);
-	regs.ed_periodcurrent = readl(ohci->regs->ed_periodcurrent);
-	regs.ed_controlhead = readl(ohci->regs->ed_controlhead);
-	regs.ed_bulkhead = readl(ohci->regs->ed_bulkhead);
-	regs.ed_bulkcurrent = readl(ohci->regs->ed_bulkcurrent);
-	regs.current_donehead = readl(ohci->regs->current_donehead);
-	regs.fminterval = readl(ohci->regs->fminterval);
-	regs.fmremaining = readl(ohci->regs->fmremaining);
-	regs.fmnumber = readl(ohci->regs->fmnumber);
-	regs.periodicstart = readl(ohci->regs->periodicstart);
-	regs.lsthresh = readl(ohci->regs->lsthresh);
-	regs.roothub.a = readl(ohci->regs->roothub.a);
-	regs.roothub.b = readl(ohci->regs->roothub.b);
-	regs.roothub.status = readl(ohci->regs->roothub.status);
+	regs.revision = readl(&ohci->regs->revision);
+	regs.control = readl(&ohci->regs->control);
+	regs.cmdstatus = readl(&ohci->regs->cmdstatus);
+	regs.intrstatus = readl(&ohci->regs->intrstatus);
+	regs.intrenable = readl(&ohci->regs->intrenable);
+	regs.hcca = readl(&ohci->regs->hcca);
+	regs.ed_periodcurrent = readl(&ohci->regs->ed_periodcurrent);
+	regs.ed_controlhead = readl(&ohci->regs->ed_controlhead);
+	regs.ed_controlcurrent = readl(&ohci->regs->ed_controlcurrent);
+	regs.ed_bulkhead = readl(&ohci->regs->ed_bulkhead);
+	regs.ed_bulkcurrent = readl(&ohci->regs->ed_bulkcurrent);
+	regs.current_donehead = readl(&ohci->regs->current_donehead);
+	regs.fminterval = readl(&ohci->regs->fminterval);
+	regs.fmremaining = readl(&ohci->regs->fmremaining);
+	regs.fmnumber = readl(&ohci->regs->fmnumber);
+	regs.periodicstart = readl(&ohci->regs->periodicstart);
+	regs.lsthresh = readl(&ohci->regs->lsthresh);
+	regs.roothub.a = readl(&ohci->regs->roothub.a);
+	regs.roothub.b = readl(&ohci->regs->roothub.b);
+	regs.roothub.status = readl(&ohci->regs->roothub.status);
 	for (i=0; i<MAX_ROOT_PORTS; ++i)
-		regs.roothub.portstatus[i] = readl(ohci->regs->roothub.portstatus[i]);
+		regs.roothub.portstatus[i] = readl(&ohci->regs->roothub.portstatus[i]);
 
-	printk("  ohci revision    =  0x%x\n", regs.revision);
-	printk("  ohci control     =  0x%x\n", regs.control);
-	printk("  ohci cmdstatus   =  0x%x\n", regs.cmdstatus);
-	printk("  ohci intrstatus  =  0x%x\n", regs.intrstatus);
-	printk("  ohci roothub.a   =  0x%x\n", regs.roothub.a);
-	printk("  ohci roothub.b   =  0x%x\n", regs.roothub.b);
-	printk("  ohci root status =  0x%x\n", regs.roothub.status);
+	printk(KERN_DEBUG "  ohci revision    =  %x\n", regs.revision);
+	printk(KERN_DEBUG "  ohci control     =  %x\n", regs.control);
+	printk(KERN_DEBUG "  ohci cmdstatus   =  %x\n", regs.cmdstatus);
+	printk(KERN_DEBUG "  ohci intrstatus  =  %x\n", regs.intrstatus);
+	printk(KERN_DEBUG "  ohci intrenable  =  %x\n", regs.intrenable);
+
+	printk(KERN_DEBUG "  ohci hcca        =  %x\n", regs.hcca);
+	printk(KERN_DEBUG "  ohci ed_pdcur    =  %x\n", regs.ed_periodcurrent);
+	printk(KERN_DEBUG "  ohci ed_ctrlhead =  %x\n", regs.ed_controlhead);
+	printk(KERN_DEBUG "  ohci ed_ctrlcur  =  %x\n", regs.ed_controlcurrent);
+	printk(KERN_DEBUG "  ohci ed_bulkhead =  %x\n", regs.ed_bulkhead);
+	printk(KERN_DEBUG "  ohci ed_bulkcur  =  %x\n", regs.ed_bulkcurrent);
+	printk(KERN_DEBUG "  ohci curdonehead =  %x\n", regs.current_donehead);
+
+	printk(KERN_DEBUG "  ohci fminterval  =  %x\n", regs.fminterval);
+	printk(KERN_DEBUG "  ohci fmremaining =  %x\n", regs.fmremaining);
+	printk(KERN_DEBUG "  ohci fmnumber    =  %x\n", regs.fmnumber);
+	printk(KERN_DEBUG "  ohci pdstart     =  %x\n", regs.periodicstart);
+	printk(KERN_DEBUG "  ohci lsthresh    =  %x\n", regs.lsthresh);
+
+	printk(KERN_DEBUG "  ohci roothub.a   =  %x\n", regs.roothub.a);
+	printk(KERN_DEBUG "  ohci roothub.b   =  %x\n", regs.roothub.b);
+	printk(KERN_DEBUG "  ohci root status =  %x\n", regs.roothub.status);
+	printk(KERN_DEBUG "    roothub.port0  =  %x\n", regs.roothub.portstatus[0]);
+	printk(KERN_DEBUG "    roothub.port1  =  %x\n", regs.roothub.portstatus[1]);
 } /* show_ohci_status() */
 
 
-static void show_ohci_ed(struct ohci_ed *ed)
+void show_ohci_ed(struct ohci_ed *ed)
 {
 	int stat = ed->status;
 	int skip = (stat & OHCI_ED_SKIP);
@@ -57,82 +75,103 @@
 	int dir = (stat & OHCI_ED_D);
 	int endnum = (stat & OHCI_ED_EN) >> 7;
 	int funcaddr = (stat & OHCI_ED_FA);
-	int halted = (ed->head_td & 1);
-	int toggle = (ed->head_td & 2) >> 1;
+	int halted = (ed->_head_td & 1);
+	int toggle = (ed->_head_td & 2) >> 1;
 
-	printk("   ohci ED:\n");
-	printk("     status     =  0x%x\n", stat);
-	printk("       %sMPS %d%s%s%s%s tc%d e%d fa%d\n",
+	printk(KERN_DEBUG "   ohci ED:\n");
+	printk(KERN_DEBUG "     status     =  0x%x\n", stat);
+	printk(KERN_DEBUG "       %sMPS %d%s%s%s%s tc%d e%d fa%d\n",
 			skip ? "Skip " : "",
 			mps,
 			isoc ? "Isoc. " : "",
-			low_speed ? "LowSpd " : "",
-			(dir == OHCI_ED_D_IN) ? "Input " :
-			(dir == OHCI_ED_D_OUT) ? "Output " : "",
-			halted ? "Halted " : "",
+			low_speed ? " LowSpd" : "",
+			(dir == OHCI_ED_D_IN) ? " Input" :
+			(dir == OHCI_ED_D_OUT) ? " Output" : "",
+			halted ? " Halted" : "",
 			toggle,
 			endnum,
 			funcaddr);
-	printk("     tail_td    =  0x%x\n", ed->tail_td);
-	printk("     head_td    =  0x%x\n", ed->head_td);
-	printk("     next_ed    =  0x%x\n", ed->next_ed);
+	printk(KERN_DEBUG "     tail_td    =  0x%x\n", ed->tail_td);
+	printk(KERN_DEBUG "     head_td    =  0x%x\n", ed_head_td(ed));
+	printk(KERN_DEBUG "     next_ed    =  0x%x\n", ed->next_ed);
 } /* show_ohci_ed() */
 
 
-static void show_ohci_td(struct ohci_td *td)
+void show_ohci_td(struct ohci_td *td)
 {
 	int td_round = td->info & OHCI_TD_ROUND;
 	int td_dir = td->info & OHCI_TD_D;
-	int td_int_delay = td->info & OHCI_TD_IOC_DELAY;
-	int td_toggle = td->info & OHCI_TD_DT;
-	int td_errcnt = td_errorcount(td->info);
-	int td_cc = td->info & OHCI_TD_CC;
-
-	printk("   ohci TD hardware fields:\n");
-	printk("      info     =  0x%x\n", td->info);
-	printk("        %s%s%s%d%s%s%d%s%d\n",
+	int td_int_delay = (td->info & OHCI_TD_IOC_DELAY) >> 21;
+	int td_toggle = (td->info & OHCI_TD_DT) >> 24;
+	int td_errcnt = td_errorcount(*td);
+	int td_cc = OHCI_TD_CC_GET(td->info);
+
+	printk(KERN_DEBUG "   ohci TD hardware fields:\n");
+	printk(KERN_DEBUG "      info     =  0x%x\n", td->info);
+	printk(KERN_DEBUG "        %s%s%s%d %s\n",
 		td_round ? "Rounding " : "",
 		(td_dir == OHCI_TD_D_IN) ? "Input " :
 		(td_dir == OHCI_TD_D_OUT) ? "Output " :
 		(td_dir == OHCI_TD_D_SETUP) ? "Setup " : "",
-		"IntDelay ", td_int_delay >> 21,
-		td_toggle ? "Data1 " : "Data0 ",
+		"IntDelay ", td_int_delay,
+		(td_toggle < 2) ? " " :
+		(td_toggle & 1) ? "Data1 " : "Data0 ");
+	printk(KERN_DEBUG "        %s%d %s0x%x, %sAccessed, %sActive\n",
 		"ErrorCnt ", td_errcnt,
-		"ComplCode ", td_cc);
-	printk("       %sAccessed, %sActive\n",
-			td_cc_accessed(td->info) ? "" : "Not ",
-			td_active(td->info) ? "" : "Not ");
-
-	printk("      cur_buf  =  0x%x\n", td->cur_buf);
-	printk("      next_td  =  0x%x\n", td->next_td);
-	printk("      buf_end  =  0x%x\n", td->buf_end);
-	printk("   ohci TD driver fields:\n");
-	printk("      data     =  %p\n", td->data);
-	printk("      dev_id   =  %p\n", td->dev_id);
-	printk("      ed_bus   =  %x\n", td->ed_bus);
+		"ComplCode ", td_cc,
+		td_cc_accessed(*td) ? "" : "Not ",
+		td_active(*td) ? "" : "Not ");
+
+	printk(KERN_DEBUG "      cur_buf  =  0x%x\n", td->cur_buf);
+	printk(KERN_DEBUG "      next_td  =  0x%x\n", td->next_td);
+	printk(KERN_DEBUG "      buf_end  =  0x%x\n", td->buf_end);
+	printk(KERN_DEBUG "   ohci TD driver fields:\n");
+	printk(KERN_DEBUG "      data     =  %p\n", td->data);
+	printk(KERN_DEBUG "      dev_id   =  %p\n", td->dev_id);
+	printk(KERN_DEBUG "      ed       =  %p\n", td->ed);
+	if (td->data != NULL) {
+	unsigned char *d = td->data;
+	printk(KERN_DEBUG "   DATA: %02x %02x %02x %02x %02x %02x %02x %02x\n",
+			d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7] );
+	}
 } /* show_ohci_td() */
 
 
 void show_ohci_device(struct ohci_device *dev)
 {
 	int idx;
-	printk("  ohci_device usb       =  %p\n", dev->usb);
-	printk("  ohci_device ohci      =  %p\n", dev->ohci);
-	printk("  ohci_device ohci_hcca =  %p\n", dev->hcca);
-	for (idx=0; idx<8 /*NUM_EDS*/; ++idx) {
-		printk("   [ed num %d] ", idx);
+	printk(KERN_DEBUG "  ohci_device usb       =  %p\n", dev->usb);
+	printk(KERN_DEBUG "  ohci_device ohci      =  %p\n", dev->ohci);
+	printk(KERN_DEBUG "  ohci_device ohci_hcca =  %p\n", dev->hcca);
+	for (idx=0; idx<3 /*NUM_EDS*/; ++idx) {
+		printk(KERN_DEBUG "   [ed num %d] ", idx);
 		show_ohci_ed(&dev->ed[idx]);
 	}
-	for (idx=0; idx<8 /*NUM_TDS*/; ++idx) {
-		printk("   [td num %d] ", idx);
+	for (idx=0; idx<3 /*NUM_TDS*/; ++idx) {
+		printk(KERN_DEBUG "   [td num %d] ", idx);
 		show_ohci_td(&dev->td[idx]);
 	}
-	printk("  ohci_device data\n    ");
+	printk(KERN_DEBUG "  ohci_device data\n    ");
 	for (idx=0; idx<4; ++idx) {
-		printk(" %08lx", dev->data[idx]);
+		printk(KERN_DEBUG " %08lx", dev->data[idx]);
 	}
-	printk("\n");
+	printk(KERN_DEBUG "\n");
 } /* show_ohci_device() */
+
+
+void show_ohci_hcca(struct ohci_hcca *hcca)
+{
+	int idx;
+
+	printk(KERN_DEBUG "  ohci_hcca\n");
+
+	for (idx=0; idx<NUM_INTS; idx++) {
+		printk(KERN_DEBUG "    int_table[%2d]  == %p\n", idx, hcca->int_table +idx);
+	}
+
+	printk(KERN_DEBUG "    frame_no          == %d\n", hcca->frame_no);
+	printk(KERN_DEBUG "    donehead          == 0x%08x\n", hcca->donehead);
+} /* show_ohci_hcca() */
 
 
 /* vim:sw=8
diff -urN linux-2.2.8-pre7/drivers/usb/ohci-hcd.c linux/drivers/usb/ohci-hcd.c
--- linux-2.2.8-pre7/drivers/usb/ohci-hcd.c	Mon Dec  3 18:46:27 2001
+++ linux/drivers/usb/ohci-hcd.c	Mon Dec  3 18:46:55 2001
@@ -32,6 +32,7 @@
 /* #define OHCI_DBG  */  /* printk some debug information */
 
  
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/kernel.h>
diff -urN linux-2.2.8-pre7/drivers/usb/ohci-hcd.h linux/drivers/usb/ohci-hcd.h
--- linux-2.2.8-pre7/drivers/usb/ohci-hcd.h	Mon Dec  3 18:46:27 2001
+++ linux/drivers/usb/ohci-hcd.h	Mon Dec  3 18:46:55 2001
@@ -22,6 +22,8 @@
  * ohci-hcd.h
  */
 
+#include <linux/config.h>
+
 #ifdef CONFIG_USB_OHCI_VROOTHUB
 #define VROOTHUB  
 #endif
diff -urN linux-2.2.8-pre7/drivers/usb/ohci.c linux/drivers/usb/ohci.c
--- linux-2.2.8-pre7/drivers/usb/ohci.c	Mon Apr 26 12:57:22 1999
+++ linux/drivers/usb/ohci.c	Mon Dec  3 18:46:55 2001
@@ -29,7 +29,7 @@
  *
  * No filesystems were harmed in the development of this code.
  *
- * $Id: ohci.c,v 1.11 1999/04/25 00:18:52 greg Exp $
+ * $Id: ohci.c,v 1.26 1999/05/11 07:34:47 greg Exp $
  */
 
 #include <linux/config.h>
@@ -59,6 +59,10 @@
 
 static struct wait_queue *ohci_configure = NULL;
 
+#ifdef OHCI_TIMER
+static struct timer_list ohci_timer;	/* timer for root hub polling */
+#endif
+
 
 static int ohci_td_result(struct ohci_device *dev, struct ohci_td *td)
 {
@@ -69,86 +73,258 @@
 	/* TODO Debugging code for TD failures goes here */
 
 	return status;
-}
+} /* ohci_td_result() */
 
 
 static spinlock_t ohci_edtd_lock = SPIN_LOCK_UNLOCKED;
 
 /*
- * Add a TD to the end of the TD list on a given ED.  td->next_td is
- * assumed to be set correctly for the situation of no TDs already
- * being on the list (ie: pointing to NULL).
+ * Add a TD to the end of the TD list on a given ED.  If td->next_td
+ * points to any more TDs, they will be added as well (naturally).
+ * Otherwise td->next_td must be 0.
+ * 
+ * The SKIP flag will be cleared after this function.
+ *
+ * Important!  This function needs locking and atomicity as it works
+ * in parallel with the HC's DMA.  Locking ohci_edtd_lock while using
+ * the function is a must.
+ *
+ * This function can be called by the interrupt handler.
  */
 static void ohci_add_td_to_ed(struct ohci_td *td, struct ohci_ed *ed)
 {
-	struct ohci_td *tail = bus_to_virt(ed->tail_td);
-	struct ohci_td *head = bus_to_virt(ed->head_td);
-	unsigned long flags;
+	/* don't let the HC pull anything from underneath us */
+	ed->status |= OHCI_ED_SKIP;
 
-	spin_lock_irqsave(&ohci_edtd_lock, flags);
-
-	if (tail == head) {	/* empty list, put it on the head */
-		head = (struct ohci_td *) virt_to_bus(td);
-		tail = 0;
+	if (ed_head_td(ed) == 0) {	/* empty list, put it on the head */
+		set_ed_head_td(ed, virt_to_bus(td));
+		ed->tail_td = 0;
 	} else {
+		struct ohci_td *tail, *head;
+		head = (ed_head_td(ed) == 0) ? NULL : bus_to_virt(ed_head_td(ed));
+		tail = (ed->tail_td == 0) ? NULL : bus_to_virt(ed->tail_td);
 		if (!tail) {	/* no tail, single element list */
 			td->next_td = head->next_td;
 			head->next_td = virt_to_bus(td);
-			tail = (struct ohci_td *) virt_to_bus(td);
+			ed->tail_td = virt_to_bus(td);
 		} else {	/* append to the list */
 			td->next_td = tail->next_td;
 			tail->next_td = virt_to_bus(td);
-			tail = (struct ohci_td *) virt_to_bus(td);
+			ed->tail_td = virt_to_bus(td);
 		}
 	}
-	/* save the reverse link */
-	td->ed_bus = virt_to_bus(ed);
 
-	spin_unlock_irqrestore(&ohci_edtd_lock, flags);
+	/* save the ED link in each of the TDs added */
+	td->ed = ed;
+	while (td->next_td != 0) {
+		td = bus_to_virt(td->next_td);
+		td->ed = ed;
+	}
+
+	/* turn off the SKIP flag */
+	ed->status &= ~OHCI_ED_SKIP;
 } /* ohci_add_td_to_ed() */
 
 
+inline void ohci_start_control(struct ohci *ohci)
+{
+	/* tell the HC to start processing the control list */
+	writel(OHCI_CMDSTAT_CLF, &ohci->regs->cmdstatus);
+}
+
+inline void ohci_start_bulk(struct ohci *ohci)
+{
+	/* tell the HC to start processing the bulk list */
+	writel(OHCI_CMDSTAT_BLF, &ohci->regs->cmdstatus);
+}
+
+inline void ohci_start_periodic(struct ohci *ohci)
+{
+	/* enable processing periodc transfers starting next frame */
+	writel_set(OHCI_USB_PLE, &ohci->regs->control);
+}
+
+inline void ohci_start_isoc(struct ohci *ohci)
+{
+	/* enable processing isoc. transfers starting next frame */
+	writel_set(OHCI_USB_IE, &ohci->regs->control);
+}
+
 /*
- *  Remove a TD from the given EDs TD list
+ * Add an ED to the hardware register ED list pointed to by hw_listhead_p
+ */
+static void ohci_add_ed_to_hw(struct ohci_ed *ed, void* hw_listhead_p)
+{
+	__u32 listhead;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ohci_edtd_lock, flags);
+	
+	listhead = readl(hw_listhead_p);
+
+	/* if the list is not empty, insert this ED at the front */
+	/* XXX should they go on the end? */
+	if (listhead) {
+		ed->next_ed = listhead;
+	}
+
+	/* update the hardware listhead pointer */
+	writel(virt_to_bus(ed), hw_listhead_p);
+
+	spin_unlock_irqrestore(&ohci_edtd_lock, flags);
+} /* ohci_add_ed() */
+
+
+/*
+ *  Put another control ED on the controller's list
+ */
+void ohci_add_control_ed(struct ohci *ohci, struct ohci_ed *ed)
+{
+	ohci_add_ed_to_hw(ed, &ohci->regs->ed_controlhead);
+	ohci_start_control(ohci);
+} /* ohci_add_control_ed() */
+
+
+#if 0
+/*
+ *  Put another control ED on the controller's list
+ */
+void ohci_add_periodic_ed(struct ohci *ohci, struct ohci_ed *ed, int period)
+{
+	ohci_add_ed_to_hw(ed, /* XXX */);
+	ohci_start_periodic(ohci);
+} /* ohci_add_control_ed() */
+#endif
+
+
+/*
+ *  Remove an ED from the HC list whos bus headpointer is pointed to
+ *  by hw_listhead_p
+ *  
+ *  Note that the SKIP bit is left on in the removed ED.
+ */
+void ohci_remove_ed_from_hw(struct ohci_ed *ed, __u32* hw_listhead_p)
+{
+	unsigned long flags;
+	struct ohci_ed *cur;
+	__u32 bus_ed = virt_to_bus(ed);
+	__u32 bus_cur;
+
+	if (ed == NULL || !bus_ed)
+		return;
+
+	/* tell the controller this skip ED */
+	ed->status |= OHCI_ED_SKIP;
+
+	bus_cur = readl(hw_listhead_p);
+
+	if (bus_cur == 0)
+		return;   /* the list is already empty */
+
+	cur = bus_to_virt(bus_cur);
+
+	spin_lock_irqsave(&ohci_edtd_lock, flags);
+
+	/* if its the head ED, move the head */
+	if (bus_cur == bus_ed) {
+		writel(cur->next_ed, hw_listhead_p);
+	} else if (cur->next_ed != 0) {
+		struct ohci_ed *prev;
+
+		/* walk the list and unlink the ED if found */
+		for (;;) {
+			prev = cur;
+			cur = bus_to_virt(cur->next_ed);
+
+			if (virt_to_bus(cur) == bus_ed) {
+				/* unlink from the list */
+				prev->next_ed = cur->next_ed;
+				break;
+			}
+
+			if (cur->next_ed == 0)
+				break;
+		}
+	}
+
+	/* clear any links from the ED for safety */
+	ed->next_ed = 0;
+
+	spin_unlock_irqrestore(&ohci_edtd_lock, flags);
+} /* ohci_remove_ed_from_hw() */
+
+/*
+ *  Remove an ED from the controller's control list.  Note that the SKIP bit
+ *  is left on in the removed ED.
+ */
+inline void ohci_remove_control_ed(struct ohci *ohci, struct ohci_ed *ed)
+{
+	ohci_remove_ed_from_hw(ed, &ohci->regs->ed_controlhead);
+}
+
+/*
+ *  Remove an ED from the controller's bulk list.  Note that the SKIP bit
+ *  is left on in the removed ED.
+ */
+inline void ohci_remove_bulk_ed(struct ohci *ohci, struct ohci_ed *ed)
+{
+	ohci_remove_ed_from_hw(ed, &ohci->regs->ed_bulkhead);
+}
+
+
+/*
+ *  Remove a TD from the given EDs TD list.
  */
 static void ohci_remove_td_from_ed(struct ohci_td *td, struct ohci_ed *ed)
 {
-	struct ohci_td *head = bus_to_virt(ed->head_td);
-	struct ohci_td *tmp_td;
 	unsigned long flags;
+	struct ohci_td *head_td;
+
+	if ((td == NULL) || (ed == NULL))
+		return;
 
 	spin_lock_irqsave(&ohci_edtd_lock, flags);
 
+	if (ed_head_td(ed) == 0)
+		return;
+
 	/* set the "skip me bit" in this ED */
-	writel_set(OHCI_ED_SKIP, ed->status);
+	ed->status |= OHCI_ED_SKIP;
 
 	/* XXX Assuming this list will never be circular */
 
-	if (td == head) {
-		/* unlink this TD; it was at the beginning */
-		ed->head_td = head->next_td;
-	}
-
-	tmp_td = head;
-	head = (struct ohci_td *) ed->head_td;
-	
-	while (head != NULL) {
+	head_td = bus_to_virt(ed_head_td(ed));
+	if (virt_to_bus(td) == ed_head_td(ed)) {
+		/* It's the first TD, remove it. */
+		set_ed_head_td(ed, head_td->next_td);
+	} else {
+		struct ohci_td *prev_td, *cur_td;
 
-		if (td == head) {
-			/* unlink this TD from the middle or end */
-			tmp_td->next_td = head->next_td;
+		/* FIXME: collapse this into a nice simple loop :) */
+		if (head_td->next_td != 0) {
+			prev_td = head_td;
+			cur_td = bus_to_virt(head_td->next_td);
+			for (;;) {
+				if (td == cur_td) {
+					/* remove it */
+					prev_td->next_td = cur_td->next_td;
+					break;
+				}
+				if (cur_td->next_td == 0)
+					break;
+				prev_td = cur_td;
+				cur_td = bus_to_virt(cur_td->next_td);
+			}
 		}
-
-		tmp_td = head;
-		head = bus_to_virt(head->next_td);
 	}
 
-	td->next_td = virt_to_bus(NULL);  /* remove links to ED list */
+	td->next_td = 0;  /* remove the TDs links */
+	td->ed = NULL;
 
-	/* XXX mark this TD for possible cleanup? */
+	/* TODO return this TD to the pool of free TDs */
 
 	/* unset the "skip me bit" in this ED */
-	writel_mask(~(__u32)OHCI_ED_SKIP, ed->status);
+	ed->status &= ~OHCI_ED_SKIP;
 
 	spin_unlock_irqrestore(&ohci_edtd_lock, flags);
 } /* ohci_remove_td_from_ed() */
@@ -165,60 +341,67 @@
 	int idx;
 
 	for (idx=0; idx < NUM_TDS; idx++) {
-		if (td_done(dev->td[idx].info)) {
-			/* XXX should this also zero out the structure? */
-			/* mark all new TDs as unaccessed */
-			dev->td[idx].info = OHCI_TD_CC_NEW;
-			return &dev->td[idx];
+		if (!td_allocated(dev->td[idx])) {
+			struct ohci_td *new_td = &dev->td[idx];
+			/* zero out the TD */
+			memset(new_td, 0, sizeof(*new_td));
+			/* mark the new TDs as unaccessed */
+			new_td->info = OHCI_TD_CC_NEW;
+			/* mark it as allocated */
+			allocate_td(new_td);
+			return new_td;
 		}
 	}
 
+	printk("usb-ohci error: unable to allocate a TD\n");
 	return NULL;
 } /* ohci_get_free_td() */
 
 
-/**********************************
- * OHCI interrupt list operations *
- **********************************/
-static spinlock_t irqlist_lock = SPIN_LOCK_UNLOCKED;
-
-static void ohci_add_irq_list(struct ohci *ohci, struct ohci_td *td, usb_device_irq completed, void *dev_id)
+/*
+ *  Initialize a TD
+ *
+ * 	dir = OHCI_TD_D_IN, OHCI_TD_D_OUT, or OHCI_TD_D_SETUP
+ * 	toggle = TOGGLE_AUTO, TOGGLE_DATA0, TOGGLE_DATA1
+ */
+inline struct ohci_td *ohci_fill_new_td(struct ohci_td *td, int dir, int toggle, __u32 flags, void *data, __u32 len, void *dev_id, usb_device_irq completed)
 {
-	unsigned long flags;
+	/* hardware fields */
+	td->info = OHCI_TD_CC_NEW |
+		(dir & OHCI_TD_D) |
+		(toggle & OHCI_TD_DT) |
+		flags;
+	td->cur_buf = (data == NULL) ? 0 : virt_to_bus(data);
+	td->buf_end = (len == 0) ? 0 : td->cur_buf + len - 1;
 
-	/* save the irq in our private portion of the TD */
-	td->completed = completed;
+	/* driver fields */
+	td->data = data;
 	td->dev_id = dev_id;
+	td->completed = completed;
 
-	spin_lock_irqsave(&irqlist_lock, flags);
-	list_add(&td->irq_list, &ohci->interrupt_list);
-	spin_unlock_irqrestore(&irqlist_lock, flags);
-} /* ohci_add_irq_list() */
+	return td;
+} /* ohci_fill_new_td() */
 
-static void ohci_remove_irq_list(struct ohci_td *td)
-{
-	unsigned long flags;
 
-	spin_lock_irqsave(&irqlist_lock, flags);
-	list_del(&td->irq_list);
-	spin_unlock_irqrestore(&irqlist_lock, flags);
-} /* ohci_remove_irq_list() */
+/**********************************
+ * OHCI interrupt list operations *
+ **********************************/
 
 /*
  * Request an interrupt handler for one "pipe" of a USB device.
  * (this function is pretty minimal right now)
  *
  * At the moment this is only good for input interrupts. (ie: for a
- * mouse)
+ * mouse or keyboard)
  *
- * period is desired polling interval in ms.  The closest, shorter
+ * Period is desired polling interval in ms.  The closest, shorter
  * match will be used.  Powers of two from 1-32 are supported by OHCI.
  */
 static int ohci_request_irq(struct usb_device *usb, unsigned int pipe,
 	usb_device_irq handler, int period, void *dev_id)
 {
 	struct ohci_device *dev = usb_to_ohci(usb);
-	struct ohci_td *td = dev->td;	/* */
+	struct ohci_td *td;
 	struct ohci_ed *interrupt_ed;	/* endpoint descriptor for this irq */
 
 	/*
@@ -239,42 +422,68 @@
 		usb_pipe_endpdev(pipe) |
 		OHCI_ED_F_NORM;
 
+	td = ohci_get_free_td(dev);
+	/* FIXME: check for NULL */
+
+	/* Fill in the TD */
+	ohci_fill_new_td(td, td_set_dir_out(usb_pipeout(pipe)),
+			TOGGLE_AUTO,
+			OHCI_TD_ROUND,
+			dev->data, DATA_BUF_LEN,
+			dev_id, handler);
 	/*
-	 * Set the not accessed condition code, allow odd sized data,
-	 * and set the data transfer direction.
+	 * TODO: be aware that OHCI won't advance out of the 4kb
+	 * page cur_buf started in.  It'll wrap around to the start
+	 * of the page...  annoying or useful? you decide.
+	 *
+	 * We should make sure dev->data doesn't cross a page...
 	 */
-	td->info = OHCI_TD_CC_NEW | OHCI_TD_ROUND |
-		td_set_dir_out(usb_pipeout(pipe));
 
-	/* point it to our data buffer */
-	td->cur_buf = virt_to_bus(dev->data);
+	/* FIXME: this just guarantees that its the end of the list */
+	td->next_td = 0;
 
-	/* FIXME: we're only using 1 TD right now! */
-	td->next_td = virt_to_bus(&td);
+	/* Linus did this. see asm/system.h; scary concept... I don't
+	 * know if its needed here or not but it won't hurt. */
+	wmb();
 
 	/*
-	 * FIXME: be aware that OHCI won't advance out of the 4kb
-	 * page cur_buf started in.  It'll wrap around to the start
-	 * of the page...  annoying or useful? you decide.
-	 *
-	 * A pointer to the last *byte* in the buffer (ergh.. we get
-	 * to work around C's pointer arithmatic here with a typecast)
+	 *  Put the TD onto our ED
 	 */
-	td->buf_end = virt_to_bus(((u8*)(dev->data + DATA_BUF_LEN)) - 1);
+	{
+		unsigned long flags;
+		spin_lock_irqsave(&ohci_edtd_lock, flags);
+		ohci_add_td_to_ed(td, interrupt_ed);
+		spin_unlock_irqrestore(&ohci_edtd_lock, flags);
+	}
 
-	/* does this make sense for ohci?.. time to think.. */
-	ohci_add_irq_list(dev->ohci, td, handler, dev_id);
-	wmb();     /* found in asm/system.h; scary concept... */
-	ohci_add_td_to_ed(td, interrupt_ed);
+#if 0
+	/* Assimilate the new ED into the collective */
+	/*
+	 *  When dynamic ED allocation is done, this call will be
+	 *  useful.  For now, the correct ED already on the
+	 *  controller's proper periodic ED lists was chosen above.
+	 */
+	ohci_add_periodic_ed(dev->ohci, interrupt_ed, period);
+#else
+	/* enable periodic (interrupt) transfers on the HC */
+	ohci_start_periodic(dev->ohci);
+#endif
 
 	return 0;
 } /* ohci_request_irq() */
 
+
 /*
  * Control thread operations:
  */
 static struct wait_queue *control_wakeup;
 
+/*
+ *  This is the handler that gets called when a control transaction
+ *  completes.
+ *
+ *  This function is called from the interrupt handler.
+ */
 static int ohci_control_completed(int stats, void *buffer, void *dev_id)
 {
 	wake_up(&control_wakeup);
@@ -283,41 +492,16 @@
 
 
 /*
- * Run a control transaction from the root hub's control endpoint.
- * The passed in TD is the control transfer's Status TD.
- */
-static int ohci_run_control(struct ohci_device *dev, struct ohci_td *status_td)
-{
-	struct wait_queue wait = { current, NULL };
-	struct ohci_ed *control_ed = &dev->ohci->root_hub->ed[ED_CONTROL];
-
-	current->state = TASK_UNINTERRUPTIBLE;
-	add_wait_queue(&control_wakeup, &wait);
-
-	ohci_add_irq_list(dev->ohci, status_td, ohci_control_completed, NULL);
-	ohci_add_td_to_ed(status_td, control_ed);
-
-	/* FIXME? isn't this a little gross */
-	schedule_timeout(HZ/10);
-
-	ohci_remove_irq_list(status_td);
-	ohci_remove_td_from_ed(status_td, control_ed);
-
-	return ohci_td_result(dev, status_td);
-} /* ohci_run_control() */
-
-/*
  * Send or receive a control message on a "pipe"
  *
+ * The cmd parameter is a pointer to the 8 byte setup command to be
+ * sent.  FIXME:  This is a devrequest in usb.h.  The function
+ * should be updated to accept a devrequest* instead of void*..
+ *
  * A control message contains:
  *   - The command itself
- *   - An optional data phase
+ *   - An optional data phase (if len > 0)
  *   - Status complete phase
- *
- * The data phase can be an arbitrary number of TD's.  Currently since
- * we use statically allocated TDs if too many come in we'll just
- * start tossing them and printk() some warning goo...  Most control
- * messages won't have much data anyways.
  */
 static int ohci_control_msg(struct usb_device *usb, unsigned int pipe, void *cmd, void *data, int len)
 {
@@ -330,10 +514,12 @@
 	 * anyways? ;)
 	 */
 	struct ohci_ed *control_ed = &dev->ohci->root_hub->ed[ED_CONTROL];
-	struct ohci_td *control_td;
-	struct ohci_td *data_td;
-	struct ohci_td *last_td;
-	__u32 data_td_info;
+	struct ohci_td *setup_td, *data_td, *status_td;
+	struct wait_queue wait = { current, NULL };
+
+#if 0
+	printk(KERN_DEBUG "entering ohci_control_msg %p (ohci_dev: %p) pipe 0x%x, cmd %p, data %p, len %d\n", usb, dev, pipe, cmd, data, len);
+#endif
 
 	/*
 	 * Set the max packet size, device speed, endpoint number, usb
@@ -351,95 +537,174 @@
 	 */
 
 	/* get a TD to send this control message with */
-	control_td = ohci_get_free_td(dev);
+	setup_td = ohci_get_free_td(dev);
 	/* TODO check for NULL */
 
 	/*
 	 * Set the not accessed condition code, allow odd sized data,
 	 * and set the data transfer type to SETUP.  Setup DATA always
 	 * uses a DATA0 packet.
-	 */
-	control_td->info = OHCI_TD_CC_NEW | OHCI_TD_ROUND |
-		OHCI_TD_D_SETUP | OHCI_TD_IOC_OFF | td_force_toggle(0);
-
-	/* point it to the command */
-	control_td->cur_buf = virt_to_bus(cmd);
+	 *
+	 * The setup packet contains a devrequest (usb.h) which
+	 * will always be 8 bytes long.  FIXME: the cmd parameter
+	 * should be a pointer to one of these instead of a void* !!!
+	 */
+	ohci_fill_new_td(setup_td, OHCI_TD_D_SETUP, TOGGLE_DATA0,
+			OHCI_TD_IOC_OFF,
+			cmd, 8,		/* cmd is always 8 bytes long */
+			NULL, NULL);
 
-	/* link to a free TD for the control data input */
+	/* allocate the next TD */
 	data_td = ohci_get_free_td(dev);  /* TODO check for NULL */
-	control_td->next_td = virt_to_bus(data_td);
+
+	/* link to the next TD */
+	setup_td->next_td = virt_to_bus(data_td);
+
+	if (len > 0) {
+
+		/* build the Control DATA TD, it starts with a DATA1. */
+		ohci_fill_new_td(data_td, td_set_dir_out(usb_pipeout(pipe)),
+				TOGGLE_DATA1,
+				OHCI_TD_ROUND | OHCI_TD_IOC_OFF,
+				data, len,
+				NULL, NULL);
+
+		/*
+		 * XXX we should check that the data buffer doesn't
+		 * cross a 4096 byte boundary.  If so, it needs to be
+		 * copied into a single 4096 byte aligned area for the
+		 * OHCI's TD logic to see it all, or multiple TDs need
+		 * to be made for each page.
+		 *
+		 * It's not likely a control transfer will run into
+		 * this problem.. (famous last words)
+		 */
+
+		status_td = ohci_get_free_td(dev);  /* TODO check for NULL */
+		data_td->next_td = virt_to_bus(status_td);
+	} else {
+		status_td = data_td; /* no data_td, use it for status */
+	}
+
+	/* The control status packet always uses a DATA1 */
+	ohci_fill_new_td(status_td,
+			td_set_dir_in(usb_pipeout(pipe) | (len == 0)),
+			TOGGLE_DATA1,
+			0,
+			NULL, 0,
+			NULL, ohci_control_completed);
+	status_td->next_td = 0; /* end of TDs */
 
 	/*
-	 * Build the DATA TDs
+	 * Start the control transaction..
 	 */
+	current->state = TASK_UNINTERRUPTIBLE;
+	add_wait_queue(&control_wakeup, &wait);
 
-	data_td_info = OHCI_TD_CC_NEW | OHCI_TD_ROUND | OHCI_TD_IOC_OFF |
-		td_set_dir_out(usb_pipeout(pipe));
-
-	while (len > 0) {
-		int pktsize = len;
-		struct ohci_td *tmp_td;
+	/*
+	 * Add the chain of 2-3 control TDs to the control ED's TD list
+	 */
+	{
+		unsigned long flags;
+		spin_lock_irqsave(&ohci_edtd_lock, flags);
+		ohci_add_td_to_ed(setup_td, control_ed);
+		spin_unlock_irqrestore(&ohci_edtd_lock, flags);
+	}
+
+#if 0
+	/* complete transaction debugging output (before) */
+	printk(KERN_DEBUG " Control ED %lx:\n", virt_to_bus(control_ed));
+	show_ohci_ed(control_ed);
+	printk(KERN_DEBUG " Setup TD %lx:\n", virt_to_bus(setup_td));
+	show_ohci_td(setup_td);
+	if (data_td != status_td) {
+		printk(KERN_DEBUG " Data TD %lx:\n", virt_to_bus(data_td));
+		show_ohci_td(data_td);
+	}
+	printk(KERN_DEBUG " Status TD %lx:\n", virt_to_bus(status_td));
+	show_ohci_td(status_td);
+#endif
 
-		if (pktsize > usb_maxpacket(pipe))
-			pktsize = usb_maxpacket(pipe);
+	/* Give the ED to the HC */
+	ohci_add_control_ed(dev->ohci, control_ed);
 
-		/* set the data transaction type */
-		data_td->info = data_td_info;
-		/* point to the current spot in the data buffer */
-		data_td->cur_buf = virt_to_bus(data);
-		/* point to the end of this data */
-		data_td->buf_end = virt_to_bus(data+pktsize-1);
+	/* FIXME:
+	 * this should really check to see that the transaction completed.
+	 */
+	schedule_timeout(HZ/10);
 
-		/* allocate the next TD */
-		tmp_td = ohci_get_free_td(dev);  /* TODO check for NULL */
-		data_td->next_td = virt_to_bus(tmp_td);
-		data_td = tmp_td;
+	remove_wait_queue(&control_wakeup, &wait);
 
-		/* move on.. */
-		data += pktsize;
-		len -= pktsize;
+#if 0
+	/* complete transaction debugging output (after) */
+	printk(KERN_DEBUG " (after) Control ED:\n");
+	show_ohci_ed(control_ed);
+	printk(KERN_DEBUG " (after) Setup TD:\n");
+	show_ohci_td(setup_td);
+	if (data_td != status_td) {
+		printk(KERN_DEBUG " (after) Data TD:\n");
+		show_ohci_td(data_td);
 	}
+	printk(KERN_DEBUG " (after) Status TD:\n");
+	show_ohci_td(status_td);
+#endif
 
-	/* point it at the newly allocated TD from above */
-	last_td = data_td;
+	/* clean up incase it failed */
+	/* XXX only do this if their ed pointer still points to control_ed
+	 * incase they've been reclaimed and used by something else
+	 * already. -greg */
+	ohci_remove_td_from_ed(setup_td, control_ed);
+	ohci_remove_td_from_ed(data_td, control_ed);
+	ohci_remove_td_from_ed(status_td, control_ed);
 
-	/* The control status packet always uses a DATA1 */
-	last_td->info = OHCI_TD_CC_NEW | OHCI_TD_ROUND | td_force_toggle(1);
-	last_td->next_td = 0; /* end of TDs */
-	last_td->cur_buf = 0; /* no data in this packet */
-	last_td->buf_end = 0;
+	/* remove the control ED */
+	ohci_remove_control_ed(dev->ohci, control_ed);
 
-	/*
-	 * Start the control transaction.. give it the last TD so the
-	 * result can be returned.
-	 */
-	return ohci_run_control(dev, last_td);
+#if 0
+	printk(KERN_DEBUG "leaving ohci_control_msg\n");
+#endif
+
+	return ohci_td_result(dev, status_td);
 } /* ohci_control_msg() */
 
 
+/*
+ * Allocate a new USB device to be attached to an OHCI controller
+ */
 static struct usb_device *ohci_usb_allocate(struct usb_device *parent)
 {
 	struct usb_device *usb_dev;
 	struct ohci_device *dev;
 
+	/*
+	 * Allocate the generic USB device
+	 */
 	usb_dev = kmalloc(sizeof(*usb_dev), GFP_KERNEL);
 	if (!usb_dev)
 		return NULL;
 
 	memset(usb_dev, 0, sizeof(*usb_dev));
 
+	/*
+	 * Allocate an OHCI device (EDs and TDs for this device)
+	 */
 	dev = kmalloc(sizeof(*dev), GFP_KERNEL);
 	if (!dev) {
 		kfree(usb_dev);
 		return NULL;
 	}
 
-	/* Initialize "dev" */
 	memset(dev, 0, sizeof(*dev));
 
+	/*
+	 * Link them together
+	 */
 	usb_dev->hcpriv = dev;
 	dev->usb = usb_dev;
 
+	/*
+	 * Link the device to its parent (hub, etc..) if any.
+	 */
 	usb_dev->parent = parent;
 
 	if (parent) {
@@ -448,8 +713,14 @@
 	}
 
 	return usb_dev;
-}
+} /* ohci_usb_allocate() */
+
 
+/*
+ * Free a usb device.
+ *
+ * TODO This function needs to take better care of the EDs and TDs, etc.
+ */
 static int ohci_usb_deallocate(struct usb_device *usb_dev)
 {
 	kfree(usb_to_ohci(usb_dev));
@@ -457,6 +728,7 @@
 	return 0;
 }
 
+
 /*
  * functions for the generic USB driver
  */
@@ -467,42 +739,92 @@
 	ohci_request_irq,
 };
 
+
 /*
- * Reset an OHCI controller
+ * Reset an OHCI controller.  Returns >= 0 on success.
+ *
+ * Afterwards the HC will be in the "suspend" state which prevents you
+ * from writing to some registers.  Bring it to the operational state
+ * ASAP.
  */
-static void reset_hc(struct ohci *ohci)
+static int reset_hc(struct ohci *ohci)
 {
-	writel((1<<31), &ohci->regs->intrdisable); /* Disable HC interrupts */
-	writel(1,  &ohci->regs->cmdstatus);	   /* HC Reset */
+	int timeout = 1000;  /* prevent an infinite loop */
+
+#if 0
+	printk(KERN_DEBUG "usb-ohci: resetting HC %p\n", ohci);
+#endif
+
+	writel(~0x0, &ohci->regs->intrdisable);    /* Disable HC interrupts */
+	writel(1, &ohci->regs->cmdstatus);	   /* HC Reset */
 	writel_mask(0x3f, &ohci->regs->control);   /* move to UsbReset state */
+
+	while ((readl(&ohci->regs->cmdstatus) & OHCI_CMDSTAT_HCR) != 0) {
+		if (!--timeout) {
+			printk("usb-ohci: USB HC reset timed out!\n");
+			return -1;
+		}
+		udelay(1);
+	}
+
+	printk(KERN_DEBUG "usb-ohci: HC %p reset.\n", ohci);
+
+	return 0;
 } /* reset_hc() */
 
 
 /*
- * Reset and start an OHCI controller
+ * Reset and start an OHCI controller.  Returns >= 0 on success.
  */
-static void start_hc(struct ohci *ohci)
+static int start_hc(struct ohci *ohci)
 {
-	int timeout = 1000;	/* used to prevent an infinite loop. */
+	int ret = 0;
+	int fminterval;
 
-	reset_hc(ohci);
+	fminterval = readl(&ohci->regs->fminterval) & 0x3fff;
+#if 0
+	printk(KERN_DEBUG "entering start_hc %p\n", ohci);
+#endif
 
-	while ((readl(&ohci->regs->control) & 0xc0) == 0) {
-		if (!--timeout) {
-			printk("USB HC Reset timed out!\n");
-			break;
-		}
-	}
+	if (reset_hc(ohci) < 0)
+		return -1;
+
+	/* restore registers cleared by the reset */
+	writel(virt_to_bus(ohci->root_hub->hcca), &ohci->regs->hcca);
+
+	/*
+	 * XXX Should fminterval also be set here?
+	 * The spec suggests 0x2edf [11,999]. (FIXME: make this a constant)
+	 */
+	fminterval |= (0x2edf << 16);
+	writel(fminterval, &ohci->regs->fminterval);
+	/* Start periodic transfers at 90% of fminterval (fmremaining
+	 * counts down; this will put them in the first 10% of the
+	 * frame). */
+	writel((0x2edf*9)/10, &ohci->regs->periodicstart);
 
+	/*
+	 * FNO (frame number overflow) could be enabled...  they
+	 * occur every 32768 frames (every 32-33 seconds).  This is
+	 * useful for debugging and as a bus heartbeat. -greg
+	 */
 	/* Choose the interrupts we care about */
-	writel( OHCI_INTR_MIE | OHCI_INTR_RHSC | OHCI_INTR_SF |
-		OHCI_INTR_WDH | OHCI_INTR_SO | OHCI_INTR_UE |
-		OHCI_INTR_FNO,
+	writel( OHCI_INTR_MIE | /* OHCI_INTR_RHSC | */
+		OHCI_INTR_WDH | OHCI_INTR_FNO,
 		&ohci->regs->intrenable);
 
 	/* Enter the USB Operational state & start the frames a flowing.. */
 	writel_set(OHCI_USB_OPER, &ohci->regs->control);
+	
+	/* Enable control lists */
+	writel_set(OHCI_USB_IE | OHCI_USB_CLE | OHCI_USB_BLE, &ohci->regs->control);
+
+	/* Turn on power to the root hub ports (thanks Roman!) */
+	writel( OHCI_ROOT_LPSC, &ohci->regs->roothub.status );
+
+	printk("usb-ohci: host controller operational\n");
 
+	return ret;
 } /* start_hc() */
 
 
@@ -511,23 +833,20 @@
  */
 static void ohci_reset_port(struct ohci *ohci, unsigned int port)
 {
-	short ms;
 	int status;
 
 	/* Don't allow overflows. */
 	if (port >= MAX_ROOT_PORTS) {
-		printk("Bad port # passed to ohci_reset_port\n");
+		printk("usb-ohci: bad port #%d in ohci_reset_port\n", port);
 		port = MAX_ROOT_PORTS-1;
 	}
 
 	writel(PORT_PRS, &ohci->regs->roothub.portstatus[port]);  /* Reset */
 
 	/*
-	 * Get the time required for a root hub port to reset and wait
-	 * it out (adding 1ms for good measure).
+	 * Wait for the reset to complete.
 	 */
-	ms = (readl(&ohci->regs->roothub.a) >> 24) * 2 + 1;
-	wait_ms(ms);
+	wait_ms(10);
 
 	/* check port status to see that the reset completed */
 	status = readl(&ohci->regs->roothub.portstatus[port]);
@@ -555,6 +874,8 @@
 	void *portaddr = &ohci->regs->roothub.portstatus[port];
 	int portstatus;	
 
+	printk(KERN_DEBUG "ohci_connect_change(%p, %d)\n", ohci, port);
+
 	/*
 	 * Because of the status change we have to forget
 	 * everything we think we know about the device
@@ -593,6 +914,7 @@
 	 * Do generic USB device tree processing on the new device.
 	 */
 	usb_new_device(usb_dev);
+
 } /* ohci_connect_change() */
 
 
@@ -603,66 +925,241 @@
  */
 static void ohci_check_configuration(struct ohci *ohci)
 {
+	struct ohci_regs *regs = ohci->regs;
 	int num = 0;
 	int maxport = readl(&ohci->regs->roothub) & 0xff;
 
+#if 1
+	printk(KERN_DEBUG "entering ohci_check_configuration %p\n", ohci);
+#endif
+
 	do {
-		if (readl(ohci->regs->roothub.portstatus[num]) & PORT_CSC)
+		if (readl(&regs->roothub.portstatus[num]) & PORT_CSC) {
+			/* reset the connect status change bit */
+			writel(PORT_CSC, &regs->roothub.portstatus[num]);
+			/* check the port for a nifty device */
 			ohci_connect_change(ohci, num);
+		}
 	} while (++num < maxport);
+
+#if 0
+	printk(KERN_DEBUG "leaving ohci_check_configuration %p\n", ohci);
+#endif
 } /* ohci_check_configuration() */
 
 
+
+/*
+ * Check root hub port status and wake the control thread up if
+ * anything has changed.
+ *
+ * This function is called from the interrupt handler.
+ */
+static void ohci_root_hub_events(struct ohci *ohci)
+{
+	if (waitqueue_active(&ohci_configure)) {
+		int num = 0;
+		int maxport = ohci->root_hub->usb->maxchild;
+
+		do {
+			if (readl(&ohci->regs->roothub.portstatus[num]) &
+					PORT_CSC) {
+				if (waitqueue_active(&ohci_configure))
+					wake_up(&ohci_configure);
+				return;
+			}
+		} while (++num < maxport);
+	}
+} /* ohci_root_hub_events() */
+
+
+/*
+ * The done list is in reverse order; we need to process TDs in the
+ * order they were finished (FIFO).  This function builds the FIFO
+ * list using the next_dl_td pointer.
+ *
+ * This function originally by Roman Weissgaerber (weissg@vienna.at)
+ *
+ * This function is called from the interrupt handler.
+ */
+static struct ohci_td * ohci_reverse_donelist(struct ohci * ohci)
+{
+	__u32 td_list_hc;
+	struct ohci_hcca *hcca = ohci->root_hub->hcca;
+	struct ohci_td *td_list = NULL;
+	struct ohci_td *td_rev = NULL;
+  	
+	td_list_hc = hcca->donehead & 0xfffffff0;
+	hcca->donehead = 0;
+
+ 	while(td_list_hc) {
+		td_list = (struct ohci_td *) bus_to_virt(td_list_hc);
+		td_list->next_dl_td = td_rev;
+			
+		td_rev = td_list;
+		td_list_hc = td_list->next_td & 0xfffffff0;
+	}
+
+	return td_list;
+} /* ohci_reverse_donelist() */
+
+
+/*
+ * Collect this interrupt's goodies off of the list of finished TDs
+ * that the OHCI controller is kind enough to setup for us.
+ *
+ * This function is called from the interrupt handler.
+ */
+static void ohci_reap_donelist(struct ohci *ohci)
+{
+	struct ohci_td *td;		/* used for walking the list */
+
+	spin_lock(&ohci_edtd_lock);
+
+	/* create the FIFO ordered donelist */
+	td = ohci_reverse_donelist(ohci);
+
+	while (td != NULL) {
+		struct ohci_td *next_td = td->next_dl_td;
+
+		/* FIXME: munge td->info into a future standard status format */
+		/* Check if TD should be re-queued */
+		if ((td->completed != NULL) &&
+		    (td->completed(OHCI_TD_CC_GET(td->info), td->data, td->dev_id)))
+		{
+			/* Mark the TD as active again:
+			 * Set the not accessed condition code
+			 * FIXME: should this reset OHCI_TD_ERRCNT?
+			 */
+			td->info |= OHCI_TD_CC_NEW;
+
+			/* point it back to the start of the data buffer */
+			td->cur_buf = virt_to_bus(td->data);
+
+			/* XXX disabled for debugging reasons right now.. */
+			/* insert it back on its ED */
+			ohci_add_td_to_ed(td, td->ed);
+		} else {
+			/* return it to the pool of free TDs */
+			ohci_free_td(td);
+		}
+
+		td = next_td;
+	}
+
+	spin_unlock(&ohci_edtd_lock);
+} /* ohci_reap_donelist() */
+
+
+#if 0
+static int in_int = 0;
+#endif
 /*
  * Get annoyed at the controller for bothering us.
+ * This pretty much follows the OHCI v1.0a spec, section 5.3.
  */
 static void ohci_interrupt(int irq, void *__ohci, struct pt_regs *r)
 {
 	struct ohci *ohci = __ohci;
 	struct ohci_regs *regs = ohci->regs;
 	struct ohci_hcca *hcca = ohci->root_hub->hcca;
-	__u32 donehead = hcca->donehead;
+	__u32 status, context;
 
-	/*
-	 * Check the interrupt status register if needed
-	 */
-	if (!donehead || (donehead & 1)) {
-		__u32 intrstatus = readl(&regs->intrstatus);
+#if 0
+	/* for debugging to keep IRQs from running away. */
+	if (in_int >= 2)
+		return;
+	++in_int;
+	return;
+#endif
 
-		/*
-		 * XXX eek! printk's in an interrupt handler.  shoot me!
-		 */
-		if (intrstatus & OHCI_INTR_SO) {
-			printk(KERN_DEBUG "usb-ohci: scheduling overrun\n");
-		}
-		if (intrstatus & OHCI_INTR_RD) {
-			printk(KERN_DEBUG "usb-ohci: resume detected\n");
-		}
-		if (intrstatus & OHCI_INTR_UE) {
-			printk(KERN_DEBUG "usb-ohci: unrecoverable error\n");
+	/* Save the status of the interrupts that are enabled */
+	status = readl(&regs->intrstatus);
+	status &= readl(&regs->intrenable);
+
+
+	/* make context = the interrupt status bits that we care about */
+	if (hcca->donehead != 0) {
+		context = OHCI_INTR_WDH;   /* hcca donehead needs processing */
+		if (hcca->donehead & 1) {
+			context |= status;  /* other status change to check */
 		}
-		if (intrstatus & OHCI_INTR_OC) {
-			printk(KERN_DEBUG "usb-ohci: ownership change?\n");
+	} else {
+		context = status;
+		if (!context) {
+			/* TODO increment a useless interrupt counter here */
+			return;
 		}
+	}
 
-		if (intrstatus & OHCI_INTR_RHSC) {
-			/* TODO Process events on the root hub */
-		}
+	/* Disable HC interrupts */
+	writel(OHCI_INTR_MIE, &regs->intrdisable);
+
+	/* Process the done list */
+	if (context & OHCI_INTR_WDH) {
+		/* See which TD's completed.. */
+		ohci_reap_donelist(ohci);
+
+		/* reset the done queue and tell the controller */
+		hcca->donehead = 0;
+		writel(OHCI_INTR_WDH, &regs->intrstatus);
+
+		context &= ~OHCI_INTR_WDH;  /* mark this as checked */
 	}
 
-	/*
-	 * Process the done list
-	 */
-	if (donehead &= ~0x1) {
-		/*
-		 * TODO See which TD's completed..
+	/* Process any root hub status changes */
+	if (context & OHCI_INTR_RHSC) {
+		/* Wake the thread to process root hub events */
+		if (waitqueue_active(&ohci_configure))
+			wake_up(&ohci_configure);
+
+		writel(OHCI_INTR_RHSC, &regs->intrstatus);
+		/* 
+		 * Don't unset RHSC in context; it should be disabled.
+		 * The control thread will re-enable it after it has
+		 * checked the root hub status.
 		 */
+	} else {
+		/* check the root hub status anyways. Some controllers
+		 * might not generate the interrupt properly. (?) */
+		ohci_root_hub_events(ohci);
 	}
 
-	/* Re-enable done queue interrupts and reset the donehead */
-	hcca->donehead = 0;
-	writel(OHCI_INTR_WDH, &regs->intrenable);
-	
+	/* Check those "other" pesky bits */
+	if (context & (OHCI_INTR_FNO)) {
+		writel(OHCI_INTR_FNO, &regs->intrstatus);
+		context &= ~OHCI_INTR_FNO;  /* mark this as checked */
+	}
+	if (context & OHCI_INTR_SO) {
+		writel(OHCI_INTR_SO, &regs->intrstatus);
+		context &= ~OHCI_INTR_SO;  /* mark this as checked */
+	}
+	if (context & OHCI_INTR_RD) {
+		writel(OHCI_INTR_RD, &regs->intrstatus);
+		context &= ~OHCI_INTR_RD;  /* mark this as checked */
+	}
+	if (context & OHCI_INTR_UE) {
+		/* FIXME: need to have the control thread reset the
+		 * controller now and keep a count of unrecoverable
+		 * errors.  If there are too many, it should just shut
+		 * the broken controller down entirely. */
+		writel(OHCI_INTR_UE, &regs->intrstatus);
+		context &= ~OHCI_INTR_UE;  /* mark this as checked */
+	}
+	if (context & OHCI_INTR_OC) {
+		writel(OHCI_INTR_OC, &regs->intrstatus);
+		context &= ~OHCI_INTR_OC;  /* mark this as checked */
+	}
+
+	/* Mask out any remaining unprocessed interrupts so we don't
+	 * get any more of them. */
+	if (context & ~OHCI_INTR_MIE) {
+		writel(context, &regs->intrdisable);
+	}
+
+	/* Re-enable HC interrupts */
+	writel(OHCI_INTR_MIE, &regs->intrenable);
+
 } /* ohci_interrupt() */
 
 
@@ -682,6 +1179,10 @@
 	struct ohci_device *dev;
 	struct usb_device *usb;
 
+#if 0
+	printk(KERN_DEBUG "entering alloc_ohci %p\n", mem_base);
+#endif
+
 	ohci = kmalloc(sizeof(*ohci), GFP_KERNEL);
 	if (!ohci)
 		return NULL;
@@ -703,6 +1204,8 @@
 	bus->op = &ohci_device_operations;
 
 	/*
+	 * Allocate the USB device structure and root hub.
+	 *
 	 * Here we allocate our own root hub and TDs as well as the
 	 * OHCI host controller communications area.  The HCCA is just
 	 * a nice pool of memory with pointers to endpoint descriptors
@@ -717,17 +1220,22 @@
 	usb->bus = bus;
 
 	/* Initialize the root hub */
-	memset(dev, 0, sizeof(*dev));
 	dev->ohci = ohci;    /* link back to the controller */
 
 	/*
-	 * Allocate the Host Controller Communications Area
+	 * Allocate the Host Controller Communications Area on a 256
+	 * byte boundary.  XXX take the easy way out and just grab a
+	 * page as that's guaranteed to have a nice boundary.
 	 */
-	dev->hcca = (struct ohci_hcca *) kmalloc(sizeof(*dev->hcca), GFP_KERNEL);
+	dev->hcca = (struct ohci_hcca *) __get_free_page(GFP_KERNEL);
 
 	/* Tell the controller where the HCCA is */
 	writel(virt_to_bus(dev->hcca), &ohci->regs->hcca);
 
+#if 0
+	printk(KERN_DEBUG "usb-ohci: HCCA allocated at %p (bus %p)\n", dev->hcca, (void*)virt_to_bus(dev->hcca));
+#endif
+
 	/* Get the number of ports on the root hub */
 	usb->maxchild = readl(&ohci->regs->roothub.a) & 0xff;
 	if (usb->maxchild > MAX_ROOT_PORTS) {
@@ -740,11 +1248,6 @@
 	}
 	printk("usb-ohci: %d root hub ports found\n", usb->maxchild);
 
-	printk("alloc_ohci() controller\n");
-	show_ohci_status(ohci);
-	printk("alloc_ohci() root_hub device\n");
-	show_ohci_device(dev);
-
 	/*
 	 * Initialize the ED polling "tree" (for simplicity's sake in
 	 * this driver many nodes in the tree will be identical)
@@ -759,11 +1262,9 @@
 	 * Initialize the polling table to call interrupts at the
 	 * intended intervals.
 	 */
-	for (i = 0; i < NUM_INTS; i++) {
-		if (i == 0)
-			dev->hcca->int_table[i] =
-				virt_to_bus(&dev->ed[ED_INT_32]);
-		else if (i & 1)
+	dev->hcca->int_table[0] = virt_to_bus(&dev->ed[ED_INT_32]);
+	for (i = 1; i < NUM_INTS; i++) {
+		if (i & 1)
 			dev->hcca->int_table[i] =
 				virt_to_bus(&dev->ed[ED_INT_16]);
 		else if (i & 2)
@@ -782,9 +1283,23 @@
 
 	/*
 	 * Tell the controller where the control and bulk lists are
+	 * The lists start out empty.
 	 */
+	writel(0, &ohci->regs->ed_controlhead);
+	writel(0, &ohci->regs->ed_bulkhead);
+	/*
 	writel(virt_to_bus(&dev->ed[ED_CONTROL]), &ohci->regs->ed_controlhead);
 	writel(virt_to_bus(&dev->ed[ED_BULK]), &ohci->regs->ed_bulkhead);
+	*/
+
+#if 0
+	printk(KERN_DEBUG "alloc_ohci(): controller\n");
+	show_ohci_status(ohci);
+#endif
+
+#if 0
+	printk(KERN_DEBUG "leaving alloc_ohci %p\n", ohci);
+#endif
 
 	return ohci;
 } /* alloc_ohci() */
@@ -795,16 +1310,25 @@
  */
 static void release_ohci(struct ohci *ohci)
 {
+	printk(KERN_DEBUG "entering release_ohci %p\n", ohci);
+
+#ifdef OHCI_TIMER
+	/* stop our timer */
+	del_timer(&ohci_timer);
+#endif
 	if (ohci->irq >= 0) {
 		free_irq(ohci->irq, ohci);
 		ohci->irq = -1;
 	}
 
+	/* stop all OHCI interrupts */
+	writel(~0x0, &ohci->regs->intrdisable);
+
 	if (ohci->root_hub) {
 		/* ensure that HC is stopped before releasing the HCCA */
 		writel(OHCI_USB_SUSPEND, &ohci->regs->control);
-		free_pages((unsigned int) ohci->root_hub->hcca, 1);
-		free_pages((unsigned int) ohci->root_hub, 1);
+		free_page((unsigned long) ohci->root_hub->hcca);
+		kfree(ohci->root_hub);
 		ohci->root_hub->hcca = NULL;
 		ohci->root_hub = NULL;
 	}
@@ -812,20 +1336,26 @@
 	/* unmap the IO address space */
 	iounmap(ohci->regs);
 
+	kfree(ohci);
+
+	MOD_DEC_USE_COUNT;
+
 	/* If the ohci itself were dynamic we'd free it here */
 
+	printk(KERN_DEBUG "usb-ohci: HC resources released.\n");
 } /* release_ohci() */
 
+
 /*
  * USB OHCI control thread
  */
 static int ohci_control_thread(void * __ohci)
 {
 	struct ohci *ohci = (struct ohci *)__ohci;
-	
+
 	/*
 	 * I'm unfamiliar with the SMP kernel locking.. where should
-	 * this be released?  -greg
+	 * this be released and what does it do?  -greg
 	 */
 	lock_kernel();
 
@@ -833,7 +1363,7 @@
 	 * This thread doesn't need any user-level access,
 	 * so get rid of all of our resources..
 	 */
-	printk("ohci_control_thread at %p\n", &ohci_control_thread);
+	printk("ohci_control_thread code at %p\n", &ohci_control_thread);
 	exit_mm(current);
 	exit_files(current);
 	exit_fs(current);
@@ -843,23 +1373,64 @@
 	/*
 	 * Damn the torpedoes, full speed ahead
 	 */
-	start_hc(ohci);
-	do {
+	if (start_hc(ohci) < 0) {
+		printk("usb-ohci: failed to start the controller\n");
+		release_ohci(ohci);
+		printk(KERN_DEBUG "leaving ohci_control_thread %p\n", __ohci);
+		return 0;
+	}
+
+	for(;;) {
+		siginfo_t info;
+		int unsigned long signr;
+
+		wait_ms(200);
+
+		/* check the root hub configuration for changes. */
+		ohci_check_configuration(ohci);
+
+		/* re-enable root hub status change interrupts. */
+#if 0
+		writel(OHCI_INTR_RHSC, &ohci->regs->intrenable);
+#endif
+
+		printk(KERN_DEBUG "ohci-control thread sleeping\n");
 		interruptible_sleep_on(&ohci_configure);
 #ifdef CONFIG_APM
 		if (apm_resume) {
 			apm_resume = 0;
-			start_hc(ohci);
+			if (start_hc(ohci) < 0)
+				break;
 			continue;
 		}
 #endif
-		ohci_check_configuration(ohci);
-	} while (!signal_pending(current));
 
-	reset_hc(ohci);
+		/*
+		 * If we were woken up by a signal, see if its useful,
+		 * otherwise exit.
+		 */
+		if (signal_pending(current)) {
+			/* sending SIGUSR1 makes us print out some info */
+			spin_lock_irq(&current->sigmask_lock);
+			signr = dequeue_signal(&current->blocked, &info);
+			spin_unlock_irq(&current->sigmask_lock);
+
+			if(signr == SIGUSR1) {
+				/* FIXME: have it do a full ed/td queue dump */
+				printk(KERN_DEBUG "OHCI status dump:\n");
+				show_ohci_status(ohci);
+			} else {
+				/* unknown signal, exit the thread */
+				break;
+			}
+		}
+	} /* for (;;) */
 
+	reset_hc(ohci);
 	release_ohci(ohci);
-	MOD_DEC_USE_COUNT;
+
+	printk(KERN_DEBUG "leaving ohci_control_thread %p\n", __ohci);
+
 	return 0;
 } /* ohci_control_thread() */
 
@@ -892,10 +1463,28 @@
 		break;
 	}
 	return 0;
-}
+} /* handle_apm_event() */
+#endif
+
+
+#ifdef OHCI_TIMER
+/*
+ * Inspired by Iñaky's driver.  This function is a timer routine that
+ * is called OHCI_TIMER_FREQ times per second.  It polls the root hub
+ * for status changes as on my system things are acting a bit odd at
+ * the moment..
+ */
+static void ohci_timer_func (unsigned long ohci_ptr)
+{
+	struct ohci *ohci = (struct ohci*)ohci_ptr;
+
+	ohci_root_hub_events(ohci);
+
+	/* press the snooze button... */
+	mod_timer(&ohci_timer, jiffies + (OHCI_TIMER_FREQ*HZ));
+} /* ohci_timer_func() */
 #endif
 
-/* ... */
 
 /*
  * Increment the module usage count, start the control thread and
@@ -906,32 +1495,50 @@
 	int retval;
 	struct ohci *ohci;
 
+#if 0
+	printk(KERN_DEBUG "entering found_ohci %d %p\n", irq, mem_base);
+#endif
+
 	/* Allocate the running OHCI structures */
 	ohci = alloc_ohci(mem_base);
-	if (!ohci)
+	if (!ohci) {
 		return -ENOMEM;
+	}
 
-	printk("usb-ohci: alloc_ohci() = %p\n", ohci);
-
-	reset_hc(ohci);
+#ifdef OHCI_TIMER
+	init_timer(&ohci_timer);
+	ohci_timer.expires = jiffies + (OHCI_TIMER_FREQ*HZ);
+	ohci_timer.data = (unsigned long)ohci;
+	ohci_timer.function = ohci_timer_func;
+#endif
 
 	retval = -EBUSY;
 	if (request_irq(irq, ohci_interrupt, SA_SHIRQ, "usb-ohci", ohci) == 0) {
 		int pid;
 
-		MOD_INC_USE_COUNT;
 		ohci->irq = irq;
 
+#if 0
+		printk(KERN_DEBUG "usb-ohci: starting ohci-control thread\n");
+#endif
+
 		/* fork off the handler */
 		pid = kernel_thread(ohci_control_thread, ohci,
 				CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
-		if (pid >= 0)
+		if (pid >= 0) {
 			return 0;
+		}
 
-		MOD_DEC_USE_COUNT;
 		retval = pid;
+	} else {
+		printk("usb-ohci: Couldn't allocate interrupt %d\n", irq);
 	}
 	release_ohci(ohci);
+
+#if 0
+	printk(KERN_DEBUG "leaving found_ohci %d %p\n", irq, mem_base);
+#endif
+
 	return retval;
 } /* found_ohci() */
 
@@ -941,35 +1548,44 @@
  */
 static int init_ohci(struct pci_dev *dev)
 {
-	unsigned int mem_base = dev->base_address[0];
+	unsigned long mem_base = dev->base_address[0];
 	
-	printk("usb-ohci: mem_base is %p\n", (void*)mem_base);
-
 	/* If its OHCI, its memory */
 	if (mem_base & PCI_BASE_ADDRESS_SPACE_IO)
 		return -ENODEV;
 
 	/* Get the memory address and map it for IO */
 	mem_base &= PCI_BASE_ADDRESS_MEM_MASK;
+
+	/* no interrupt won't work... */
+	if (dev->irq == 0) {
+		printk("usb-ohci: no irq assigned? check your BIOS settings.\n");
+		return -ENODEV;
+	}
+
 	/* 
 	 * FIXME ioremap_nocache isn't implemented on all CPUs (such
 	 * as the Alpha) [?]  What should I use instead...
 	 *
 	 * The iounmap() is done on in release_ohci.
 	 */
-	mem_base = (unsigned int) ioremap_nocache(mem_base, 4096);
+	mem_base = (unsigned long) ioremap_nocache(mem_base, 4096);
 
 	if (!mem_base) {
 		printk("Error mapping OHCI memory\n");
 		return -EFAULT;
 	}
+        MOD_INC_USE_COUNT;
 
-	return found_ohci(dev->irq, (void *) mem_base);
-} /* init_ohci() */
+	if (found_ohci(dev->irq, (void *) mem_base) < 0) {
+		MOD_DEC_USE_COUNT;
+		return -1;
+	}
 
+	return 0;
+} /* init_ohci() */
 
 #ifdef MODULE
-
 /*
  *  Clean up when unloading the module
  */
@@ -978,6 +1594,10 @@
 #ifdef CONFIG_APM
 	apm_unregister_callback(&handle_apm_event);
 #endif
+#ifdef CONFIG_USB_MOUSE
+	usb_mouse_cleanup();
+#endif
+	printk("usb-ohci: module unloaded\n");
 }
 
 #define ohci_init init_module
@@ -1005,6 +1625,8 @@
 		return -ENODEV;
 	}
 
+	printk("OHCI USB Driver loading\n");
+
 	retval = -ENODEV;
 	for (;;) {
 		/* Find an OHCI USB controller */
@@ -1024,9 +1646,16 @@
 
 		/* TODO check module params here to determine what to load */
 
-/*		usb_mouse_init(); */
-/*		usb_kbd_init();
-		hub_init();	*/
+#ifdef CONFIG_USB_MOUSE
+		usb_mouse_init();
+#endif
+#ifdef CONFIG_USB_KBD		
+		usb_kbd_init();
+#endif		
+		hub_init();
+#ifdef CONFIG_USB_AUDIO		
+		usb_audio_init();
+#endif		
 #ifdef CONFIG_APM
 		apm_register_callback(&handle_apm_event);
 #endif
@@ -1034,7 +1663,7 @@
 		return 0; /* no error */
 	}
 	return retval;
-} /* init_module() */
+} /* ohci_init */
 
 /* vim:sw=8
  */
diff -urN linux-2.2.8-pre7/drivers/usb/ohci.h linux/drivers/usb/ohci.h
--- linux-2.2.8-pre7/drivers/usb/ohci.h	Mon Apr 26 12:51:57 1999
+++ linux/drivers/usb/ohci.h	Mon Dec  3 18:46:55 2001
@@ -6,7 +6,7 @@
  *
  * (C) Copyright 1999 Gregory P. Smith <greg@electricrain.com>
  *
- * $Id: ohci.h,v 1.6 1999/04/24 22:50:06 greg Exp $
+ * $Id: ohci.h,v 1.15 1999/05/09 23:25:49 greg Exp $
  */
 
 #include <linux/list.h>
@@ -14,50 +14,65 @@
 
 #include "usb.h"
 
+struct ohci_ed;
+
 /*
  * Each TD must be aligned on a 16-byte boundary.  From the OHCI v1.0 spec
  * it does not state that TDs must be contiguious in memory (due to the
  * use of the next_td field).  This gives us extra room at the end of a
  * TD for our own driver specific data.
  *
- * This structure's size must be a multiple of 16 bytes.
+ * This structure's size must be a multiple of 16 bytes. ?? no way, I
+ * don't see why.  Alignment should be all that matters.
  */
 struct ohci_td {
     	/* OHCI Hardware fields */
-    	__u32 info;
-	__u32 cur_buf;		/* Current Buffer Pointer */
-	__u32 next_td;		/* Next TD Pointer */
-	__u32 buf_end;		/* Memory Buffer End Pointer */
+    	__u32 info;		/* TD status & type flags */
+	__u32 cur_buf;		/* Current Buffer Pointer (bus address) */
+	__u32 next_td;		/* Next TD Pointer (bus address) */
+	__u32 buf_end;		/* Memory Buffer End Pointer (bus address) */
 
 	/* Driver specific fields */
-	struct list_head irq_list;	/* Active interrupt list */
+	struct ohci_ed *ed;		/* address of the ED this TD is on */
+	struct ohci_td *next_dl_td;	/* used during donelist processing */
+	void *data;			/* virt. address of the the buffer */
 	usb_device_irq completed;	/* Completion handler routine */
-	void *data;	/* XXX ? */
-	void *dev_id;	/* XXX ? */
-	__u32 ed_bus;			/* bus address of original ED */
-} __attribute((aligned(32)));
+	int allocated;			/* boolean: is this TD allocated? */
+
+	/* User or Device class driver specific fields */
+	void *dev_id;	/* user defined pointer passed to irq handler */
+} __attribute((aligned(16)));
 
 #define OHCI_TD_ROUND	(1 << 18)	/* buffer rounding bit */
-#define OHCI_TD_D	(3 << 11)	/* direction of xfer: */
-#define OHCI_TD_D_IN	(2 << 11)
-#define OHCI_TD_D_OUT	(1 << 11)
-#define OHCI_TD_D_SETUP (0)
+#define OHCI_TD_D	(3 << 19)	/* direction of xfer: */
+#define OHCI_TD_D_IN	(2 << 19)
+#define OHCI_TD_D_OUT	(1 << 19)
+#define OHCI_TD_D_SETUP (0 << 19)
 #define td_set_dir_in(d)	((d) ? OHCI_TD_D_IN : OHCI_TD_D_OUT )
 #define td_set_dir_out(d)	((d) ? OHCI_TD_D_OUT : OHCI_TD_D_IN )
 #define OHCI_TD_IOC_DELAY (7 << 21)	/* frame delay allowed before int. */
 #define OHCI_TD_IOC_OFF	(OHCI_TD_IOC_DELAY)	/* no interrupt on complete */
 #define OHCI_TD_DT	(3 << 24)	/* data toggle bits */
+#define TOGGLE_AUTO	(0 << 24)	/* automatic (from the ED) */
+#define TOGGLE_DATA0	(2 << 24)	/* force Data0 */
+#define TOGGLE_DATA1	(3 << 24)	/* force Data1 */
 #define td_force_toggle(b)	(((b) | 2) << 24)
 #define OHCI_TD_ERRCNT	(3 << 26)	/* error count */
-#define td_errorcount(td)	(((td) >> 26) & 3)
+#define td_errorcount(td)	(((td).info >> 26) & 3)
 #define OHCI_TD_CC	(0xf << 28)	/* condition code */
+#define OHCI_TD_CC_GET(td_i) (((td_i) >> 28) & 0xf)
 #define OHCI_TD_CC_NEW	(OHCI_TD_CC)	/* set this on all unaccessed TDs! */
-#define td_cc_notaccessed(td)	((td >> 29) == 7)
-#define td_cc_accessed(td)	((td >> 29) != 7)
-#define td_cc_noerror(td)	(((td) & OHCI_TD_CC) == 0)
+#define td_cc_notaccessed(td)	(((td).info >> 29) == 7)
+#define td_cc_accessed(td)	(((td).info >> 29) != 7)
+#define td_cc_noerror(td)	((((td).info) & OHCI_TD_CC) == 0)
 #define td_active(td)	(!td_cc_noerror((td)) && (td_errorcount((td)) < 3))
 #define td_done(td)	(td_cc_noerror((td)) || (td_errorcount((td)) == 3))
 
+#define td_allocated(td)	((td).allocated)
+#define allocate_td(td)		((td)->allocated = 1)
+#define ohci_free_td(td)	((td)->allocated = 0)
+
+
 /*
  * The endpoint descriptors also requires 16-byte alignment
  */
@@ -65,10 +80,16 @@
 	/* OHCI hardware fields */
 	__u32 status;
 	__u32 tail_td;	/* TD Queue tail pointer */
-	__u32 head_td;	/* TD Queue head pointer */
+	__u32 _head_td;	/* TD Queue head pointer, toggle carry & halted bits */
 	__u32 next_ed;	/* Next ED */
 } __attribute((aligned(16)));
 
+/* get the head_td */
+#define ed_head_td(ed)	((ed)->_head_td & 0xfffffff0)
+
+/* save the carry flag while setting the head_td */
+#define set_ed_head_td(ed, td)	((ed)->_head_td = (td) | ((ed)->_head_td & 3))
+
 #define OHCI_ED_SKIP	(1 << 14)
 #define OHCI_ED_MPS	(0x7ff << 16)
 /* FIXME: should cap at the USB max packet size [0x4ff] */
@@ -90,10 +111,10 @@
 
 /* NOTE: bits 27-31 of the status dword are reserved for the driver */
 /*
- * We'll use this status flag for the non-predefined EDs to mark if
- * they're in use or not.
+ * We'll use this status flag for to mark if an ED is in use by the
+ * driver or not.  If the bit is set, it is used.
  *
- * FIXME: unimplemented (needed?)
+ * FIXME: implement this!
  */
 #define ED_USED	(1 << 31)
 
@@ -174,8 +195,8 @@
 
 /*
  * Given a period p in ms, convert it to the closest endpoint
- * interrupt frequency; rounding down.  I'm sure many feel that this
- * is a gross macro.  Feel free to toss it for actual code.
+ * interrupt frequency; rounding down.  This is a gross macro.
+ * Feel free to toss it for actual code. (gasp!)
  */
 #define ms_to_ed_int(p) \
 	((p >= 32) ? ED_INT_32 : \
@@ -257,6 +278,15 @@
 #define PORT_OCIC	(1 << 19)	/* port over current indicator chg */
 #define PORT_PRSC	(1 << 20)	/* port reset status change */
 
+/*
+ * Root Hub status register masks
+ */
+#define OHCI_ROOT_LPS	(1)		/* turn off root hub ports power */
+#define OHCI_ROOT_OCI	(1 << 1)	/* Overcurrent Indicator */
+#define OHCI_ROOT_DRWE	(1 << 15)	/* Device remote wakeup enable */
+#define OHCI_ROOT_LPSC	(1 << 16)	/* turn on root hub ports power */
+#define OHCI_ROOT_OCIC	(1 << 17)	/* Overcurrent indicator change */
+#define OHCI_ROOT_CRWE	(1 << 31)	/* Clear RemoteWakeupEnable */
 
 /*
  * Interrupt register masks
@@ -276,6 +306,19 @@
  */
 #define OHCI_USB_OPER		(2 << 6)
 #define OHCI_USB_SUSPEND	(3 << 6)
+#define OHCI_USB_PLE		(1 << 2)  /* Periodic (interrupt) list enable */
+#define OHCI_USB_IE		(1 << 3)  /* Isochronous list enable */
+#define OHCI_USB_CLE		(1 << 4)  /* Control list enable */
+#define OHCI_USB_BLE		(1 << 5)  /* Bulk list enable */
+
+/*
+ * Command status register masks
+ */
+#define OHCI_CMDSTAT_HCR	(1)
+#define OHCI_CMDSTAT_CLF	(1 << 1)
+#define OHCI_CMDSTAT_BLF	(1 << 2)
+#define OHCI_CMDSTAT_OCR	(1 << 3)
+#define OHCI_CMDSTAT_SOC	(3 << 16)
 
 /*
  * This is the full ohci controller description
@@ -291,10 +334,15 @@
 	struct list_head interrupt_list;	/* List of interrupt active TDs for this OHCI */
 };
 
+#define OHCI_TIMER
+#define OHCI_TIMER_FREQ	(1)		/* frequency of OHCI status checks */
+
 /* Debugging code */
-void show_ed(struct ohci_ed *ed);
-void show_td(struct ohci_td *td);
-void show_status(struct ohci *ohci);
+void show_ohci_ed(struct ohci_ed *ed);
+void show_ohci_td(struct ohci_td *td);
+void show_ohci_status(struct ohci *ohci);
+void show_ohci_device(struct ohci_device *dev);
+void show_ohci_hcca(struct ohci_hcca *hcca);
 
 #endif
 /* vim:sw=8
diff -urN linux-2.2.8-pre7/drivers/usb/restart linux/drivers/usb/restart
--- linux-2.2.8-pre7/drivers/usb/restart	Fri Apr 16 15:22:40 1999
+++ linux/drivers/usb/restart	Mon Dec  3 18:46:55 2001
@@ -11,25 +11,28 @@
 #  fi
 #fi
 
-UPID=`ps aux | grep uhci-control | grep -v grep | awk '{print $2}'`
+UPID=`ps aux | grep ohci-control | grep -v grep | awk '{print $2}'`
 if test "$UPID"; then
   echo "$ME: killing $UPID"
   kill $UPID
 fi
 
-UMOD=`lsmod | grep '^usb-uhci' | grep -v grep`
+UMOD=`lsmod | grep '^usb-ohci' | grep -v grep`
 if test "$UMOD"; then
-  echo "$ME: removing usb-uhci.o"
+  echo "$ME: removing usb-ohci.o"
   sleep 1
-  if ! rmmod usb-uhci; then
-    echo "$ME: cannot remove usb-uhci.o"
+  if ! rmmod usb-ohci; then
+    echo "$ME: cannot remove usb-ohci.o"
     exit 1
   fi
 fi
 
 dmesg -c > /dev/null
 
-echo "$ME: starting usb-uhci.o"
-insmod -m usb-uhci.o > usb-uhci.map
-#echo "$ME: starting bp-mouse.o"
-#insmod -m bp-mouse.o > bp-mouse.map
+echo "$ME: starting usb-ohci.o"
+insmod -m usb-ohci.o > usb-ohci.map
+
+sleep 1
+UPID=`ps aux | grep ohci-control | grep -v grep | awk '{print $2}'`
+if test "$UPID"; then echo "$ME: ohci-control is pid $UPID" ; fi
+
diff -urN linux-2.2.8-pre7/drivers/usb/stopusb linux/drivers/usb/stopusb
--- linux-2.2.8-pre7/drivers/usb/stopusb	Wed Apr 21 02:42:11 1999
+++ linux/drivers/usb/stopusb	Mon Dec  3 18:46:55 2001
@@ -1,8 +1,7 @@
 #!/bin/sh
 
-killall uhci-control
-killall khubd
+killall ohci-control
 
-sleep 1
+sleep 2
 
-rmmod usb-uhci
+rmmod usb-ohci
diff -urN linux-2.2.8-pre7/drivers/usb/usb.h linux/drivers/usb/usb.h
--- linux-2.2.8-pre7/drivers/usb/usb.h	Mon Dec  3 18:46:27 2001
+++ linux/drivers/usb/usb.h	Mon Dec  3 18:46:55 2001
@@ -194,6 +194,14 @@
 
 /*
  * Pointer to a device endpoint interrupt function -greg
+ *   Parameters:
+ *     int status - This needs to be defined.  Right now each HCD
+ *         passes different transfer status bits back.  Don't use it
+ *         until we come up with a common meaning.
+ *     void *buffer - This is a pointer to the data used in this
+ *         USB transfer.
+ *     void *dev_id - This is a user defined pointer set when the IRQ
+ *         is requested that is passed back.
  */
 typedef int (*usb_device_irq)(int, void *, void *);
 
diff -urN linux-2.2.8-pre7/drivers/video/vesafb.c linux/drivers/video/vesafb.c
--- linux-2.2.8-pre7/drivers/video/vesafb.c	Mon Dec  3 18:46:27 2001
+++ linux/drivers/video/vesafb.c	Mon Dec  3 18:46:55 2001
@@ -21,7 +21,6 @@
 #include <linux/selection.h>
 #include <linux/ioport.h>
 #include <linux/init.h>
-#include <linux/config.h>
 
 #include <asm/io.h>
 #include <asm/mtrr.h>
diff -urN linux-2.2.8-pre7/fs/adfs/namei.c linux/fs/adfs/namei.c
--- linux-2.2.8-pre7/fs/adfs/namei.c	Fri Apr 23 21:20:37 1999
+++ linux/fs/adfs/namei.c	Mon Dec  3 18:46:55 2001
@@ -46,7 +46,7 @@
 	unsigned long parent_object_id, dir_object_id;
 	int buffers, pos;
 
-	if (!dir || !S_ISDIR(dir->i_mode))
+	if (!S_ISDIR(dir->i_mode))
 		return 0;
 
 	sb = dir->i_sb;
diff -urN linux-2.2.8-pre7/fs/buffer.c linux/fs/buffer.c
--- linux-2.2.8-pre7/fs/buffer.c	Tue Apr 27 14:34:41 1999
+++ linux/fs/buffer.c	Mon Dec  3 18:46:55 2001
@@ -100,7 +100,8 @@
 				each time we call refill */
 		int nref_dirt; /* Dirty buffer threshold for activating bdflush
 				  when trying to refill buffers. */
-		int dummy1;    /* unused */
+		int interval;  /* Interval (seconds) between spontaneous
+				  bdflush runs */
 		int age_buffer;  /* Time for normal buffer to age before 
 				    we flush it */
 		int age_super;  /* Time for superblock to age before we 
@@ -109,10 +110,10 @@
 		int dummy3;    /* unused */
 	} b_un;
 	unsigned int data[N_PARAM];
-} bdf_prm = {{40, 500, 64, 256, 15, 30*HZ, 5*HZ, 1884, 2}};
+} bdf_prm = {{40, 500, 64, 256, 5, 30*HZ, 5*HZ, 1884, 2}};
 
 /* These are the min and max parameter values that we will allow to be assigned */
-int bdflush_min[N_PARAM] = {  0,  10,    5,   25,  0,   1*HZ,   1*HZ, 1, 1};
+int bdflush_min[N_PARAM] = {  0,  10,    5,   25,  1,   1*HZ,   1*HZ, 1, 1};
 int bdflush_max[N_PARAM] = {100,5000, 2000, 2000,100, 600*HZ, 600*HZ, 2047, 5};
 
 void wakeup_bdflush(int);
@@ -1553,7 +1554,6 @@
  * response to dirty buffers.  Once this process is activated, we write back
  * a limited number of buffers to the disks and then go back to sleep again.
  */
-static struct wait_queue * bdflush_wait = NULL;
 static struct wait_queue * bdflush_done = NULL;
 struct task_struct *bdflush_tsk = 0;
 
@@ -1561,7 +1561,7 @@
 {
 	if (current == bdflush_tsk)
 		return;
-	wake_up(&bdflush_wait);
+	wake_up_process(bdflush_tsk);
 	if (wait) {
 		run_task_queue(&tq_disk);
 		sleep_on(&bdflush_done);
@@ -1570,82 +1570,107 @@
 
 
 /* 
- * Here we attempt to write back old buffers.  We also try to flush inodes 
- * and supers as well, since this function is essentially "update", and 
- * otherwise there would be no way of ensuring that these quantities ever 
- * get written back.  Ideally, we would have a timestamp on the inodes
- * and superblocks so that we could write back only the old ones as well
- */
+ * Here we attempt to write back old buffers.
+ * To prevent deadlocks for a loop device:
+ * 1) Do non-blocking writes to loop (avoids deadlock with running
+ *	out of request blocks).
+ * 2) But do a blocking write if the only dirty buffers are loop buffers
+ *	(otherwise we go into an infinite busy-loop).
+ * 3) Quit writing loop blocks if a freelist went low (avoids deadlock
+ *	with running out of free buffers for loop's "real" device).
+*/
 
-static int sync_old_buffers(void)
+static inline void sync_old_buffers(void)
 {
 	int i;
-	int ndirty, nwritten;
-	int nlist;
-	int ncount;
-	struct buffer_head * bh, *next;
-
-	sync_supers(0);
-	sync_inodes(0);
-
-	ncount = 0;
+	int ndirty = 0;
+	int wrta_cmd = WRITEA;
 #ifdef DEBUG
-	for(nlist = 0; nlist < NR_LIST; nlist++)
-#else
-	for(nlist = BUF_LOCKED; nlist <= BUF_DIRTY; nlist++)
+	int ncount = 0, nwritten = 0;
 #endif
-	{
-		ndirty = 0;
-		nwritten = 0;
-	repeat:
+	struct buffer_head * bh, *next;
 
-		bh = lru_list[nlist];
-		if(bh) 
-			 for (i = nr_buffers_type[nlist]; i-- > 0; bh = next) {
-				 /* We may have stalled while waiting for I/O to complete. */
-				 if(bh->b_list != nlist) goto repeat;
-				 next = bh->b_next_free;
-				 if(!lru_list[nlist]) {
-					 printk("Dirty list empty %d\n", i);
-					 break;
-				 }
-				 
-				 /* Clean buffer on dirty list?  Refile it */
-				 if (nlist == BUF_DIRTY && !buffer_dirty(bh) && !buffer_locked(bh)) {
-					 refile_buffer(bh);
-					 continue;
-				 }
-				  
-				  /* Unlocked buffer on locked list?  Refile it */
-				  if (nlist == BUF_LOCKED && !buffer_locked(bh)) {
-					  refile_buffer(bh);
-					  continue;
-				  }
-				 
-				 if (buffer_locked(bh) || !buffer_dirty(bh))
-					  continue;
-				 ndirty++;
-				 if(time_before(jiffies, bh->b_flushtime))
-					continue;
-				 nwritten++;
-				 next->b_count++;
-				 bh->b_count++;
-				 bh->b_flushtime = 0;
 #ifdef DEBUG
-				 if(nlist != BUF_DIRTY) ncount++;
+	bh = lru_list[BUF_CLEAN];
+	if(bh)
+		for(i = nr_buffers_type[BUF_CLEAN]; --i > 0; bh = next) {
+			next = bh->b_next_free;
+
+			/* Dirty/locked buffer on clean list?  Refile it */
+			if (buffer_locked(bh) || buffer_dirty(bh)) {
+				ncount++;
+				refile_buffer(bh);
+			}
+		}
 #endif
-				 ll_rw_block(WRITE, 1, &bh);
-				 bh->b_count--;
-				 next->b_count--;
-			 }
+
+	bh = lru_list[BUF_LOCKED];
+	if(bh)
+		for(i = nr_buffers_type[BUF_LOCKED]; --i > 0; bh = next) {
+			next = bh->b_next_free;
+
+			/* Unlocked buffer on locked list?  Refile it */
+			if (!buffer_locked(bh))
+				refile_buffer(bh);
+		}
+
+ restart:
+	bh = lru_list[BUF_DIRTY];
+	if(bh) 
+		for (i = nr_buffers_type[BUF_DIRTY];
+		     i-- > 0 && ndirty < bdf_prm.b_un.ndirty; 
+		     bh = next) {
+			/* We may have stalled while waiting for
+			   I/O to complete. */
+			if(bh->b_list != BUF_DIRTY)
+				goto restart;
+			next = bh->b_next_free;
+			if(!lru_list[BUF_DIRTY]) {
+				printk("Dirty list empty %d\n", i);
+				break;
+			}
+					  
+			/* Clean buffer on dirty list?  Refile it */
+			if (!buffer_dirty(bh)) {
+				refile_buffer(bh);
+				continue;
+			}
+					  
+			if (buffer_locked(bh))
+				continue;
+			/* Should we write back buffers that are
+			   shared or not??  Currently dirty buffers
+			   are not shared, so it does not matter */
+			next->b_count++;
+			bh->b_count++;
+			ndirty++;
+			bh->b_flushtime = 0;
+			if (MAJOR(bh->b_dev) == LOOP_MAJOR) {
+				ll_rw_block(wrta_cmd,1, &bh);
+				wrta_cmd = WRITEA;
+				if (buffer_dirty(bh))
+					--ndirty;
+			}
+			else
+				ll_rw_block(WRITE, 1, &bh);
+			bh->b_count--;
+			next->b_count--;
+		}
+	/* If we didn't write anything, but there are still
+	 * dirty buffers, then make the next write to a
+	 * loop device to be a blocking write.
+	 * This lets us block--which we _must_ do! */
+	if (ndirty == 0
+	    && nr_buffers_type[BUF_DIRTY] > 0 && wrta_cmd != WRITE) {
+		wrta_cmd = WRITE;
+		goto restart;
 	}
-	run_task_queue(&tq_disk);
+
 #ifdef DEBUG
 	if (ncount) printk("sync_old_buffers: %d dirty buffers not on dirty list\n", ncount);
-	printk("Wrote %d/%d buffers\n", nwritten, ndirty);
+	printk("wrote %d/%d buffers...", nwritten, ndirty);
 #endif
 	run_task_queue(&tq_disk);
-	return 0;
 }
 
 
@@ -1662,10 +1687,12 @@
 	if (!capable(CAP_SYS_ADMIN))
 		goto out;
 
-	if (func == 1) {
-		 error = sync_old_buffers();
-		 goto out;
-	}
+	if (func == 1)
+		/* Func 1 used to call sync_old_buffers; a user space
+		   daemon would call it periodically.  This is no
+		   longer necessary.  Returning -EPERM here makes the
+		   daemon silently exit.  */
+		goto out;
 
 	/* Basically func 1 means read param 1, 2 means write param 1, etc */
 	if (func >= 2) {
@@ -1694,27 +1721,17 @@
 	return error;
 }
 
-/* This is the actual bdflush daemon itself. It used to be started from
- * the syscall above, but now we launch it ourselves internally with
- * kernel_thread(...)  directly after the first thread in init/main.c */
+/* This is the actual bdflush daemon itself. It used to be started
+ * from the syscall above, but now we launch it ourselves internally
+ * with kernel_thread(...)  directly after the first thread in
+ * init/main.c.  Every so often, or when woken up by another task that
+ * needs memory, we call sync_old_buffers to partially clear the dirty list.
+ */
 
-/* To prevent deadlocks for a loop device:
- * 1) Do non-blocking writes to loop (avoids deadlock with running
- *	out of request blocks).
- * 2) But do a blocking write if the only dirty buffers are loop buffers
- *	(otherwise we go into an infinite busy-loop).
- * 3) Quit writing loop blocks if a freelist went low (avoids deadlock
- *	with running out of free buffers for loop's "real" device).
-*/
 int bdflush(void * unused) 
 {
-	int i;
-	int ndirty;
-	int nlist;
-	int ncount;
-	struct buffer_head * bh, *next;
-	int major;
-	int wrta_cmd = WRITEA;	/* non-blocking write for LOOP */
+	long remaining = HZ * bdf_prm.b_un.interval;
+	struct task_struct *tsk = current;
 
 	/*
 	 *	We have a bare-bones task_struct, and really should fill
@@ -1722,10 +1739,12 @@
 	 *	display semi-sane things. Not real crucial though...  
 	 */
 
-	current->session = 1;
-	current->pgrp = 1;
-	sprintf(current->comm, "kflushd");
-	bdflush_tsk = current;
+	tsk->session = 1;
+	tsk->pgrp = 1;
+	tsk->dumpable = 0;  /* inhibit ptrace() */
+	strcpy(tsk->comm, "kflushd");
+	sigfillset(&tsk->blocked);
+	bdflush_tsk = tsk;
 
 	/*
 	 *	As a kernel thread we want to tamper with system buffers
@@ -1735,93 +1754,36 @@
 	lock_kernel();
 		 
 	for (;;) {
+		tsk->state = TASK_INTERRUPTIBLE;
+		remaining = schedule_timeout(remaining);
+
 #ifdef DEBUG
 		printk("bdflush() activated...");
 #endif
-
 		CHECK_EMERGENCY_SYNC
 
-		ncount = 0;
-#ifdef DEBUG
-		for(nlist = 0; nlist < NR_LIST; nlist++)
-#else
-		for(nlist = BUF_LOCKED; nlist <= BUF_DIRTY; nlist++)
-#endif
-		 {
-			 ndirty = 0;
-		 repeat:
-
-			 bh = lru_list[nlist];
-			 if(bh) 
-				  for (i = nr_buffers_type[nlist]; i-- > 0 && ndirty < bdf_prm.b_un.ndirty; 
-				       bh = next) {
-					  /* We may have stalled while waiting for I/O to complete. */
-					  if(bh->b_list != nlist) goto repeat;
-					  next = bh->b_next_free;
-					  if(!lru_list[nlist]) {
-						  printk("Dirty list empty %d\n", i);
-						  break;
-					  }
-					  
-					  /* Clean buffer on dirty list?  Refile it */
-					  if (nlist == BUF_DIRTY && !buffer_dirty(bh)) {
-						  refile_buffer(bh);
-						  continue;
-					  }
-					  
-					  /* Unlocked buffer on locked list?  Refile it */
-					  if (nlist == BUF_LOCKED && !buffer_locked(bh)) {
-						  refile_buffer(bh);
-						  continue;
-					  }
-					  
-					  if (buffer_locked(bh) || !buffer_dirty(bh))
-						   continue;
-					  major = MAJOR(bh->b_dev);
-					  /* Should we write back buffers that are shared or not??
-					     currently dirty buffers are not shared, so it does not matter */
-					  next->b_count++;
-					  bh->b_count++;
-					  ndirty++;
-					  bh->b_flushtime = 0;
-					  if (major == LOOP_MAJOR) {
-						  ll_rw_block(wrta_cmd,1, &bh);
-						  wrta_cmd = WRITEA;
-						  if (buffer_dirty(bh))
-							  --ndirty;
-					  }
-					  else
-					  ll_rw_block(WRITE, 1, &bh);
-#ifdef DEBUG
-					  if(nlist != BUF_DIRTY) ncount++;
-#endif
-					  bh->b_count--;
-					  next->b_count--;
-				  }
-		 }
+		if (remaining == 0) {
+			/*
+			 * Also try to flush inodes and supers, since
+			 * otherwise there would be no way of ensuring
+			 * that these quantities ever get written
+			 * back.  Ideally, we would have a timestamp
+			 * on the inodes and superblocks so that we
+			 * could write back only the old ones.
+			 */
+			sync_supers(0);
+			sync_inodes(0);
+			remaining = HZ * bdf_prm.b_un.interval;
+		}
+			
+		/* Keep flushing till there aren't very many dirty buffers */
+		do {
+			sync_old_buffers();
+		} while(nr_buffers_type[BUF_DIRTY] > nr_buffers * bdf_prm.b_un.nfract/100);
+
+		wake_up(&bdflush_done);
 #ifdef DEBUG
-		if (ncount) printk("sys_bdflush: %d dirty buffers not on dirty list\n", ncount);
 		printk("sleeping again.\n");
 #endif
-		/* If we didn't write anything, but there are still
-		 * dirty buffers, then make the next write to a
-		 * loop device to be a blocking write.
-		 * This lets us block--which we _must_ do! */
-		if (ndirty == 0 && nr_buffers_type[BUF_DIRTY] > 0 && wrta_cmd != WRITE) {
-			wrta_cmd = WRITE;
-			continue;
-		}
-		run_task_queue(&tq_disk);
-		wake_up(&bdflush_done);
-		
-		/* If there are still a lot of dirty buffers around, skip the sleep
-		   and flush some more */
-		if(ndirty == 0 || nr_buffers_type[BUF_DIRTY] <= nr_buffers * bdf_prm.b_un.nfract/100) {
-			spin_lock_irq(&current->sigmask_lock);
-			flush_signals(current);
-			spin_unlock_irq(&current->sigmask_lock);
-
-			interruptible_sleep_on(&bdflush_wait);
-		}
 	}
 }
diff -urN linux-2.2.8-pre7/fs/ext2/namei.c linux/fs/ext2/namei.c
--- linux-2.2.8-pre7/fs/ext2/namei.c	Fri Apr 23 21:20:37 1999
+++ linux/fs/ext2/namei.c	Mon Dec  3 18:46:55 2001
@@ -74,8 +74,6 @@
 	int block, toread, i, err;
 
 	*res_dir = NULL;
-	if (!dir)
-		return NULL;
 	sb = dir->i_sb;
 
 	if (namelen > EXT2_NAME_LEN)
diff -urN linux-2.2.8-pre7/fs/isofs/namei.c linux/fs/isofs/namei.c
--- linux-2.2.8-pre7/fs/isofs/namei.c	Fri Apr 23 21:20:38 1999
+++ linux/fs/isofs/namei.c	Mon Dec  3 18:46:55 2001
@@ -74,7 +74,6 @@
 	char c;
 
 	*ino = 0;
-	if (!dir) return NULL;
 	
 	if (!(block = dir->u.isofs_i.i_first_extent)) return NULL;
   
diff -urN linux-2.2.8-pre7/fs/locks.c linux/fs/locks.c
--- linux-2.2.8-pre7/fs/locks.c	Tue Mar 16 11:31:28 1999
+++ linux/fs/locks.c	Mon Dec  3 18:46:55 2001
@@ -263,16 +263,18 @@
 		if (waiter->fl_notify)
 			waiter->fl_notify(waiter);
 		wake_up(&waiter->fl_wait);
-		if (wait)
+		if (wait) {
 			/* Let the blocked process remove waiter from the
 			 * block list when it gets scheduled.
 			 */
+			current->policy |= SCHED_YIELD;
 			schedule();
-		else
+		} else {
 			/* Remove waiter from the block list, because by the
 			 * time it wakes up blocker won't exist any more.
 			 */
 			locks_delete_block(blocker, waiter);
+		}
 	}
 	return;
 }
diff -urN linux-2.2.8-pre7/fs/minix/namei.c linux/fs/minix/namei.c
--- linux-2.2.8-pre7/fs/minix/namei.c	Fri Apr 23 21:20:38 1999
+++ linux/fs/minix/namei.c	Mon Dec  3 18:46:55 2001
@@ -45,7 +45,7 @@
 	struct minix_dir_entry *de;
 
 	*res_dir = NULL;
-	if (!dir || !dir->i_sb)
+	if (!dir->i_sb)
 		return NULL;
 	info = &dir->i_sb->u.minix_sb;
 	if (namelen > info->s_namelen) {
@@ -249,12 +249,6 @@
 	struct buffer_head * bh;
 	struct minix_dir_entry * de;
 
-	bh = minix_find_entry(dir, dentry->d_name.name,
-			      dentry->d_name.len, &de);
-	if (bh) {
-		brelse(bh);
-		return -EEXIST;
-	}
 	inode = minix_new_inode(dir);
 	if (!inode)
 		return -ENOSPC;
@@ -295,12 +289,6 @@
 	struct minix_sb_info * info;
 
 	info = &dir->i_sb->u.minix_sb;
-	bh = minix_find_entry(dir, dentry->d_name.name,
-			      dentry->d_name.len, &de);
-	if (bh) {
-		brelse(bh);
-		return -EEXIST;
-	}
 	if (dir->i_nlink >= info->s_link_max)
 		return -EMLINK;
 	inode = minix_new_inode(dir);
@@ -524,15 +512,6 @@
 	brelse(name_block);
 	inode->i_size = i;
 	mark_inode_dirty(inode);
-	bh = minix_find_entry(dir, dentry->d_name.name,
-			      dentry->d_name.len, &de);
-	if (bh) {
-		inode->i_nlink--;
-		mark_inode_dirty(inode);
-		iput(inode);
-		brelse(bh);
-		return -EEXIST;
-	}
 	i = minix_add_entry(dir, dentry->d_name.name,
 			    dentry->d_name.len, &bh, &de);
 	if (i) {
@@ -562,12 +541,6 @@
 	if (inode->i_nlink >= inode->i_sb->u.minix_sb.s_link_max)
 		return -EMLINK;
 
-	bh = minix_find_entry(dir, dentry->d_name.name,
-			      dentry->d_name.len, &de);
-	if (bh) {
-		brelse(bh);
-		return -EEXIST;
-	}
 	error = minix_add_entry(dir, dentry->d_name.name,
 				dentry->d_name.len, &bh, &de);
 	if (error) {
diff -urN linux-2.2.8-pre7/fs/qnx4/namei.c linux/fs/qnx4/namei.c
--- linux-2.2.8-pre7/fs/qnx4/namei.c	Fri Apr 23 21:20:38 1999
+++ linux/fs/qnx4/namei.c	Mon Dec  3 18:46:55 2001
@@ -70,12 +70,8 @@
 	struct buffer_head *bh;
 
 	*res_dir = NULL;
-	if (!dir || !dir->i_sb) {
-		if (!dir) {
-			printk("qnx4: NULL dir.\n");
-		} else {
-			printk("qnx4: no superblock on dir.\n");
-		}
+	if (!dir->i_sb) {
+		printk("qnx4: no superblock on dir.\n");
 		return NULL;
 	}
 	bh = NULL;
diff -urN linux-2.2.8-pre7/fs/sysv/namei.c linux/fs/sysv/namei.c
--- linux-2.2.8-pre7/fs/sysv/namei.c	Fri Apr 23 21:20:38 1999
+++ linux/fs/sysv/namei.c	Mon Dec  3 18:46:55 2001
@@ -67,8 +67,6 @@
 	struct buffer_head * bh;
 
 	*res_dir = NULL;
-	if (!dir)
-		return NULL;
 	sb = dir->i_sb;
 	if (namelen > SYSV_NAMELEN) {
 		if (sb->sv_truncate)
diff -urN linux-2.2.8-pre7/fs/ufs/namei.c linux/fs/ufs/namei.c
--- linux-2.2.8-pre7/fs/ufs/namei.c	Fri Apr 23 21:20:38 1999
+++ linux/fs/ufs/namei.c	Mon Dec  3 18:46:55 2001
@@ -91,8 +91,6 @@
 	UFSD(("ENTER, dir_ino %lu, name %s, namlen %u\n", dir->i_ino, name, namelen))
 	
 	*res_dir = NULL;
-	if (!dir) 
-		return NULL;
 	
 	sb = dir->i_sb;
 	flags = sb->u.ufs_sb.s_flags;
diff -urN linux-2.2.8-pre7/include/asm-alpha/system.h linux/include/asm-alpha/system.h
--- linux-2.2.8-pre7/include/asm-alpha/system.h	Mon Dec  3 18:46:27 2001
+++ linux/include/asm-alpha/system.h	Mon Dec  3 18:46:55 2001
@@ -1,6 +1,7 @@
 #ifndef __ALPHA_SYSTEM_H
 #define __ALPHA_SYSTEM_H
 
+#include <linux/config.h>
 #include <asm/pal.h>
 #include <asm/page.h>
 
diff -urN linux-2.2.8-pre7/include/asm-m68k/atari_SCCserial.h linux/include/asm-m68k/atari_SCCserial.h
--- linux-2.2.8-pre7/include/asm-m68k/atari_SCCserial.h	Sat Jun 13 13:14:33 1998
+++ linux/include/asm-m68k/atari_SCCserial.h	Mon Dec  3 18:46:55 2001
@@ -28,6 +28,8 @@
 #define SCC_BAUD_BASE_NONE	0		/* for not connected or unused
 						 * clock sources */
 
+#define SCC_BAUD_BASE_M147_PCLK	312500	/* 5 MHz */
+#define SCC_BAUD_BASE_M147	312500	/* 5 MHz */
 #define SCC_BAUD_BASE_MVME_PCLK	781250	/* 12.5 MHz */
 #define SCC_BAUD_BASE_MVME	625000	/* 10.000 MHz */
 #define SCC_BAUD_BASE_BVME_PCLK	781250	/* 12.5 MHz */   /* XXX ??? */
diff -urN linux-2.2.8-pre7/include/asm-m68k/bootinfo.h linux/include/asm-m68k/bootinfo.h
--- linux-2.2.8-pre7/include/asm-m68k/bootinfo.h	Tue Jan 19 10:58:34 1999
+++ linux/include/asm-m68k/bootinfo.h	Mon Dec  3 18:46:55 2001
@@ -219,9 +219,10 @@
 #define AMIGA_BOOTI_VERSION    MK_BI_VERSION( 2, 0 )
 #define ATARI_BOOTI_VERSION    MK_BI_VERSION( 2, 1 )
 #define MAC_BOOTI_VERSION      MK_BI_VERSION( 2, 0 )
+#define MVME147_BOOTI_VERSION  MK_BI_VERSION( 2, 0 )
 #define MVME16x_BOOTI_VERSION  MK_BI_VERSION( 2, 0 )
 #define BVME6000_BOOTI_VERSION MK_BI_VERSION( 2, 0 )
-
+#define Q40_BOOTI_VERSION      MK_BI_VERSION( 2, 0 )
 
 #ifdef BOOTINFO_COMPAT_1_0
 
diff -urN linux-2.2.8-pre7/include/asm-m68k/dvma.h linux/include/asm-m68k/dvma.h
--- linux-2.2.8-pre7/include/asm-m68k/dvma.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/dvma.h	Mon Dec  3 18:46:55 2001
@@ -0,0 +1,165 @@
+/* $Id: dvma.h,v 1.4 1999/03/27 20:23:41 tsbogend Exp $
+ * include/asm-m68k/dma.h
+ *
+ * Copyright 1995 (C) David S. Miller (davem@caip.rutgers.edu)
+ * 
+ * Hacked to fit Sun3x needs by Thomas Bogendoerfer
+ */
+
+#ifndef __M68K_DVMA_H
+#define __M68K_DVMA_H
+
+/* Structure to describe the current status of DMA registers on the Sparc */
+struct sparc_dma_registers {
+  __volatile__ unsigned long cond_reg;	/* DMA condition register */
+  __volatile__ unsigned long st_addr;	/* Start address of this transfer */
+  __volatile__ unsigned long  cnt;	/* How many bytes to transfer */
+  __volatile__ unsigned long dma_test;	/* DMA test register */
+};
+
+/* DVMA chip revisions */
+enum dvma_rev {
+	dvmarev0,
+	dvmaesc1,
+	dvmarev1,
+	dvmarev2,
+	dvmarev3,
+	dvmarevplus,
+	dvmahme
+};
+
+#define DMA_HASCOUNT(rev)  ((rev)==dvmaesc1)
+
+/* Linux DMA information structure, filled during probe. */
+struct Linux_SBus_DMA {
+	struct Linux_SBus_DMA *next;
+	struct linux_sbus_device *SBus_dev;
+	struct sparc_dma_registers *regs;
+
+	/* Status, misc info */
+	int node;                /* Prom node for this DMA device */
+	int running;             /* Are we doing DMA now? */
+	int allocated;           /* Are we "owned" by anyone yet? */
+
+	/* Transfer information. */
+	unsigned long addr;      /* Start address of current transfer */
+	int nbytes;              /* Size of current transfer */
+	int realbytes;           /* For splitting up large transfers, etc. */
+
+	/* DMA revision */
+	enum dvma_rev revision;
+};
+
+extern struct Linux_SBus_DMA *dma_chain;
+
+/* Broken hardware... */
+#define DMA_ISBROKEN(dma)    ((dma)->revision == dvmarev1)
+#define DMA_ISESC1(dma)      ((dma)->revision == dvmaesc1)
+
+/* Fields in the cond_reg register */
+/* First, the version identification bits */
+#define DMA_DEVICE_ID    0xf0000000        /* Device identification bits */
+#define DMA_VERS0        0x00000000        /* Sunray DMA version */
+#define DMA_ESCV1        0x40000000        /* DMA ESC Version 1 */
+#define DMA_VERS1        0x80000000        /* DMA rev 1 */
+#define DMA_VERS2        0xa0000000        /* DMA rev 2 */
+#define DMA_VERHME       0xb0000000        /* DMA hme gate array */
+#define DMA_VERSPLUS     0x90000000        /* DMA rev 1 PLUS */
+
+#define DMA_HNDL_INTR    0x00000001        /* An IRQ needs to be handled */
+#define DMA_HNDL_ERROR   0x00000002        /* We need to take an error */
+#define DMA_FIFO_ISDRAIN 0x0000000c        /* The DMA FIFO is draining */
+#define DMA_INT_ENAB     0x00000010        /* Turn on interrupts */
+#define DMA_FIFO_INV     0x00000020        /* Invalidate the FIFO */
+#define DMA_ACC_SZ_ERR   0x00000040        /* The access size was bad */
+#define DMA_FIFO_STDRAIN 0x00000040        /* DMA_VERS1 Drain the FIFO */
+#define DMA_RST_SCSI     0x00000080        /* Reset the SCSI controller */
+#define DMA_RST_ENET     DMA_RST_SCSI      /* Reset the ENET controller */
+#define DMA_ST_WRITE     0x00000100        /* write from device to memory */
+#define DMA_ENABLE       0x00000200        /* Fire up DMA, handle requests */
+#define DMA_PEND_READ    0x00000400        /* DMA_VERS1/0/PLUS Pending Read */
+#define DMA_ESC_BURST    0x00000800        /* 1=16byte 0=32byte */
+#define DMA_READ_AHEAD   0x00001800        /* DMA read ahead partial longword */
+#define DMA_DSBL_RD_DRN  0x00001000        /* No EC drain on slave reads */
+#define DMA_BCNT_ENAB    0x00002000        /* If on, use the byte counter */
+#define DMA_TERM_CNTR    0x00004000        /* Terminal counter */
+#define DMA_CSR_DISAB    0x00010000        /* No FIFO drains during csr */
+#define DMA_SCSI_DISAB   0x00020000        /* No FIFO drains during reg */
+#define DMA_DSBL_WR_INV  0x00020000        /* No EC inval. on slave writes */
+#define DMA_ADD_ENABLE   0x00040000        /* Special ESC DVMA optimization */
+#define DMA_E_BURST8	 0x00040000	   /* ENET: SBUS r/w burst size */
+#define DMA_BRST_SZ      0x000c0000        /* SCSI: SBUS r/w burst size */
+#define DMA_BRST64       0x00080000        /* SCSI: 64byte bursts (HME on UltraSparc only) */
+#define DMA_BRST32       0x00040000        /* SCSI: 32byte bursts */
+#define DMA_BRST16       0x00000000        /* SCSI: 16byte bursts */
+#define DMA_BRST0        0x00080000        /* SCSI: no bursts (non-HME gate arrays) */
+#define DMA_ADDR_DISAB   0x00100000        /* No FIFO drains during addr */
+#define DMA_2CLKS        0x00200000        /* Each transfer = 2 clock ticks */
+#define DMA_3CLKS        0x00400000        /* Each transfer = 3 clock ticks */
+#define DMA_EN_ENETAUI   DMA_3CLKS         /* Put lance into AUI-cable mode */
+#define DMA_CNTR_DISAB   0x00800000        /* No IRQ when DMA_TERM_CNTR set */
+#define DMA_AUTO_NADDR   0x01000000        /* Use "auto nxt addr" feature */
+#define DMA_SCSI_ON      0x02000000        /* Enable SCSI dma */
+#define DMA_PARITY_OFF   0x02000000        /* HME: disable parity checking */
+#define DMA_LOADED_ADDR  0x04000000        /* Address has been loaded */
+#define DMA_LOADED_NADDR 0x08000000        /* Next address has been loaded */
+
+/* Values describing the burst-size property from the PROM */
+#define DMA_BURST1       0x01
+#define DMA_BURST2       0x02
+#define DMA_BURST4       0x04
+#define DMA_BURST8       0x08
+#define DMA_BURST16      0x10
+#define DMA_BURST32      0x20
+#define DMA_BURST64      0x40
+#define DMA_BURSTBITS    0x7f
+
+/* Determine highest possible final transfer address given a base */
+#define DMA_MAXEND(addr) (0x01000000UL-(((unsigned long)(addr))&0x00ffffffUL))
+
+/* Yes, I hack a lot of elisp in my spare time... */
+#define DMA_ERROR_P(regs)  ((((regs)->cond_reg) & DMA_HNDL_ERROR))
+#define DMA_IRQ_P(regs)    ((((regs)->cond_reg) & (DMA_HNDL_INTR | DMA_HNDL_ERROR)))
+#define DMA_WRITE_P(regs)  ((((regs)->cond_reg) & DMA_ST_WRITE))
+#define DMA_OFF(regs)      ((((regs)->cond_reg) &= (~DMA_ENABLE)))
+#define DMA_INTSOFF(regs)  ((((regs)->cond_reg) &= (~DMA_INT_ENAB)))
+#define DMA_INTSON(regs)   ((((regs)->cond_reg) |= (DMA_INT_ENAB)))
+#define DMA_PUNTFIFO(regs) ((((regs)->cond_reg) |= DMA_FIFO_INV))
+#define DMA_SETSTART(regs, addr)  ((((regs)->st_addr) = (char *) addr))
+#define DMA_BEGINDMA_W(regs) \
+        ((((regs)->cond_reg |= (DMA_ST_WRITE|DMA_ENABLE|DMA_INT_ENAB))))
+#define DMA_BEGINDMA_R(regs) \
+        ((((regs)->cond_reg |= ((DMA_ENABLE|DMA_INT_ENAB)&(~DMA_ST_WRITE)))))
+
+/* For certain DMA chips, we need to disable ints upon irq entry
+ * and turn them back on when we are done.  So in any ESP interrupt
+ * handler you *must* call DMA_IRQ_ENTRY upon entry and DMA_IRQ_EXIT
+ * when leaving the handler.  You have been warned...
+ */
+#define DMA_IRQ_ENTRY(dma, dregs) do { \
+        if(DMA_ISBROKEN(dma)) DMA_INTSOFF(dregs); \
+   } while (0)
+
+#define DMA_IRQ_EXIT(dma, dregs) do { \
+	if(DMA_ISBROKEN(dma)) DMA_INTSON(dregs); \
+   } while(0)
+
+/* Reset the friggin' thing... */
+#define DMA_RESET(dma) do { \
+	struct sparc_dma_registers *regs = dma->regs;                      \
+	/* Let the current FIFO drain itself */                            \
+	sparc_dma_pause(regs, (DMA_FIFO_ISDRAIN));                         \
+	/* Reset the logic */                                              \
+	regs->cond_reg |= (DMA_RST_SCSI);     /* assert */                 \
+	__delay(400);                         /* let the bits set ;) */    \
+	regs->cond_reg &= ~(DMA_RST_SCSI);    /* de-assert */              \
+	sparc_dma_enable_interrupts(regs);    /* Re-enable interrupts */   \
+	/* Enable FAST transfers if available */                           \
+	if(dma->revision>dvmarev1) regs->cond_reg |= DMA_3CLKS;            \
+	dma->running = 0;                                                  \
+} while(0)
+
+extern unsigned long dvma_alloc (unsigned long, unsigned long);
+extern void dvma_free (unsigned long, unsigned long);
+
+#endif /* !(__M68K_DVMA_H) */
diff -urN linux-2.2.8-pre7/include/asm-m68k/floppy.h linux/include/asm-m68k/floppy.h
--- linux-2.2.8-pre7/include/asm-m68k/floppy.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/floppy.h	Mon Dec  3 18:46:55 2001
@@ -0,0 +1,239 @@
+/*
+ * Q40 Architecture specific parts of the Floppy driver
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1999
+ */
+
+#include <asm/io.h>
+
+#include <linux/vmalloc.h>
+
+
+asmlinkage void floppy_hardint(int irq, void *dev_id, struct pt_regs * regs);
+
+#define MAX_DMA_ADDRESS   0x00  /* nothing like that */
+
+extern spinlock_t  dma_spin_lock;
+
+static __inline__ unsigned long claim_dma_lock(void)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&dma_spin_lock, flags);
+	return flags;
+}
+
+static __inline__ void release_dma_lock(unsigned long flags)
+{
+	spin_unlock_irqrestore(&dma_spin_lock, flags);
+}
+
+
+
+#define fd_inb(port)			inb_p(port)
+#define fd_outb(port,value)		outb_p(port,value)
+
+
+#define fd_request_dma()        vdma_request_dma(FLOPPY_DMA,"floppy")
+/*#define fd_free_dma()           */
+
+
+#define fd_get_dma_residue()    vdma_get_dma_residue(FLOPPY_DMA)
+#define fd_dma_mem_alloc(size)	vdma_mem_alloc(size)
+#define fd_dma_setup(addr, size, mode, io) vdma_dma_setup(addr, size, mode, io)
+
+
+#define fd_enable_irq()           /* nothing... */
+#define fd_disable_irq()          /* nothing... */
+#define fd_free_irq()		free_irq(FLOPPY_IRQ, NULL)
+
+#define fd_free_dma()             /* nothing */
+
+/* No 64k boundary crossing problems on Q40 - no DMA at all */
+#define CROSS_64KB(a,s) (0)
+
+#define DMA_MODE_READ  0x44    /* i386 look-alike */
+#define DMA_MODE_WRITE 0x48
+
+
+static int q40_floppy_init(void)
+{
+  use_virtual_dma =1;
+  /* FLOPPY_IRQ=6; */
+
+  if (MACH_IS_Q40)  
+    return 0x3f0;
+  else
+    return -1;
+}
+
+
+
+
+/*
+ * Again, the CMOS information doesn't work on the Q40..
+ */
+#define FLOPPY0_TYPE 6
+#define FLOPPY1_TYPE 0
+
+
+
+
+#define FLOPPY_MOTOR_MASK 0xf0
+
+
+
+
+/* basically PC init + set use_virtual_dma */
+#define  FDC1 q40_floppy_init()
+static int FDC2 = -1;
+
+
+#define N_FDC 1
+#define N_DRIVE 8
+
+
+
+/* vdma stuff adapted from asm-i386/floppy.h */
+
+static int virtual_dma_count=0;
+static int virtual_dma_residue=0;
+static char *virtual_dma_addr=0;
+static int virtual_dma_mode=0;
+static int doing_pdma=0;
+
+
+
+static int fd_request_irq(void)
+{
+  return request_irq(FLOPPY_IRQ, floppy_hardint,SA_INTERRUPT,
+						   "floppy", NULL);
+}
+
+/*#define SLOW_DOWN do{outb(0,0x80);}while(0)*/
+#define SLOW_DOWN do{int count=1;do{if(!jiffies)break;}while(count-->0);}while(0)
+
+asmlinkage void floppy_hardint(int irq, void *dev_id, struct pt_regs * regs)
+{
+	register unsigned char st;
+
+#undef TRACE_FLPY_INT
+#define NO_FLOPPY_ASSEMBLER
+
+#ifdef TRACE_FLPY_INT 
+	static int calls=0;
+	static int bytes=0;
+	static int dma_wait=0;
+#endif
+	if(!doing_pdma) {
+		floppy_interrupt(irq, dev_id, regs);
+		return;
+	}
+
+#ifdef TRACE_FLPY_INT
+	if(!calls)
+		bytes = virtual_dma_count;
+#endif
+
+	{
+		register int lcount;
+		register char *lptr;
+
+		/* serve 1st byte fast: */
+
+		st=1;
+		for(lcount=virtual_dma_count, lptr=virtual_dma_addr; 
+		    lcount; lcount--, lptr++) {
+			st=inb(virtual_dma_port+4) & 0xa0 ;
+			if(st != 0xa0) 
+				break;
+			if(virtual_dma_mode)
+				outb_p(*lptr, virtual_dma_port+5);
+			else
+				*lptr = inb_p(virtual_dma_port+5);
+		}
+
+		virtual_dma_count = lcount;
+		virtual_dma_addr = lptr;
+		st = inb(virtual_dma_port+4);
+	}
+
+#ifdef TRACE_FLPY_INT
+	calls++;
+#endif
+	if(st == 0x20)
+		return;
+	if(!(st & 0x20)) {
+		virtual_dma_residue += virtual_dma_count;
+		virtual_dma_count=0;
+#ifdef TRACE_FLPY_INT
+		printk("count=%x, residue=%x calls=%d bytes=%d dma_wait=%d\n", 
+		       virtual_dma_count, virtual_dma_residue, calls, bytes,
+		       dma_wait);
+		calls = 0;
+		dma_wait=0;
+#endif
+		doing_pdma = 0;
+		floppy_interrupt(irq, dev_id, regs);
+		return;
+	}
+#ifdef TRACE_FLPY_INT
+	if(!virtual_dma_count)
+		dma_wait++;
+#endif
+}
+
+
+
+static int vdma_request_dma(unsigned int dmanr, const char * device_id)
+{
+	return 0;
+}
+
+
+static int vdma_get_dma_residue(unsigned int dummy)
+{
+	return virtual_dma_count + virtual_dma_residue;
+}
+
+
+static unsigned long vdma_mem_alloc(unsigned long size)
+{
+	return (unsigned long) vmalloc(size);
+
+}
+
+static void _fd_dma_mem_free(unsigned long addr, unsigned long size)
+{
+        vfree((void *)addr);
+}
+#define fd_dma_mem_free(addr,size) _fd_dma_mem_free(addr, size)
+
+
+/* choose_dma_mode ???*/
+
+static int vdma_dma_setup(char *addr, unsigned long size, int mode, int io)
+{
+	doing_pdma = 1;
+	virtual_dma_port = io;
+	virtual_dma_mode = (mode  == DMA_MODE_WRITE);
+	virtual_dma_addr = addr;
+	virtual_dma_count = size;
+	virtual_dma_residue = 0;
+	return 0;
+}
+
+
+
+static void fd_disable_dma(void)
+{
+	doing_pdma = 0;
+	virtual_dma_residue += virtual_dma_count;
+	virtual_dma_count=0;
+}
+
+
+
diff -urN linux-2.2.8-pre7/include/asm-m68k/ide.h linux/include/asm-m68k/ide.h
--- linux-2.2.8-pre7/include/asm-m68k/ide.h	Tue Jan 19 10:58:34 1999
+++ linux/include/asm-m68k/ide.h	Mon Dec  3 18:46:55 2001
@@ -45,22 +45,38 @@
 #include <asm/macints.h>
 #endif
 
+
+typedef unsigned int   q40ide_ioreg_t;
+
+
 typedef unsigned char * ide_ioreg_t;
 
+
 #ifndef MAX_HWIFS
 #define MAX_HWIFS	4	/* same as the other archs */
 #endif
 
-static __inline int ide_default_irq (ide_ioreg_t base)
+int q40ide_default_irq(q40ide_ioreg_t);
+
+static __inline__ int ide_default_irq(ide_ioreg_t base)
 {
-	return 0;
+        if (MACH_IS_Q40)
+	      return q40ide_default_irq((q40ide_ioreg_t) base);
+	else return 0;
 }
 
+
 /*
  *  Can we do this in a generic manner??
  */
+void q40_ide_init_hwif_ports (q40ide_ioreg_t *p, q40ide_ioreg_t base, int *irq);
+
 static __inline__ void ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq)
 {
+#ifdef CONFIG_Q40
+    if (MACH_IS_Q40)
+      return q40_ide_init_hwif_ports((q40ide_ioreg_t *)p,(q40ide_ioreg_t)base,irq);
+#endif
     printk("ide_init_hwif_ports: must not be called\n");
 }
 
@@ -86,6 +102,10 @@
 	if (MACH_IS_AMIGA)
 		return request_irq(irq, handler, 0, device, dev_id);
 #endif /* CONFIG_AMIGA */
+#ifdef CONFIG_Q40
+	if (MACH_IS_Q40)
+	  	return request_irq(irq, handler, 0, device, dev_id);
+#endif /* CONFIG_Q40*/
 #ifdef CONFIG_MAC
 	if (MACH_IS_MAC)
 #if 0	/* MSch Hack: maybe later we'll call ide_intr without a wrapper */
@@ -103,6 +123,10 @@
 	if (MACH_IS_AMIGA)
 		free_irq(irq, dev_id);
 #endif /* CONFIG_AMIGA */
+#ifdef CONFIG_Q40
+	if (MACH_IS_Q40)
+	  	free_irq(irq, dev_id);
+#endif /* CONFIG_Q40*/
 #ifdef CONFIG_MAC
 	if (MACH_IS_MAC)
 		nubus_free_irq(12);
@@ -119,10 +143,18 @@
 
 static __inline__ void ide_request_region (ide_ioreg_t from, unsigned int extent, const char *name)
 {
+#ifdef CONFIG_Q40
+        if (MACH_IS_Q40)
+            request_region((q40ide_ioreg_t)from,extent,name);
+#endif
 }
 
 static __inline__ void ide_release_region (ide_ioreg_t from, unsigned int extent)
 {
+#ifdef CONFIG_Q40
+        if (MACH_IS_Q40)
+            release_region((q40ide_ioreg_t)from,extent);
+#endif
 }
 
 #undef SUPPORT_SLOW_DATA_PORTS
@@ -131,14 +163,36 @@
 #undef SUPPORT_VLB_SYNC
 #define SUPPORT_VLB_SYNC 0
 
+/* this definition is used only on startup .. */
+#ifndef CONFIG_Q40
 #undef HD_DATA
 #define HD_DATA NULL
+#else
+#ifdef MACH_Q40_ONLY
+#undef HD_DATA
+#define HD_DATA ((ide_ioreg_t)0x1f0)
+#else
+#undef HD_DATA
+#define HD_DATA   (MACH_IS_Q40 ? (ide_ioreg_t)0x1f0 : 0)
+#endif
+#endif
+
 
 #define insl(data_reg, buffer, wcount) insw(data_reg, buffer, (wcount)<<1)
 #define outsl(data_reg, buffer, wcount) outsw(data_reg, buffer, (wcount)<<1)
 
+#ifdef CONFIG_Q40
+#ifdef MACH_Q40_ONLY
+#define ADDR_TRANS(_addr_) (Q40_ISA_IO_W(_addr_))
+#else
+#define ADDR_TRANS(_addr_) (MACH_IS_Q40 ? ((unsigned char *)Q40_ISA_IO_W(_addr_)) : (_addr_))
+#endif
+#else
+#define ADDR_TRANS(_addr_) (_addr_)
+#endif
+
 #define insw(port, buf, nr) ({				\
-	unsigned char *_port = (unsigned char *)(port);	\
+	unsigned char *_port = (unsigned char *) ADDR_TRANS(port);	\
 	unsigned char *_buf = (buf);			\
 	int _nr = (nr);					\
 	unsigned long _tmp;				\
@@ -179,7 +233,7 @@
 })
 
 #define outsw(port, buf, nr) ({				\
-	unsigned char *_port = (unsigned char *)(port);	\
+	unsigned char *_port = (unsigned char *) ADDR_TRANS(port);	\
 	unsigned char *_buf = (buf);			\
 	int _nr = (nr);					\
 	unsigned long _tmp;				\
@@ -219,7 +273,7 @@
 	}						\
 })
 
-#ifdef CONFIG_ATARI
+#if defined(CONFIG_ATARI) || defined(CONFIG_Q40)
 #define insl_swapw(data_reg, buffer, wcount) \
     insw_swapw(data_reg, buffer, (wcount)<<1)
 #define outsl_swapw(data_reg, buffer, wcount) \
@@ -236,7 +290,7 @@
 		 rolw  #8,%/d0; \
 		 movew %/d0,%/a1@+; \
 		 dbra %/d6,1b" : \
-		: "g" (port), "g" (buf), "g" (nr) \
+		: "g" (ADDR_TRANS(port)), "g" (buf), "g" (nr) \
 		: "d0", "a0", "a1", "d6"); \
     else \
 	__asm__ __volatile__ \
@@ -270,8 +324,9 @@
 		 rolw  #8,%/d0; \
 		 movew %/d0,%/a1@+; \
 		 dbra %/d6,1b" : \
-		: "g" (port), "g" (buf), "g" (nr) \
-		: "d0", "a0", "a1", "d6")
+		: "g" (ADDR_TRANS(port)), "g" (buf), "g" (nr) \
+		: "d0", "a0", "a1", "d6") 
+
 
 #define outsw_swapw(port, buf, nr) \
     if ((nr) % 8) \
@@ -284,7 +339,7 @@
 		 rolw  #8,%/d0; \
 		 movew %/d0,%/a0@; \
 		 dbra %/d6,1b" : \
-		: "g" (port), "g" (buf), "g" (nr) \
+		: "g" (ADDR_TRANS(port)), "g" (buf), "g" (nr) \
 		: "d0", "a0", "a1", "d6"); \
     else \
 	__asm__ __volatile__ \
@@ -318,7 +373,7 @@
 		 rolw  #8,%/d0; \
 		 movew %/d0,%/a0@; \
 		 dbra %/d6,1b" : \
-		: "g" (port), "g" (buf), "g" (nr) \
+		: "g" (ADDR_TRANS(port)), "g" (buf), "g" (nr) \
 		: "d0", "a0", "a1", "d6")
 
 #endif /* CONFIG_ATARI */
diff -urN linux-2.2.8-pre7/include/asm-m68k/keyboard.h linux/include/asm-m68k/keyboard.h
--- linux-2.2.8-pre7/include/asm-m68k/keyboard.h	Mon Apr 26 10:53:51 1999
+++ linux/include/asm-m68k/keyboard.h	Mon Dec  3 18:46:55 2001
@@ -16,26 +16,46 @@
 
 #include <asm/machdep.h>
 
+#ifdef CONFIG_Q40
+#include <asm/q40_keyboard.h>
+#endif
+
 static __inline__ int kbd_setkeycode(unsigned int scancode,
 				     unsigned int keycode)
 {
+#ifdef CONFIG_Q40
+    if (MACH_IS_Q40)
+        return q40kbd_setkeycode(scancode,keycode);
+#endif
     return -EOPNOTSUPP;
 }
 
 static __inline__ int kbd_getkeycode(unsigned int scancode)
 {
+#ifdef CONFIG_Q40
+    if (MACH_IS_Q40)
+        return q40kbd_getkeycode(scancode);
+#endif
     return scancode > 127 ? -EINVAL : scancode;
 }
 
 static __inline__ int kbd_translate(unsigned char scancode,
 				    unsigned char *keycode, char raw_mode)
 {
+#ifdef CONFIG_Q40
+    if (MACH_IS_Q40)
+        return q40kbd_translate(scancode,keycode,raw_mode);
+#endif
     *keycode = scancode;
     return 1;
 }
 
 static __inline__ char kbd_unexpected_up(unsigned char keycode)
 {
+#ifdef CONFIG_Q40
+    if (MACH_IS_Q40)
+        return q40kbd_unexpected_up(keycode);
+#endif
     return 0200;
 }
 
diff -urN linux-2.2.8-pre7/include/asm-m68k/mvme147hw.h linux/include/asm-m68k/mvme147hw.h
--- linux-2.2.8-pre7/include/asm-m68k/mvme147hw.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/mvme147hw.h	Mon Dec  3 18:46:55 2001
@@ -0,0 +1,110 @@
+#ifndef _MVME147HW_H_
+#define _MVME147HW_H_
+
+typedef struct {
+	unsigned char
+		ctrl,
+		bcd_sec,
+		bcd_min,
+		bcd_hr,
+		bcd_dow,
+		bcd_dom,
+		bcd_mth,
+		bcd_year;
+} MK48T02;
+
+#define RTC_WRITE	0x80
+#define RTC_READ	0x40
+#define RTC_STOP	0x20
+
+#define m147_rtc ((MK48T02 * volatile)0xfffe07f8)
+
+
+struct pcc_regs {
+   volatile u_long 	dma_tadr;
+   volatile u_long	dma_dadr;
+   volatile u_long	dma_bcr;
+   volatile u_long	dma_hr;
+   volatile u_short	t1_preload;
+   volatile u_short	t1_count;
+   volatile u_short	t2_preload;
+   volatile u_short	t2_count;
+   volatile u_char	t1_int_cntrl;
+   volatile u_char	t1_cntrl;
+   volatile u_char	t2_int_cntrl;
+   volatile u_char	t2_cntrl;
+   volatile u_char	ac_fail;
+   volatile u_char	watchdog;
+   volatile u_char	lpt_intr;
+   volatile u_char	lpt_cntrl;
+   volatile u_char	dma_intr;
+   volatile u_char	dma_cntrl;
+   volatile u_char	bus_error;
+   volatile u_char	dma_status;
+   volatile u_char	abort;
+   volatile u_char	ta_fnctl;
+   volatile u_char	serial_cntrl;
+   volatile u_char	general_cntrl;
+   volatile u_char	lan_cntrl;
+   volatile u_char	general_status;
+   volatile u_char	scsi_interrupt;
+   volatile u_char	slave;
+   volatile u_char	soft1_cntrl;
+   volatile u_char	int_base;
+   volatile u_char	soft2_cntrl;
+   volatile u_char	revision_level;
+   volatile u_char	lpt_data;
+   volatile u_char	lpt_status;
+   };
+
+#define m147_pcc ((struct pcc_regs * volatile)0xfffe1000)
+
+
+#define PCC_INT_ENAB		0x08
+
+#define PCC_TIMER_INT_CLR	0x80
+#define PCC_TIMER_PRELOAD	63936l
+
+#define PCC_LEVEL_ABORT		0x07
+#define PCC_LEVEL_SERIAL	0x04
+#define PCC_LEVEL_ETH		0x04
+#define PCC_LEVEL_TIMER1	0x04
+#define PCC_LEVEL_SCSI_PORT	0x04
+#define PCC_LEVEL_SCSI_DMA	0x04
+
+#define PCC_IRQ_AC_FAIL		0x40
+#define PCC_IRQ_BERR		0x41
+#define PCC_IRQ_ABORT		0x42
+/* #define PCC_IRQ_SERIAL	0x43 */
+#define PCC_IRQ_PRINTER		0x47
+#define PCC_IRQ_TIMER1		0x48
+#define PCC_IRQ_TIMER2		0x49
+#define PCC_IRQ_SOFTWARE1	0x4a
+#define PCC_IRQ_SOFTWARE2	0x4b
+
+
+#define M147_SCC_A_ADDR		0xfffe3002
+#define M147_SCC_B_ADDR		0xfffe3000
+
+#define MVME147_IRQ_SCSI_PORT	0x45
+#define MVME147_IRQ_SCSI_DMA	0x46
+
+/* SCC interrupts, for MVME162 */
+
+#define MVME147_IRQ_TYPE_PRIO	0
+#define MVME147_IRQ_SCC_BASE		0x60
+#define MVME147_IRQ_SCCB_TX		0x60
+#define MVME147_IRQ_SCCB_STAT		0x62
+#define MVME147_IRQ_SCCB_RX		0x64
+#define MVME147_IRQ_SCCB_SPCOND		0x66
+#define MVME147_IRQ_SCCA_TX		0x68
+#define MVME147_IRQ_SCCA_STAT		0x6a
+#define MVME147_IRQ_SCCA_RX		0x6c
+#define MVME147_IRQ_SCCA_SPCOND		0x6e
+
+#define MVME147_LANCE_BASE	0xfffe1800
+#define MVME147_LANCE_IRQ	0x44
+
+#define ETHERNET_ADDRESS 0xfffe0778
+
+#endif
diff -urN linux-2.2.8-pre7/include/asm-m68k/oplib.h linux/include/asm-m68k/oplib.h
--- linux-2.2.8-pre7/include/asm-m68k/oplib.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/oplib.h	Mon Dec  3 18:46:55 2001
@@ -0,0 +1,8 @@
+/*
+ * prototypes for dummy prom_* routines
+ */
+
+extern int prom_getintdefault(int node, char *property, int defval);
+extern int prom_getbool(int node, char *prop);
+extern void prom_printf(char *fmt, ...);
+extern void prom_halt(void) __attribute__ ((noreturn));
diff -urN linux-2.2.8-pre7/include/asm-m68k/page.h linux/include/asm-m68k/page.h
--- linux-2.2.8-pre7/include/asm-m68k/page.h	Tue Jan 19 10:58:34 1999
+++ linux/include/asm-m68k/page.h	Mon Dec  3 18:46:55 2001
@@ -110,7 +110,22 @@
 /* This handles the memory map.. */
 #define PAGE_OFFSET		0
 #define __pa(x)			((unsigned long)(x)-PAGE_OFFSET)
-#define __va(x)			((void *)((unsigned long)(x)+PAGE_OFFSET))
+/*
+ * A hacky workaround for the problems with mmap() of frame buffer
+ * memory in the lower 16MB physical memoryspace.
+ *
+ * This is a short term solution, we will have to deal properly
+ * with this in 2.3.x.
+ */
+extern inline void *__va(unsigned long physaddr)
+{
+#ifdef CONFIG_AMIGA
+	if (MACH_IS_AMIGA && (physaddr < 16*1024*1024))
+		return (void *)0xffffffff;
+	else
+#endif
+		return (void *)(physaddr+PAGE_OFFSET);
+}
 #define MAP_NR(addr)		(__pa(addr) >> PAGE_SHIFT)
 
 #endif /* __KERNEL__ */
diff -urN linux-2.2.8-pre7/include/asm-m68k/pgtable.h linux/include/asm-m68k/pgtable.h
--- linux-2.2.8-pre7/include/asm-m68k/pgtable.h	Wed Mar 10 18:11:51 1999
+++ linux/include/asm-m68k/pgtable.h	Mon Dec  3 18:46:55 2001
@@ -507,6 +507,7 @@
 	if (tsk == current) {
 		if (CPU_IS_040_OR_060)
 			__asm__ __volatile__ (".chip 68040\n\t"
+					      "pflushan\n\t"
 					      "movec %0,%%urp\n\t"
 					      ".chip 68k"
 					      : : "r" (tsk->tss.crp[1]));
@@ -514,10 +515,22 @@
 			unsigned long tmp;
 			__asm__ __volatile__ ("movec  %%cacr,%0\n\t"
 					      "orw #0x0808,%0\n\t"
-					      "movec %0,%%cacr\n\t"
-					      "pmove %1,%%crp\n\t"
-					      : "=d" (tmp)
-					      : "m" (tsk->tss.crp[0]));
+					      "movec %0,%%cacr"
+					      : "=d" (tmp));
+			/* For a 030-only kernel, avoid flushing the whole
+			   ATC, we only need to flush the user entries.
+			   The 68851 does this by itself.  Avoid a runtime
+			   check here.  */
+			__asm__ __volatile__ (
+#ifdef CPU_M68030_ONLY
+					      ".chip 68030\n\t"
+					      "pmovefd %0,%%crp\n\t"
+					      ".chip 68k\n\t"
+					      "pflush #0,#4"
+#else
+					      "pmove %0,%%crp"
+#endif
+					      : : "m" (tsk->tss.crp[0]));
 		}
 	}
 }
diff -urN linux-2.2.8-pre7/include/asm-m68k/q40_keyboard.h linux/include/asm-m68k/q40_keyboard.h
--- linux-2.2.8-pre7/include/asm-m68k/q40_keyboard.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/q40_keyboard.h	Mon Dec  3 18:46:55 2001
@@ -0,0 +1,54 @@
+/*
+ *  linux/include/asm-m68k/q40_keyboard.h
+ *
+ *  Created 
+ */
+
+/*
+ *  This file contains the Q40 specific keyboard definitions
+ */
+
+
+#include <linux/config.h> /* CONFIG_MAGIC_SYSRQ */
+
+
+
+#ifdef __KERNEL__
+
+
+#include <asm/machdep.h>
+
+
+
+extern int q40kbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int q40kbd_getkeycode(unsigned int scancode);
+extern int q40kbd_pretranslate(unsigned char scancode, char raw_mode);
+extern int q40kbd_translate(unsigned char scancode, unsigned char *keycode,
+			   char raw_mode);
+extern char q40kbd_unexpected_up(unsigned char keycode);
+extern void q40kbd_leds(unsigned char leds);
+extern int q40kbd_is_sysrq(unsigned char keycode);
+extern void q40kbd_init_hw(void);
+extern unsigned char q40kbd_sysrq_xlate[128];
+
+
+#if 0
+#define kbd_setkeycode		q40kbd_setkeycode
+#define kbd_getkeycode		q40kbd_getkeycode
+#define kbd_pretranslate	q40kbd_pretranslate
+#define kbd_translate		q40kbd_translate
+#define kbd_unexpected_up	q40kbd_unexpected_up
+#define kbd_leds		q40kbd_leds
+#define kbd_init_hw		q40kbd_init_hw
+#define kbd_is_sysrq		q40kbd_is_sysrq
+#define kbd_sysrq_xlate		q40kbd_sysrq_xlate
+
+
+#define SYSRQ_KEY 0x54
+#endif
+#endif /* __KERNEL__ */
+
+
+
+
+
diff -urN linux-2.2.8-pre7/include/asm-m68k/q40_master.h linux/include/asm-m68k/q40_master.h
--- linux-2.2.8-pre7/include/asm-m68k/q40_master.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/q40_master.h	Mon Dec  3 18:46:55 2001
@@ -0,0 +1,75 @@
+/* 
+ * Q40 master Chip Control 
+ * RTC stuff merged for compactnes..
+*/
+
+#if 1
+#define q40_master_addr 0xff000000
+#define q40_rtc_addr    0xff021ffc
+#else
+extern unsigned long q40_master_addr;  /* wherever it is mapped ... */
+extern unsigned long q40_rtc_addr;
+#endif
+
+#define IIRQ_REG            0x0       /* internal IRQ reg */
+#define EIRQ_REG            0x4       /* external ... */
+#define KEYCODE_REG         0x1c      /* value of received scancode  */
+#define DISPLAY_CONTROL_REG 0x18
+#define FRAME_CLEAR_REG     0x24
+
+#define INTERRUPT_REG       IIRQ_REG  /* "native" ints */
+#define KEY_IRQ_ENABLE_REG  0x08      /**/
+#define KEYBOARD_UNLOCK_REG 0x20      /* clear kb int */
+
+#define SAMPLE_ENABLE_REG   0x14      /* generate SAMPLE ints */
+#define SAMPLE_RATE_REG     0x28
+#define SAMPLE_CLEAR_REG    0x28
+#define SAMPLE_LOW          0x00
+#define SAMPLE_HIGH         0x01
+
+#define FRAME_RATE_REG       0x38      /* generate FRAME ints at 200 HZ rate */
+
+#if 0
+#define SER_ENABLE_REG      0x0c      /* allow serial ints to be generated */
+#endif
+#define EXT_ENABLE_REG      0x10      /* ... rest of the ISA ints ... */
+
+#define master_inb(_reg_)           (*(((unsigned char *)q40_master_addr)+_reg_))
+#define master_outb(_b_,_reg_)      (*(((unsigned char *)q40_master_addr)+_reg_)=(_b_))
+
+
+/* define some Q40 specific ints */
+#include "q40ints.h"
+
+/* RTC defines */
+
+#define Q40_RTC_BASE (q40_rtc_addr)
+
+#define RTC_YEAR        (*(unsigned char *)(Q40_RTC_BASE+0))
+#define RTC_MNTH        (*(unsigned char *)(Q40_RTC_BASE-4))
+#define RTC_DATE        (*(unsigned char *)(Q40_RTC_BASE-8))
+#define RTC_DOW         (*(unsigned char *)(Q40_RTC_BASE-12))
+#define RTC_HOUR        (*(unsigned char *)(Q40_RTC_BASE-16))
+#define RTC_MINS        (*(unsigned char *)(Q40_RTC_BASE-20))
+#define RTC_SECS        (*(unsigned char *)(Q40_RTC_BASE-24))
+#define RTC_CTRL        (*(unsigned char *)(Q40_RTC_BASE-28))
+
+
+#if 0
+struct RTC_STRUCT{ 
+  unsigned char bcd_year;
+  unsigned char bcd_mth;
+  unsigned char bcd_dom;
+  unsigned char bcd_dayofweek;
+  unsigned char bcd_hr;
+  unsigned char bcd_min;
+  unsigned char bcd_sec;
+  unsigned char ctrl;
+};
+typedef struct RTC_STRUCT *RtcPtr_t;
+#endif
+
+
+/* some control bits */
+#define RTC_READ   64  /* prepare for reading */
+#define RTC_WRITE  128
diff -urN linux-2.2.8-pre7/include/asm-m68k/q40ints.h linux/include/asm-m68k/q40ints.h
--- linux-2.2.8-pre7/include/asm-m68k/q40ints.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/q40ints.h	Mon Dec  3 18:46:55 2001
@@ -0,0 +1,29 @@
+/*
+ * contains some Q40 related interrupt definitions
+ */
+
+#define Q40_IRQ_MAX      (34)
+
+#define Q40_IRQ_TIMER    (34)
+#define Q40_IRQ_KEYBOARD (32)
+#define Q40_IRQ_FRAME    (33)
+
+
+/* masks for interrupt regiosters*/
+/* internal, IIRQ_REG */
+#define IRQ_KEYB_MASK    (2)
+#define IRQ_SER_MASK     (1<<2)
+#define IRQ_FRAME_MASK   (1<<3)
+#define IRQ_EXT_MASK     (1<<4)    /* is a EIRQ */
+/* eirq, EIRQ_REG */
+#define IRQ3_MASK        (1)
+#define IRQ4_MASK        (1<<1)
+#define IRQ5_MASK        (1<<2)
+#define IRQ6_MASK        (1<<3)
+#define IRQ7_MASK        (1<<4)
+#define IRQ10_MASK       (1<<5)
+#define IRQ14_MASK       (1<<6)
+#define IRQ15_MASK       (1<<7)
+
+extern unsigned long q40_probe_irq_on (void);
+extern int q40_probe_irq_off (unsigned long irqs);
diff -urN linux-2.2.8-pre7/include/asm-m68k/scatterlist.h linux/include/asm-m68k/scatterlist.h
--- linux-2.2.8-pre7/include/asm-m68k/scatterlist.h	Wed Apr 23 19:01:27 1997
+++ linux/include/asm-m68k/scatterlist.h	Mon Dec  3 18:46:55 2001
@@ -6,6 +6,14 @@
     char * alt_address; /* Location of actual if address is a 
 			 * dma indirect buffer.  NULL otherwise */
     unsigned int length;
+    unsigned long dvma_address;
+};
+
+struct mmu_sglist {
+        char *addr;
+        char *__dont_touch;
+        unsigned int len;
+        unsigned long dvma_addr;
 };
 
 /* This is bogus and should go away. */
diff -urN linux-2.2.8-pre7/include/asm-m68k/semaphore-helper.h linux/include/asm-m68k/semaphore-helper.h
--- linux-2.2.8-pre7/include/asm-m68k/semaphore-helper.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/semaphore-helper.h	Mon Dec  3 18:46:55 2001
@@ -0,0 +1,136 @@
+#ifndef _M68K_SEMAPHORE_HELPER_H
+#define _M68K_SEMAPHORE_HELPER_H
+
+/*
+ * SMP- and interrupt-safe semaphores helper functions.
+ *
+ * (C) Copyright 1996 Linus Torvalds
+ *
+ * m68k version by Andreas Schwab
+ */
+
+/*
+ * These two _must_ execute atomically wrt each other.
+ */
+static inline void wake_one_more(struct semaphore * sem)
+{
+	atomic_inc(&sem->waking);
+}
+
+static inline int waking_non_zero(struct semaphore *sem)
+{
+	int ret;
+#ifndef CONFIG_RMW_INSNS
+	unsigned long flags;
+
+	spin_lock_irqsave(&semaphore_wake_lock, flags);
+	ret = 0;
+	if (atomic_read(&sem->waking) > 0) {
+		atomic_dec(&sem->waking);
+		ret = 1;
+	}
+	spin_unlock_irqrestore(&semaphore_wake_lock, flags);
+#else
+	int tmp1, tmp2;
+
+	__asm__ __volatile__
+	  ("1:	movel	%1,%2\n"
+	   "    jle	2f\n"
+	   "	subql	#1,%2\n"
+	   "	casl	%1,%2,%3\n"
+	   "	jne	1b\n"
+	   "	moveq	#1,%0\n"
+	   "2:"
+	   : "=d" (ret), "=d" (tmp1), "=d" (tmp2)
+	   : "m" (sem->waking), "0" (0), "1" (sem->waking));
+#endif
+
+	return ret;
+}
+
+/*
+ * waking_non_zero_interruptible:
+ *	1	got the lock
+ *	0	go to sleep
+ *	-EINTR	interrupted
+ */
+static inline int waking_non_zero_interruptible(struct semaphore *sem,
+						struct task_struct *tsk)
+{
+	int ret;
+#ifndef CONFIG_RMW_INSNS
+	unsigned long flags;
+
+	spin_lock_irqsave(&semaphore_wake_lock, flags);
+	ret = 0;
+	if (atomic_read(&sem->waking) > 0) {
+		atomic_dec(&sem->waking);
+		ret = 1;
+	} else if (signal_pending(tsk)) {
+		atomic_inc(&sem->count);
+		ret = -EINTR;
+	}
+	spin_unlock_irqrestore(&semaphore_wake_lock, flags);
+#else
+	int tmp1, tmp2;
+
+	__asm__ __volatile__
+	  ("1:	movel	%1,%2\n"
+	   "	jle	2f\n"
+	   "	subql	#1,%2\n"
+	   "	casl	%1,%2,%3\n"
+	   "	jne	1b\n"
+	   "	moveq	#1,%0\n"
+	   "	jra	%a4\n"
+	   "2:"
+	   : "=d" (ret), "=d" (tmp1), "=d" (tmp2)
+	   : "m" (sem->waking), "i" (&&next), "0" (0), "1" (sem->waking));
+	if (signal_pending(tsk)) {
+		atomic_inc(&sem->count);
+		ret = -EINTR;
+	}
+next:
+#endif
+
+	return ret;
+}
+
+/*
+ * waking_non_zero_trylock:
+ *	1	failed to lock
+ *	0	got the lock
+ */
+static inline int waking_non_zero_trylock(struct semaphore *sem)
+{
+	int ret;
+#ifndef CONFIG_RMW_INSNS
+	unsigned long flags;
+
+	spin_lock_irqsave(&semaphore_wake_lock, flags);
+	ret = 1;
+	if (atomic_read(&sem->waking) > 0) {
+		atomic_dec(&sem->waking);
+		ret = 0;
+	} else
+		atomic_inc(&sem->count);
+	spin_unlock_irqrestore(&semaphore_wake_lock, flags);
+#else
+	int tmp1, tmp2;
+
+	__asm__ __volatile__
+	  ("1:	movel	%1,%2\n"
+	   "    jle	2f\n"
+	   "	subql	#1,%2\n"
+	   "	casl	%1,%2,%3\n"
+	   "	jne	1b\n"
+	   "	moveq	#0,%0\n"
+	   "2:"
+	   : "=d" (ret), "=d" (tmp1), "=d" (tmp2)
+	   : "m" (sem->waking), "0" (1), "1" (sem->waking));
+	if (ret)
+		atomic_inc(&sem->count);
+#endif
+	return ret;
+}
+
+#endif
diff -urN linux-2.2.8-pre7/include/asm-m68k/semaphore.h linux/include/asm-m68k/semaphore.h
--- linux-2.2.8-pre7/include/asm-m68k/semaphore.h	Tue Jan 19 10:58:34 1999
+++ linux/include/asm-m68k/semaphore.h	Mon Dec  3 18:46:55 2001
@@ -3,9 +3,10 @@
 
 #include <linux/config.h>
 #include <linux/linkage.h>
-#include <asm/current.h>
+
 #include <asm/system.h>
 #include <asm/atomic.h>
+#include <asm/spinlock.h>
 
 /*
  * SMP- and interrupt-safe semaphores..
@@ -17,79 +18,25 @@
 
 struct semaphore {
 	atomic_t count;
-	unsigned long owner, owner_depth;
 	atomic_t waking;
 	struct wait_queue * wait;
 };
 
-/*
- * Because we want the non-contention case to be
- * fast, we save the stack pointer into the "owner"
- * field, and to get the true task pointer we have
- * to do the bit masking. That moves the masking
- * operation into the slow path.
- */
-#define semaphore_owner(sem) \
-	((struct task_struct *)((2*PAGE_MASK) & (sem)->owner))
-
-#define MUTEX ((struct semaphore) { ATOMIC_INIT(1), 0, 0, ATOMIC_INIT(0), NULL })
-#define MUTEX_LOCKED ((struct semaphore) { ATOMIC_INIT(0), 0, 1, ATOMIC_INIT(0), NULL })
+#define MUTEX ((struct semaphore) { ATOMIC_INIT(1), ATOMIC_INIT(0), NULL })
+#define MUTEX_LOCKED ((struct semaphore) { ATOMIC_INIT(0), ATOMIC_INIT(0), NULL })
 
 asmlinkage void __down_failed(void /* special register calling convention */);
 asmlinkage int  __down_failed_interruptible(void  /* params in registers */);
+asmlinkage int  __down_failed_trylock(void  /* params in registers */);
 asmlinkage void __up_wakeup(void /* special register calling convention */);
 
-extern void __down(struct semaphore * sem);
-extern int  __down_interruptible(struct semaphore * sem);
-extern void __up(struct semaphore * sem);
+asmlinkage void __down(struct semaphore * sem);
+asmlinkage int  __down_interruptible(struct semaphore * sem);
+asmlinkage int  __down_trylock(struct semaphore * sem);
+asmlinkage void __up(struct semaphore * sem);
 
 #define sema_init(sem, val)	atomic_set(&((sem)->count), val)
 
-static inline void wake_one_more(struct semaphore * sem)
-{
-	atomic_inc(&sem->waking);
-}
-
-static inline int waking_non_zero(struct semaphore *sem, struct task_struct *tsk)
-{
-#ifndef CONFIG_RMW_INSNS
-	unsigned long flags;
-	int ret = 0;
-
-	save_flags(flags);
-	cli();
-	if (atomic_read(&sem->waking) > 0 || (owner_depth && semaphore_owner(sem) == tsk)) {
-		sem->owner = (unsigned long)tsk;
-		sem->owner_depth++;
-		atomic_dec(&sem->waking);
-		ret = 1;
-	}
-	restore_flags(flags);
-#else
-	int ret, tmp;
-
-	__asm__ __volatile__
-	  ("1:	movel	%2,%0\n"
-	   "    jeq	3f\n"
-	   "2:	movel	%0,%1\n"
-	   "	subql	#1,%1\n"
-	   "	casl	%0,%1,%2\n"
-	   "	jeq	3f\n"
-	   "	tstl	%0\n"
-	   "	jne	2b\n"
-	   "3:"
-	   : "=d" (ret), "=d" (tmp), "=m" (sem->waking));
-
-	ret |= ((sem->owner_depth != 0) && (semaphore_owner(sem) == tsk));
-	if (ret) {
-		sem->owner = (unsigned long)tsk;
-		sem->owner_depth++;
-	}
-
-#endif
-	return ret;
-}
-
 /*
  * This is ugly, but we want the default case to fall through.
  * "down_failed" is a special asm handler that calls the C
@@ -102,8 +49,6 @@
 		"| atomic down operation\n\t"
 		"subql #1,%0@\n\t"
 		"jmi 2f\n\t"
-		"movel %%sp,4(%0)\n"
-		"movel #1,8(%0)\n\t"
 		"1:\n"
 		".section .text.lock,\"ax\"\n"
 		".even\n"
@@ -124,9 +69,6 @@
 		"| atomic interruptible down operation\n\t"
 		"subql #1,%1@\n\t"
 		"jmi 2f\n\t"
-		"movel %%sp,4(%1)\n"
-		"moveql #1,%0\n"
-		"movel %0,8(%1)\n"
 		"clrl %0\n"
 		"1:\n"
 		".section .text.lock,\"ax\"\n"
@@ -140,6 +82,28 @@
 	return result;
 }
 
+extern inline int down_trylock(struct semaphore * sem)
+{
+	register struct semaphore *sem1 __asm__ ("%a1") = sem;
+	register int result __asm__ ("%d0");
+
+	__asm__ __volatile__(
+		"| atomic down trylock operation\n\t"
+		"subql #1,%1@\n\t"
+		"jmi 2f\n\t"
+		"clrl %0\n"
+		"1:\n"
+		".section .text.lock,\"ax\"\n"
+		".even\n"
+		"2:\tpea 1b\n\t"
+		"jbra __down_failed_trylock\n"
+		".previous"
+		: "=d" (result)
+		: "a" (sem1)
+		: "%d0", "memory");
+	return result;
+}
+
 /*
  * Note! This is subtle. We jump to wake people up only if
  * the semaphore was negative (== somebody was waiting on it).
@@ -151,13 +115,13 @@
 	register struct semaphore *sem1 __asm__ ("%a1") = sem;
 	__asm__ __volatile__(
 		"| atomic up operation\n\t"
-		"subql #1,8(%0)\n\t"
 		"addql #1,%0@\n\t"
 		"jle 2f\n"
 		"1:\n"
 		".section .text.lock,\"ax\"\n"
 		".even\n"
-		"2:\tpea 1b\n\t"
+		"2:\t"
+		"pea 1b\n\t"
 		"jbra __up_wakeup\n"
 		".previous"
 		: /* no outputs */
diff -urN linux-2.2.8-pre7/include/asm-m68k/serial.h linux/include/asm-m68k/serial.h
--- linux-2.2.8-pre7/include/asm-m68k/serial.h	Wed Nov 11 11:50:00 1998
+++ linux/include/asm-m68k/serial.h	Mon Dec  3 18:46:55 2001
@@ -1,448 +1,84 @@
 /*
- * include/linux/serial.h
+ * include/asm-m68k/serial.h
  *
- * Copyright (C) 1992 by Theodore Ts'o.
- * 
- * Redistribution of this file is permitted under the terms of the GNU 
- * Public License (GPL)
- */
-
-#ifndef _M68K_SERIAL_H
-#define _M68K_SERIAL_H
-
-
-/* m68k serial port types are numbered from 100 to avoid interference
- * with the PC types (1..4)
- */
-#define PORT_UNKNOWN	0
-#define PORT_8250	1
-#define PORT_16450	2
-#define PORT_16550	3
-#define PORT_16550A	4
-#define PORT_CIRRUS     5
-#define PORT_16650V2	7
-#define PORT_16750	8
-
-#define SER_SCC_NORM	100	/* standard SCC channel */
-#define	SER_SCC_DMA	101	/* SCC channel with DMA support */
-#define	SER_MFP_CTRL	102	/* standard MFP port with modem control signals */
-#define	SER_MFP_BARE	103	/* MFP port without modem controls */
-#define	SER_MIDI	104	/* Atari MIDI */
-#define	SER_AMIGA	105	/* Amiga built-in serial port */
-#define SER_IOEXT	106	/* Amiga GVP IO-Extender (16c552) */
-#define SER_MFC_III	107	/* Amiga BSC Multiface Card III (MC68681) */
-#define SER_WHIPPET	108	/* Amiga Hisoft Whippet PCMCIA (16c550B) */
-#define SER_SCC_MVME	109	/* MVME162/MVME172 ports */
-#define SER_SCC_MAC	110	/* Macintosh SCC channel */
-#define SER_HPDCA	111	/* HP DCA serial */
-#define SER_SCC_BVME	112	/* BVME6000 ports */
-
-struct serial_struct {
-	int	type;
-	int	line;
-	int	port;
-	int	irq;
-	int	flags;
-	int	xmit_fifo_size;
-	int	custom_divisor;
-	int	baud_base;
-	unsigned short	close_delay;
-	char	reserved_char[2];
-	int	hub6;
-	unsigned short	closing_wait; /* time to wait before closing */
-	unsigned short	closing_wait2; /* no longer used... */
-	int	reserved[4];
-};
-
-/*
- * For the close wait times, 0 means wait forever for serial port to
- * flush its output.  65535 means don't wait at all.
- */
-#define ASYNC_CLOSING_WAIT_INF	0
-#define ASYNC_CLOSING_WAIT_NONE	65535
-
-/* This function tables does the abstraction from the underlying
- * hardware:
+ * currently this seems usefull only for a Q40,
+ * its an almost exact copy of ../asm/alpha/serial.h 
  *
- *   init(): Initialize the port as necessary, set RTS and DTR and
- *      enable interrupts. It does not need to set the speed and other
- *      parameters, because change_speed() is called, too.
- *   deinit(): Stop and shutdown the port (e.g. disable interrupts, ...)
- *   enab_tx_int(): Enable or disable the Tx Buffer Empty interrupt
- *      independently from other interrupt sources. If the int is
- *      enabled, the transmitter should also be restarted, i.e. if there
- *      are any chars to be sent, they should be put into the Tx
- *      register. The real en/disabling of the interrupt may be a no-op
- *      if there is no way to do this or it is too complex. This Tx ints
- *      are just disabled to save some interrupts if the transmitter is
- *      stopped anyway. But the restarting must be implemented!
- *   check_custom_divisor(): Check the given custom divisor for legality
- *      and return 0 if OK, non-zero otherwise.
- *   change_speed(): Set port speed, character size, number of stop
- *      bits and parity from the termios structure. If the user wants
- *      to set the speed with a custom divisor, he is required to
- *      check the baud_base first!
- *   throttle(): Set or clear the RTS line according to 'status'.
- *   set_break(): Set or clear the 'Send a Break' flag.
- *   get_serial_info(): Fill in the baud_base and custom_divisor
- *      fields of a serial_struct. It may also modify other fields, if
- *      needed.
- *   get_modem_info(): Return the status of RTS, DTR, DCD, RI, DSR and CTS.
- *   set_modem_info(): Set the status of RTS and DTR according to
- *      'new_dtr' and 'new_rts', resp. 0 = clear, 1 = set, -1 = don't change
- *   ioctl(): Process any port-specific ioctl's. This pointer may be
- *      NULL, if the port has no own ioctl's.
- *   stop_receive(): Turn off the Rx part of the port, so no more characters
- *      will be received. This is called before shutting the port down.
- *   trans_empty(): Return !=0 if there are no more characters still to be
- *      sent out (Tx buffer register and FIFOs empty)
- *   check_open(): Is called before the port is opened. The driver can check
- *      if that's ok and return an error code, or keep track of the opening
- *      even before init() is called. Use deinit() for matching closing of the
- *      port.
- *
- */
-
-struct m68k_async_struct;
-
-typedef struct {
-	void (*init)( struct m68k_async_struct *info );
-	void (*deinit)( struct m68k_async_struct *info, int leave_dtr );
-	void (*enab_tx_int)( struct m68k_async_struct *info, int enab_flag );
-	int  (*check_custom_divisor)( struct m68k_async_struct *info, int baud_base,
-				     int divisor );
-	void (*change_speed)( struct m68k_async_struct *info );
-	void (*throttle)( struct m68k_async_struct *info, int status );
-	void (*set_break)( struct m68k_async_struct *info, int break_flag );
-	void (*get_serial_info)( struct m68k_async_struct *info,
-				struct serial_struct *retinfo );
-	unsigned int (*get_modem_info)( struct m68k_async_struct *info );
-	int  (*set_modem_info)( struct m68k_async_struct *info, int new_dtr,
-			       int new_rts );
-	int  (*ioctl)( struct tty_struct *tty, struct file *file,
-		      struct m68k_async_struct *info, unsigned int cmd,
-		      unsigned long arg );
-	void (*stop_receive)( struct m68k_async_struct *info );
-	int  (*trans_empty)( struct m68k_async_struct *info );
-	int  (*check_open)( struct m68k_async_struct *info, struct tty_struct *tty,
-			   struct file *file );
-} SERIALSWITCH;
-
-/*
- * Definitions for m68k_async_struct (and serial_struct) flags field
  */
-#define ASYNC_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes 
-				   on the callout port */
-#define ASYNC_FOURPORT  0x0002	/* Set OU1, OUT2 per AST Fourport settings */
-#define ASYNC_SAK	0x0004	/* Secure Attention Key (Orange book) */
-#define ASYNC_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */
-
-#define ASYNC_SPD_MASK	0x1030
-#define ASYNC_SPD_HI	0x0010	/* Use 56000 instead of 38400 bps */
-
-#define ASYNC_SPD_VHI	0x0020  /* Use 115200 instead of 38400 bps */
-#define ASYNC_SPD_CUST	0x0030  /* Use user-specified divisor */
-
-#define ASYNC_SKIP_TEST	0x0040 /* Skip UART test during autoconfiguration */
-#define ASYNC_AUTO_IRQ  0x0080 /* Do automatic IRQ during autoconfiguration */
-#define ASYNC_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */
-#define ASYNC_PGRP_LOCKOUT    0x0200 /* Lock out cua opens based on pgrp */
-#define ASYNC_CALLOUT_NOHUP   0x0400 /* Don't do hangups for cua device */
-
-#define ASYNC_HARDPPS_CD	0x0800	/* Call hardpps when CD goes high  */
-
-#define ASYNC_SPD_SHI	0x1000	/* Use 230400 instead of 38400 bps */
-#define ASYNC_SPD_WARP	0x1010	/* Use 460800 instead of 38400 bps */
-
-#define ASYNC_FLAGS	0x1FFF	/* Possible legal async flags */
-#define ASYNC_USR_MASK 0x1430	/* Legal flags that non-privileged
-				 * users can set or reset */
-
-/* Internal flags used only by drivers/char/m68kserial.c */
-#define ASYNC_INITIALIZED	0x80000000 /* Serial port was initialized */
-#define ASYNC_CALLOUT_ACTIVE	0x40000000 /* Call out device is active */
-#define ASYNC_NORMAL_ACTIVE	0x20000000 /* Normal device is active */
-#define ASYNC_BOOT_AUTOCONF	0x10000000 /* Autoconfigure port on bootup */
-#define ASYNC_CLOSING		0x08000000 /* Serial port is closing */
-#define ASYNC_CTS_FLOW		0x04000000 /* Do CTS flow control */
-#define ASYNC_CHECK_CD		0x02000000 /* i.e., CLOCAL */
-
-#define ASYNC_INTERNAL_FLAGS	0xFF000000 /* Internal flags */
-
-/*
- * Serial input interrupt line counters -- external structure
- * Four lines can interrupt: CTS, DSR, RI, DCD
- */
-struct serial_icounter_struct {
-	int cts, dsr, rng, dcd;
-	int rx, tx;
-	int frame, overrun, parity, brk;
-	int buf_overrun;
-	int reserved[9];
-};
 
+#include <linux/config.h>
+#if 0
+#define rs_init serial_rs_init
+#define register_serial serial_register_serial
+#define unregister_serial serial_unregister_serial
+#endif
 
-#ifdef __KERNEL__
 /*
- * This is our internal structure for each serial port's state.
- * 
- * Many fields are paralleled by the structure used by the serial_struct
- * structure.
+ * This assumes you have a 1.8432 MHz clock for your UART.
  *
- * For definitions of the flags field, see tty.h
- */
-
-#include <linux/termios.h>
-#include <linux/tqueue.h>
-
-#include <linux/config.h>	/* for Mac SCC extensions */
-
-#ifdef CONFIG_MAC
-#define NUM_ZSREGS    16
-struct mac_zschannel {
-	volatile unsigned char *control;
-	volatile unsigned char *data;
-};
-struct m68k_async_private;
-#endif
-
-struct m68k_async_struct {
-	int			magic;
-	int			baud_base;
-	int			port;
-	int			irq;
-	int			flags; 		/* defined in tty.h */
-	int			hub6;		/* HUB6 plus one */
-	int			type;
-	struct tty_struct 	*tty;
-	int			read_status_mask;
-	int			ignore_status_mask;
-	int			timeout;
-	int			xmit_fifo_size;
-	int			custom_divisor;
-	int			x_char;	/* xon/xoff character */
-	int			close_delay;
-	unsigned short		closing_wait;
-	unsigned short		closing_wait2;
-	int			IER; 	/* Interrupt Enable Register */
-	int			MCR; 	/* Modem control register */
-	int			MCR_noint; /* MCR with interrupts off */
-	unsigned long		event;
-	unsigned long		last_active;
-	int			line;
-	int			count;	    /* # of fd on device */
-	int			blocked_open; /* # of blocked opens */
-	long			session; /* Session of opening process */
-	long			pgrp; /* pgrp of opening process */
-	unsigned char 		*xmit_buf;
-	int			xmit_head;
-	int			xmit_tail;
-	int			xmit_cnt;
-	struct tq_struct	tqueue;
-	struct termios		normal_termios;
-	struct termios		callout_termios;
-	struct wait_queue	*open_wait;
-	struct wait_queue	*close_wait;
-	struct wait_queue	*delta_msr_wait;
-	struct async_icount	icount;	/* kernel counters for the 4 input interrupts */
-	struct m68k_async_struct	*next_port; /* For the linked list */
-	struct m68k_async_struct	*prev_port;
-	void			*board_base; /* board-base address for use with
-						boards carrying several UART's,
-						like some Amiga boards. */
-	unsigned short		nr_uarts;    /* UART-counter, that indicates
-						how many UART's there are on
-						the board.  If the board has a
-						IRQ-register, this can be used
-						to check if any of the uarts,
-						on the board has requested an
-						interrupt, instead of checking
-						IRQ-registers on all UART's */
-	SERIALSWITCH		*sw;		/* functions to manage this port */
-#ifdef CONFIG_MAC
-	struct m68k_async_private	*private;
+ * It'd be nice if someone built a serial card with a 24.576 MHz
+ * clock, since the 16550A is capable of handling a top speed of 1.5
+ * megabits/second; but this requires the faster clock.
+ */
+#define BASE_BAUD ( 1843200 / 16 )
+
+/* Standard COM flags (except for COM4, because of the 8514 problem) */
+#ifdef CONFIG_SERIAL_DETECT_IRQ
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ)
+#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_AUTO_IRQ)
+#else
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
+#define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF
 #endif
-};
-
-#ifdef CONFIG_MAC
-struct m68k_async_private {
-	struct m68k_async_info	*zs_next;	/* For IRQ servicing chain */
-	struct mac_zschannel	*zs_channel;	/* Channel registers */
-	struct mac_zschannel	*zs_chan_a;	/* A side registers */
-	unsigned char		read_reg_zero;
-
-	char			soft_carrier;	/* Use soft carrier on this */
-	char			break_abort;	/* console, process brk/abrt */
-	char			kgdb_channel;	/* Kgdb running on this channel */
-	char			is_cons;	/* Is this our console. */
-	unsigned char		tx_active;	/* character being xmitted */
-	unsigned char		tx_stopped;	/* output is suspended */
-
-	/* We need to know the current clock divisor
-	 * to read the bps rate the chip has currently
-	 * loaded.
-	 */
-	unsigned char		clk_divisor;	/* May be 1, 16, 32, or 64 */
-	int			zs_baud;
-
-	/* Current write register values */
-	unsigned char		curregs[NUM_ZSREGS];
-
-	/* Values we need to set next opportunity */
-	unsigned char		pendregs[NUM_ZSREGS];
-
-	char			change_needed;
-};
-#endif
-#define SERIAL_MAGIC 0x5301
-
-/*
- * The size of the serial xmit buffer is 1 page, or 4096 bytes
- */
-#define SERIAL_XMIT_SIZE 4096
-
-/*
- * Events are used to schedule things to happen at timer-interrupt
- * time, instead of at rs interrupt time.
- */
-#define RS_EVENT_WRITE_WAKEUP	0
-
-/* number of characters left in xmit buffer before we ask for more */
-#define WAKEUP_CHARS 256
-
-/* Export to allow PCMCIA to use this - Dave Hinds */
-extern int register_serial(struct serial_struct *req);
-extern void unregister_serial(int line);
-extern struct m68k_async_struct rs_table[];
-extern task_queue tq_serial;
-
 
-/*
- * This routine is used by the interrupt handler to schedule
- * processing in the software interrupt portion of the driver.
- */
-static __inline__ void rs_sched_event(struct m68k_async_struct *info, int event)
-{
-	info->event |= 1 << event;
-	queue_task(&info->tqueue, &tq_serial);
-	mark_bh(SERIAL_BH);
-}
-
-static __inline__ void rs_receive_char( struct m68k_async_struct *info,
-					    int ch, int err )
-{
-	struct tty_struct *tty = info->tty;
-	
-	if (tty->flip.count >= TTY_FLIPBUF_SIZE)
-		return;
-	tty->flip.count++;
-	switch(err) {
-	case TTY_BREAK:
-		info->icount.brk++;
-		if (info->flags & ASYNC_SAK)
-			do_SAK(tty);
-		break;
-	case TTY_PARITY:
-		info->icount.parity++;
-		break;
-	case TTY_OVERRUN:
-		info->icount.overrun++;
-		break;
-	case TTY_FRAME:
-		info->icount.frame++;
-		break;
-	}
-	*tty->flip.flag_buf_ptr++ = err;
-	*tty->flip.char_buf_ptr++ = ch;
-	info->icount.rx++;
-	tty_flip_buffer_push(tty);
-}
-
-static __inline__ int rs_get_tx_char( struct m68k_async_struct *info )
-{
-	unsigned char ch;
-	
-	if (info->x_char) {
-		ch = info->x_char;
-		info->icount.tx++;
-		info->x_char = 0;
-		return( ch );
-	}
-
-	if (info->xmit_cnt <= 0 || info->tty->stopped || info->tty->hw_stopped)
-		return( -1 );
-
-	ch = info->xmit_buf[info->xmit_tail++];
-	info->xmit_tail &= SERIAL_XMIT_SIZE - 1;
-	info->icount.tx++;
-	if (--info->xmit_cnt < WAKEUP_CHARS)
-		rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
-	return( ch );
-}
-
-static __inline__ int rs_no_more_tx( struct m68k_async_struct *info )
-{
-	return( info->xmit_cnt <= 0 ||
-			info->tty->stopped ||
-			info->tty->hw_stopped );
-}
-
-static __inline__ void rs_dcd_changed( struct m68k_async_struct *info, int dcd )
-
-{
-	/* update input line counter */
-	info->icount.dcd++;
-	wake_up_interruptible(&info->delta_msr_wait);
-
-	if (info->flags & ASYNC_CHECK_CD) {
-#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR))
-		printk("ttyS%d CD now %s...", info->line,
-		       dcd ? "on" : "off");
-#endif		
-		if (dcd) {
-			wake_up_interruptible(&info->open_wait);
-		} else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
-			     (info->flags & ASYNC_CALLOUT_NOHUP))) {
-#ifdef SERIAL_DEBUG_OPEN
-			printk("scheduling hangup...");
+#ifdef CONFIG_SERIAL_MANY_PORTS
+#define FOURPORT_FLAGS ASYNC_FOURPORT
+#define ACCENT_FLAGS 0
+#define BOCA_FLAGS 0
 #endif
-			if (info->tty)
-				tty_hangup(info->tty);
-		}
-	}
-}
-
-
-void rs_stop( struct tty_struct *tty );
-void rs_start( struct tty_struct *tty );
-
-static __inline__ void rs_check_cts( struct m68k_async_struct *info, int cts )
-{
-	/* update input line counter */
-	info->icount.cts++;
-	wake_up_interruptible(&info->delta_msr_wait);
 	
-	if ((info->flags & ASYNC_CTS_FLOW) && info->tty) {
-		if (info->tty->hw_stopped) {
-			if (cts) {
-#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
-				printk("CTS tx start...");
+#define STD_SERIAL_PORT_DEFNS			\
+	/* UART CLK   PORT IRQ     FLAGS        */			\
+	{ 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS },	/* ttyS0 */	\
+	{ 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS },	/* ttyS1 */	\
+	{ 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS },	/* ttyS2 */	\
+	{ 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS },	/* ttyS3 */
+
+
+#ifdef CONFIG_SERIAL_MANY_PORTS
+#define EXTRA_SERIAL_PORT_DEFNS			\
+	{ 0, BASE_BAUD, 0x1A0, 9, FOURPORT_FLAGS }, 	/* ttyS4 */	\
+	{ 0, BASE_BAUD, 0x1A8, 9, FOURPORT_FLAGS },	/* ttyS5 */	\
+	{ 0, BASE_BAUD, 0x1B0, 9, FOURPORT_FLAGS },	/* ttyS6 */	\
+	{ 0, BASE_BAUD, 0x1B8, 9, FOURPORT_FLAGS },	/* ttyS7 */	\
+	{ 0, BASE_BAUD, 0x2A0, 5, FOURPORT_FLAGS },	/* ttyS8 */	\
+	{ 0, BASE_BAUD, 0x2A8, 5, FOURPORT_FLAGS },	/* ttyS9 */	\
+	{ 0, BASE_BAUD, 0x2B0, 5, FOURPORT_FLAGS },	/* ttyS10 */	\
+	{ 0, BASE_BAUD, 0x2B8, 5, FOURPORT_FLAGS },	/* ttyS11 */	\
+	{ 0, BASE_BAUD, 0x330, 4, ACCENT_FLAGS },	/* ttyS12 */	\
+	{ 0, BASE_BAUD, 0x338, 4, ACCENT_FLAGS },	/* ttyS13 */	\
+	{ 0, BASE_BAUD, 0x000, 0, 0 },	/* ttyS14 (spare) */		\
+	{ 0, BASE_BAUD, 0x000, 0, 0 },	/* ttyS15 (spare) */		\
+	{ 0, BASE_BAUD, 0x100, 12, BOCA_FLAGS },	/* ttyS16 */	\
+	{ 0, BASE_BAUD, 0x108, 12, BOCA_FLAGS },	/* ttyS17 */	\
+	{ 0, BASE_BAUD, 0x110, 12, BOCA_FLAGS },	/* ttyS18 */	\
+	{ 0, BASE_BAUD, 0x118, 12, BOCA_FLAGS },	/* ttyS19 */	\
+	{ 0, BASE_BAUD, 0x120, 12, BOCA_FLAGS },	/* ttyS20 */	\
+	{ 0, BASE_BAUD, 0x128, 12, BOCA_FLAGS },	/* ttyS21 */	\
+	{ 0, BASE_BAUD, 0x130, 12, BOCA_FLAGS },	/* ttyS22 */	\
+	{ 0, BASE_BAUD, 0x138, 12, BOCA_FLAGS },	/* ttyS23 */	\
+	{ 0, BASE_BAUD, 0x140, 12, BOCA_FLAGS },	/* ttyS24 */	\
+	{ 0, BASE_BAUD, 0x148, 12, BOCA_FLAGS },	/* ttyS25 */	\
+	{ 0, BASE_BAUD, 0x150, 12, BOCA_FLAGS },	/* ttyS26 */	\
+	{ 0, BASE_BAUD, 0x158, 12, BOCA_FLAGS },	/* ttyS27 */	\
+	{ 0, BASE_BAUD, 0x160, 12, BOCA_FLAGS },	/* ttyS28 */	\
+	{ 0, BASE_BAUD, 0x168, 12, BOCA_FLAGS },	/* ttyS29 */	\
+	{ 0, BASE_BAUD, 0x170, 12, BOCA_FLAGS },	/* ttyS30 */	\
+	{ 0, BASE_BAUD, 0x178, 12, BOCA_FLAGS },	/* ttyS31 */
+#else
+#define EXTRA_SERIAL_PORT_DEFNS
 #endif
-				info->tty->hw_stopped = 0;
-				rs_start( info->tty );
-				rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
-				return;
-			}
-		} else {
-			if (!cts) {
-				info->tty->hw_stopped = 1;
-				rs_stop( info->tty );
-			}
-		}
-	}
-}
-
-
-#endif /* __KERNEL__ */
 
-#endif /* _M68K_SERIAL_H */
+#define SERIAL_PORT_DFNS		\
+	STD_SERIAL_PORT_DEFNS		\
+	EXTRA_SERIAL_PORT_DEFNS
diff -urN linux-2.2.8-pre7/include/asm-m68k/setup.h linux/include/asm-m68k/setup.h
--- linux-2.2.8-pre7/include/asm-m68k/setup.h	Tue Jan 19 10:58:34 1999
+++ linux/include/asm-m68k/setup.h	Mon Dec  3 18:46:55 2001
@@ -39,6 +39,8 @@
 #define MACH_MVME16x  7
 #define MACH_BVME6000 8
 #define MACH_HP300    9
+#define MACH_Q40     10
+#define MACH_SUN3X   11
 
 #ifdef __KERNEL__
 
@@ -49,7 +51,9 @@
 #if !defined(CONFIG_AMIGA)
 #  define MACH_IS_AMIGA (0)
 #elif defined(CONFIG_ATARI) || defined(CONFIG_MAC) || defined(CONFIG_APOLLO) \
-	|| defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000) || defined(CONFIG_HP300)
+	|| defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000)               \
+	|| defined(CONFIG_HP300) || defined(CONFIG_Q40)                      \
+	|| defined(CONFIG_SUN3X) || defined(CONFIG_MVME147)
 #  define MACH_IS_AMIGA (m68k_machtype == MACH_AMIGA)
 #else
 #  define MACH_AMIGA_ONLY
@@ -60,7 +64,9 @@
 #if !defined(CONFIG_ATARI)
 #  define MACH_IS_ATARI (0)
 #elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_APOLLO) \
-	|| defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000) || defined(CONFIG_HP300)
+	|| defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000)               \
+	|| defined(CONFIG_HP300) || defined(CONFIG_Q40)                      \
+	|| defined(CONFIG_SUN3X) || defined(CONFIG_MVME147)
 #  define MACH_IS_ATARI (m68k_machtype == MACH_ATARI)
 #else
 #  define MACH_ATARI_ONLY
@@ -71,7 +77,9 @@
 #if !defined(CONFIG_MAC)
 #  define MACH_IS_MAC (0)
 #elif defined(CONFIG_AMIGA) || defined(CONFIG_ATARI) || defined(CONFIG_APOLLO) \
-	|| defined(CONFIG_HP300) || defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000)
+	|| defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000)                 \
+	|| defined(CONFIG_HP300) || defined(CONFIG_Q40)                        \
+	|| defined(CONFIG_SUN3X) || defined(CONFIG_MVME147)
 #  define MACH_IS_MAC (m68k_machtype == MACH_MAC)
 #else
 #  define MACH_MAC_ONLY
@@ -88,7 +96,9 @@
 #if !defined (CONFIG_APOLLO)
 #  define MACH_IS_APOLLO (0)
 #elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \
-	|| defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000) || defined(CONFIG_HP300)
+	|| defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000)              \
+	|| defined(CONFIG_HP300) || defined(CONFIG_Q40)                     \
+	|| defined(CONFIG_SUN3X) || defined(CONFIG_MVME147)
 #  define MACH_IS_APOLLO (m68k_machtype == MACH_APOLLO)
 #else
 #  define MACH_APOLLO_ONLY
@@ -96,10 +106,25 @@
 #  define MACH_TYPE (MACH_APOLLO)
 #endif
 
+#if !defined (CONFIG_MVME147)
+#  define MACH_IS_MVME147 (0)
+#elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \
+	|| defined(CONFIG_APOLLO) || defined(CONFIG_BVME6000)               \
+	|| defined(CONFIG_HP300) || defined(CONFIG_Q40)                     \
+	|| defined(CONFIG_SUN3X) || defined(CONFIG_MVME16x)
+#  define MACH_IS_MVME147 (m68k_machtype == MACH_MVME147)
+#else
+#  define MACH_MVME147_ONLY
+#  define MACH_IS_MVME147 (1)
+#  define MACH_TYPE (MACH_MVME147)
+#endif
+
 #if !defined (CONFIG_MVME16x)
 #  define MACH_IS_MVME16x (0)
 #elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \
-	|| defined(CONFIG_APOLLO) || defined(CONFIG_BVME6000) || defined(CONFIG_HP300)
+	|| defined(CONFIG_APOLLO) || defined(CONFIG_BVME6000)               \
+	|| defined(CONFIG_HP300) || defined(CONFIG_Q40)                     \
+	|| defined(CONFIG_SUN3X) || defined(CONFIG_MVME147)
 #  define MACH_IS_MVME16x (m68k_machtype == MACH_MVME16x)
 #else
 #  define MACH_MVME16x_ONLY
@@ -110,7 +135,9 @@
 #if !defined (CONFIG_BVME6000)
 #  define MACH_IS_BVME6000 (0)
 #elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \
-	|| defined(CONFIG_APOLLO) || defined(CONFIG_MVME16x) || defined(CONFIG_HP300)
+	|| defined(CONFIG_APOLLO) || defined(CONFIG_MVME16x)                \
+	|| defined(CONFIG_HP300) || defined(CONFIG_Q40)                     \
+	|| defined(CONFIG_SUN3X) || defined(CONFIG_MVME147)
 #  define MACH_IS_BVME6000 (m68k_machtype == MACH_BVME6000)
 #else
 #  define MACH_BVME6000_ONLY
@@ -121,12 +148,40 @@
 #if !defined (CONFIG_HP300)
 #  define MACH_IS_HP300 (0)
 #elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \
-	|| defined(CONFIG_APOLLO) || defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000)
-#  define MAC_IS_HP300 (m68k_machtype == MACH_HP300)
+	|| defined(CONFIG_APOLLO) || defined(CONFIG_MVME16x) \
+	|| defined(CONFIG_BVME6000) || defined(CONFIG_Q40) \
+	|| defined(CONFIG_SUN3X) || defined(CONFIG_MVME147)
+#  define MACH_IS_HP300 (m68k_machtype == MACH_HP300)
 #else
 #  define MACH_HP300_ONLY
 #  define MACH_IS_HP300 (1)
 #  define MACH_TYPE (MACH_HP300)
+#endif
+
+#if !defined (CONFIG_Q40)
+#  define MACH_IS_Q40 (0)
+#elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \
+	|| defined(CONFIG_APOLLO) || defined(CONFIG_MVME16x)                \
+	|| defined(CONFIG_BVME6000) || defined(CONFIG_HP300)                \
+	|| defined(CONFIG_SUN3X) || defined(CONFIG_MVME147)
+#  define MACH_IS_Q40 (m68k_machtype == MACH_Q40)
+#else
+#  define MACH_Q40_ONLY
+#  define MACH_IS_Q40 (1)
+#  define MACH_TYPE (MACH_Q40)
+#endif
+
+#if !defined (CONFIG_SUN3X)
+#  define MACH_IS_SUN3X (0)
+#elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \
+	|| defined(CONFIG_APOLLO) || defined(CONFIG_MVME16x)                \
+	|| defined(CONFIG_BVME6000) || defined(CONFIG_HP300)                \
+	|| defined(CONFIG_Q40) || defined(CONFIG_MVME147)
+#  define MACH_IS_SUN3X (m68k_machtype == MACH_SUN3X)
+#else
+#  define CONFIG_SUN3X_ONLY
+#  define MACH_IS_SUN3X (1)
+#  define MACH_TYPE (MACH_SUN3X)
 #endif
 
 #ifndef MACH_TYPE
diff -urN linux-2.2.8-pre7/include/asm-m68k/sun3x.h linux/include/asm-m68k/sun3x.h
--- linux-2.2.8-pre7/include/asm-m68k/sun3x.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/sun3x.h	Mon Dec  3 18:46:55 2001
@@ -0,0 +1,24 @@
+#ifndef SUN3X_H
+#define SUN3X_H
+
+/* hardware addresses */
+#define SUN3X_IOMMU       0x60000000
+#define SUN3X_ENAREG      0x61000000
+#define SUN3X_INTREG      0x61001400
+#define SUN3X_DIAGREG     0x61001800
+#define SUN3X_ZS1         0x62000000
+#define SUN3X_ZS2         0x62002000
+#define SUN3X_LANCE       0x65002000
+#define SUN3X_EEPROM      0x64000000
+#define SUN3X_IDPROM      0x640007d8
+#define SUN3X_VIDEO_BASE  0x50000000
+#define SUN3X_VIDEO_P4ID  0x50300000
+#define SUN3X_ESP_BASE	  0x66000000
+#define SUN3X_ESP_DMA	  0x66001000
+
+/* some NVRAM addresses */
+#define SUN3X_EEPROM_CONS 	(SUN3X_EEPROM + 0x1f)
+#define SUN3X_EEPROM_PORTA	(SUN3X_EEPROM + 0x58)
+#define SUN3X_EEPROM_PORTB	(SUN3X_EEPROM + 0x60)
+
+#endif
diff -urN linux-2.2.8-pre7/include/asm-m68k/system.h linux/include/asm-m68k/system.h
--- linux-2.2.8-pre7/include/asm-m68k/system.h	Tue Jan 19 10:58:34 1999
+++ linux/include/asm-m68k/system.h	Mon Dec  3 18:46:55 2001
@@ -43,12 +43,14 @@
  * the mm structures are shared in d2 (to avoid atc flushing).
  */
 asmlinkage void resume(void);
-#define switch_to(prev,next) { \
+#define switch_to(prev,next,last) { \
   register void *_prev __asm__ ("a0") = (prev); \
   register void *_next __asm__ ("a1") = (next); \
+  register void *_last __asm__ ("d1"); \
   __asm__ __volatile__("jbsr " SYMBOL_NAME_STR(resume) \
-		       : : "a" (_prev), "a" (_next) \
+		       : "=d" (_last) : "a" (_prev), "a" (_next) \
 		       : "d0", "d1", "d2", "d3", "d4", "d5", "a0", "a1"); \
+  (last) = _last; \
 }
 
 #define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
@@ -66,6 +68,8 @@
 #define __cli() __asm__ __volatile__ ("oriw  #0x0700,%/sr": : : "memory")
 #define nop() __asm__ __volatile__ ("nop"::)
 #define mb()  __asm__ __volatile__ (""   : : :"memory")
+#define rmb()  __asm__ __volatile__ (""   : : :"memory")
+#define wmb()  __asm__ __volatile__ (""   : : :"memory")
 
 #define __save_flags(x) \
 __asm__ __volatile__("movew %/sr,%0":"=d" (x) : /* no input */ :"memory")
diff -urN linux-2.2.8-pre7/include/asm-m68k/uaccess.h linux/include/asm-m68k/uaccess.h
--- linux-2.2.8-pre7/include/asm-m68k/uaccess.h	Tue Jan  5 11:20:43 1999
+++ linux/include/asm-m68k/uaccess.h	Mon Dec  3 18:46:55 2001
@@ -759,6 +759,10 @@
 #define __copy_from_user(to, from, n) copy_from_user(to, from, n)
 #define __copy_to_user(to, from, n) copy_to_user(to, from, n)
 
+#define copy_to_user_ret(to,from,n,retval) ({ if (copy_to_user(to,from,n)) return retval; })
+
+#define copy_from_user_ret(to,from,n,retval) ({ if (copy_from_user(to,from,n)) return retval; })
+
 /*
  * Copy a null terminated string from userspace.
  */
diff -urN linux-2.2.8-pre7/include/asm-ppc/processor.h linux/include/asm-ppc/processor.h
--- linux-2.2.8-pre7/include/asm-ppc/processor.h	Mon Dec  3 18:46:28 2001
+++ linux/include/asm-ppc/processor.h	Mon Dec  3 18:46:55 2001
@@ -235,7 +235,6 @@
 	double		fpr[32];	/* Complete floating point set */
 	unsigned long	fpscr_pad;	/* fpr ... fpscr must be contiguous */
 	unsigned long	fpscr;		/* Floating point status */
-	unsigned long	smp_fork_ret;
 };
 
 #define INIT_SP		(sizeof(init_stack) + (unsigned long) &init_stack)
@@ -247,7 +246,7 @@
 	(struct pt_regs *)INIT_SP - 1, /* regs */ \
 	KERNEL_DS, /*fs*/ \
 	0, /* last_syscall */ \
-	{0}, 0, 0, 0 \
+	{0}, 0, 0 \
 }
 
 /*
diff -urN linux-2.2.8-pre7/include/asm-ppc/raven.h linux/include/asm-ppc/raven.h
--- linux-2.2.8-pre7/include/asm-ppc/raven.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-ppc/raven.h	Mon Dec  3 18:46:55 2001
@@ -0,0 +1,33 @@
+/*
+ *  asm-ppc/raven.h -- Raven MPIC chip.
+ *
+ *  Copyright (C) 1998 Johnnie Peters
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive
+ *  for more details.
+ */
+
+#ifndef _ASMPPC_RAVEN_H
+#define _ASMPPC_RAVEN_H
+
+#define MVME2600_INT_SIO		0
+#define MVME2600_INT_FALCN_ECC_ERR	1
+#define MVME2600_INT_PCI_ETHERNET	2
+#define MVME2600_INT_PCI_SCSI		3
+#define MVME2600_INT_PCI_GRAPHICS	4
+#define MVME2600_INT_PCI_VME0		5
+#define MVME2600_INT_PCI_VME1		6
+#define MVME2600_INT_PCI_VME2		7
+#define MVME2600_INT_PCI_VME3		8
+#define MVME2600_INT_PCI_INTA		9
+#define MVME2600_INT_PCI_INTB		10
+#define MVME2600_INT_PCI_INTC 		11
+#define MVME2600_INT_PCI_INTD 		12
+#define MVME2600_INT_LM_SIG0		13
+#define MVME2600_INT_LM_SIG1		14
+
+extern struct hw_interrupt_type raven_pic;
+
+extern int raven_init(void);
+#endif _ASMPPC_RAVEN_H
diff -urN linux-2.2.8-pre7/include/asm-ppc/system.h linux/include/asm-ppc/system.h
--- linux-2.2.8-pre7/include/asm-ppc/system.h	Mon Dec  3 18:46:28 2001
+++ linux/include/asm-ppc/system.h	Mon Dec  3 18:46:55 2001
@@ -80,11 +80,14 @@
 extern void note_scsi_host(struct device_node *, void *);
 
 struct task_struct;
-extern void switch_to(struct task_struct *prev, struct task_struct *next);
+#define switch_to(prev,next,last) _switch_to((prev),(next),&(last))
+extern void _switch_to(struct task_struct *, struct task_struct *,
+		       struct task_struct **);
 
 struct thread_struct;
-extern void _switch(struct thread_struct *prev, struct thread_struct *next,
-		    unsigned long context);
+extern struct task_struct *_switch(struct thread_struct *prev,
+				     struct thread_struct *next,
+				     unsigned long context);
 
 struct pt_regs;
 extern void dump_regs(struct pt_regs *);
diff -urN linux-2.2.8-pre7/include/asm-sparc/smp.h linux/include/asm-sparc/smp.h
--- linux-2.2.8-pre7/include/asm-sparc/smp.h	Wed Mar 10 16:53:37 1999
+++ linux/include/asm-sparc/smp.h	Mon Dec  3 18:46:55 2001
@@ -157,6 +157,7 @@
 #endif
 
 #define smp_processor_id() hard_smp_processor_id()
+/* XXX We really need to implement this now.  -DaveM */
 extern __inline__ void smp_send_reschedule(int cpu) { }
 extern __inline__ void smp_send_stop(void) { }
 
diff -urN linux-2.2.8-pre7/include/asm-sparc/system.h linux/include/asm-sparc/system.h
--- linux-2.2.8-pre7/include/asm-sparc/system.h	Thu Apr 22 19:24:52 1999
+++ linux/include/asm-sparc/system.h	Mon Dec  3 18:46:55 2001
@@ -1,4 +1,4 @@
-/* $Id: system.h,v 1.73 1999/04/20 13:22:49 anton Exp $ */
+/* $Id: system.h,v 1.74 1999/05/08 03:03:14 davem Exp $ */
 #include <linux/config.h>
 
 #ifndef __SPARC_SYSTEM_H
@@ -84,8 +84,15 @@
 #define SWITCH_DO_LAZY_FPU if(last_task_used_math != next) next->tss.kregs->psr&=~PSR_EF;
 #endif
 
-	/* Much care has gone into this code, do not touch it. */
-#define switch_to(prev, next) do {							\
+	/* Much care has gone into this code, do not touch it.
+	 *
+	 * We need to loadup regs l0/l1 for the newly forked child
+	 * case because the trap return path relies on those registers
+	 * holding certain values, gcc is told that they are clobbered.
+	 * Gcc needs registers for 3 values in and 1 value out, so we
+	 * clobber every non-fixed-usage register besides l2/l3/o4/o5.  -DaveM
+	 */
+#define switch_to(prev, next, last) do {						\
 	__label__ here;									\
 	register unsigned long task_pc asm("o7");					\
 	extern struct task_struct *current_set[NR_CPUS];				\
@@ -103,21 +110,22 @@
 	next->mm->cpu_vm_mask |= (1 << smp_processor_id());				\
 	task_pc = ((unsigned long) &&here) - 0x8;					\
 	__asm__ __volatile__(								\
+	"mov	%%g6, %%g3\n\t"								\
 	"rd	%%psr, %%g4\n\t"							\
-	"std	%%sp, [%%g6 + %3]\n\t"							\
+	"std	%%sp, [%%g6 + %4]\n\t"							\
 	"rd	%%wim, %%g5\n\t"							\
 	"wr	%%g4, 0x20, %%psr\n\t"							\
 	"nop\n\t"									\
-	"std	%%g4, [%%g6 + %2]\n\t"							\
-	"ldd	[%1 + %2], %%g4\n\t"							\
-	"mov	%1, %%g6\n\t"								\
+	"std	%%g4, [%%g6 + %3]\n\t"							\
+	"ldd	[%2 + %3], %%g4\n\t"							\
+	"mov	%2, %%g6\n\t"								\
 	".globl	patchme_store_new_current\n"						\
 "patchme_store_new_current:\n\t"							\
-	"st	%1, [%0]\n\t"								\
+	"st	%2, [%1]\n\t"								\
 	"wr	%%g4, 0x20, %%psr\n\t"							\
 	"nop\n\t"									\
 	"nop\n\t"									\
-	"ldd	[%%g6 + %3], %%sp\n\t"							\
+	"ldd	[%%g6 + %4], %%sp\n\t"							\
 	"wr	%%g5, 0x0, %%wim\n\t"							\
 	"ldd	[%%sp + 0x00], %%l0\n\t"						\
 	"ldd	[%%sp + 0x38], %%i6\n\t"						\
@@ -125,11 +133,13 @@
 	"nop\n\t"									\
 	"nop\n\t"									\
 	"jmpl	%%o7 + 0x8, %%g0\n\t"							\
-	" nop\n\t" : : "r" (&(current_set[hard_smp_processor_id()])), "r" (next),	\
+	" mov	%%g3, %0\n\t"								\
+        : "=&r" (last)									\
+        : "r" (&(current_set[hard_smp_processor_id()])), "r" (next),			\
 	  "i" ((const unsigned long)(&((struct task_struct *)0)->tss.kpsr)),		\
 	  "i" ((const unsigned long)(&((struct task_struct *)0)->tss.ksp)),		\
 	  "r" (task_pc)									\
-	: "g1", "g2", "g3", "g4", "g5", "g7", "l2", "l3",				\
+	: "g1", "g2", "g3", "g4", "g5", "g7", "l0", "l1",				\
 	"l4", "l5", "l6", "l7", "i0", "i1", "i2", "i3", "i4", "i5", "o0", "o1", "o2",	\
 	"o3");										\
 here:  } while(0)
diff -urN linux-2.2.8-pre7/include/asm-sparc64/mmu_context.h linux/include/asm-sparc64/mmu_context.h
--- linux-2.2.8-pre7/include/asm-sparc64/mmu_context.h	Wed Mar 10 16:53:38 1999
+++ linux/include/asm-sparc64/mmu_context.h	Mon Dec  3 18:46:55 2001
@@ -1,4 +1,4 @@
-/* $Id: mmu_context.h,v 1.34 1999/01/11 13:45:44 davem Exp $ */
+/* $Id: mmu_context.h,v 1.35 1999/05/08 03:03:20 davem Exp $ */
 #ifndef __SPARC64_MMU_CONTEXT_H
 #define __SPARC64_MMU_CONTEXT_H
 
@@ -13,7 +13,6 @@
 #ifndef __ASSEMBLY__
 
 extern unsigned long tlb_context_cache;
-extern spinlock_t scheduler_lock;
 extern unsigned long mmu_context_bmap[];
 
 #define CTX_VERSION_SHIFT	(PAGE_SHIFT - 3)
@@ -38,11 +37,9 @@
 #define destroy_context(__mm)	do { 						\
 	if ((__mm)->context != NO_CONTEXT &&					\
 	    atomic_read(&(__mm)->count) == 1) { 				\
-		spin_lock(&scheduler_lock); 					\
 		if (!(((__mm)->context ^ tlb_context_cache) & CTX_VERSION_MASK))\
 			clear_bit((__mm)->context & ~(CTX_VERSION_MASK),	\
 				  mmu_context_bmap);				\
-		spin_unlock(&scheduler_lock); 					\
 		(__mm)->context = NO_CONTEXT; 					\
 		if(current->mm == (__mm)) {					\
 			current->tss.ctx = 0;					\
@@ -126,9 +123,7 @@
 #define activate_context(__tsk)		\
 do {	flushw_user();			\
 	(__tsk)->mm->cpu_vm_mask = 0;	\
-	spin_lock(&scheduler_lock);	\
 	__get_mmu_context(__tsk);	\
-	spin_unlock(&scheduler_lock);	\
 	(__tsk)->mm->cpu_vm_mask = (1UL<<smp_processor_id()); \
 } while(0)
 
diff -urN linux-2.2.8-pre7/include/asm-sparc64/system.h linux/include/asm-sparc64/system.h
--- linux-2.2.8-pre7/include/asm-sparc64/system.h	Wed Mar 10 16:53:38 1999
+++ linux/include/asm-sparc64/system.h	Mon Dec  3 18:46:55 2001
@@ -1,4 +1,4 @@
-/* $Id: system.h,v 1.48 1999/01/02 16:50:28 davem Exp $ */
+/* $Id: system.h,v 1.50 1999/05/08 03:03:22 davem Exp $ */
 #ifndef __SPARC64_SYSTEM_H
 #define __SPARC64_SYSTEM_H
 
@@ -48,7 +48,7 @@
 ({	unsigned long retval; \
 	__asm__ __volatile__("rdpr	%%pil, %0\n\t" \
 			     "wrpr	%1, %%pil" \
-			     : "=r" (retval) \
+			     : "=&r" (retval) \
 			     : "r" (__new_pil) \
 			     : "memory"); \
 	retval; \
@@ -127,21 +127,14 @@
 
 	/* See what happens when you design the chip correctly?
 	 *
-	 * XXX What we are doing here assumes a lot about gcc reload
-	 * XXX internals, it heavily risks compiler aborts due to
-	 * XXX forbidden registers being spilled.  Rewrite me...  -DaveM
-	 *
-	 * SMP NOTE: At first glance it looks like there is a tiny
-	 *           race window here at the end.  The possible problem
-	 *           would be if a tlbcachesync MONDO vector got delivered
-	 *           to us right before we set the final %g6 thread reg
-	 *           value.  But that is impossible since only the holder
-	 *           of scheduler_lock can send a tlbcachesync MONDO and
-	 *           by definition we hold it right now.  Normal tlb
-	 *           flush xcalls can come in, but those are safe and do
-	 *           not reference %g6.
+	 * We tell gcc we clobber all non-fixed-usage registers except
+	 * for l0/l1.  It will use one for 'next' and the other to hold
+	 * the output value of 'last'.  'next' is not referenced again
+	 * past the invocation of switch_to in the scheduler, so we need
+	 * not preserve it's value.  Hairy, but it lets us remove 2 loads
+	 * and 2 stores in this critical code path.  -DaveM
 	 */
-#define switch_to(prev, next)							\
+#define switch_to(prev, next, last)						\
 do {	if (current->tss.flags & SPARC_FLAG_PERFCTR) {				\
 		unsigned long __tmp;						\
 		read_pcr(__tmp);						\
@@ -157,26 +150,23 @@
 	__get_mmu_context(next);						\
 	(next)->mm->cpu_vm_mask |= (1UL << smp_processor_id());			\
 	__asm__ __volatile__(							\
+	"mov	%%g6, %%g5\n\t"							\
 	"wrpr	%%g0, 0x95, %%pstate\n\t"					\
-	"stx	%%l0, [%%sp + 2047 + 0x60]\n\t"					\
-	"stx	%%l1, [%%sp + 2047 + 0x68]\n\t"					\
 	"stx	%%i6, [%%sp + 2047 + 0x70]\n\t"					\
 	"stx	%%i7, [%%sp + 2047 + 0x78]\n\t"					\
 	"rdpr	%%wstate, %%o5\n\t"						\
-	"stx	%%o6, [%%g6 + %2]\n\t"						\
-	"sth	%%o5, [%%g6 + %1]\n\t"						\
+	"stx	%%o6, [%%g6 + %3]\n\t"						\
+	"sth	%%o5, [%%g6 + %2]\n\t"						\
 	"rdpr	%%cwp, %%o5\n\t"						\
-	"sth	%%o5, [%%g6 + %4]\n\t"						\
-	"mov	%0, %%g6\n\t"							\
-	"lduh	[%0 + %4], %%g1\n\t"						\
+	"sth	%%o5, [%%g6 + %5]\n\t"						\
+	"mov	%1, %%g6\n\t"							\
+	"lduh	[%1 + %5], %%g1\n\t"						\
 	"wrpr	%%g1, %%cwp\n\t"						\
-	"ldx	[%%g6 + %2], %%o6\n\t"						\
-	"lduh	[%%g6 + %1], %%o5\n\t"						\
-	"lduh	[%%g6 + %3], %%o7\n\t"						\
+	"ldx	[%%g6 + %3], %%o6\n\t"						\
+	"lduh	[%%g6 + %2], %%o5\n\t"						\
+	"lduh	[%%g6 + %4], %%o7\n\t"						\
 	"mov	%%g6, %%l2\n\t"							\
 	"wrpr	%%o5, 0x0, %%wstate\n\t"					\
-	"ldx	[%%sp + 2047 + 0x60], %%l0\n\t"					\
-	"ldx	[%%sp + 2047 + 0x68], %%l1\n\t"					\
 	"ldx	[%%sp + 2047 + 0x70], %%i6\n\t"					\
 	"ldx	[%%sp + 2047 + 0x78], %%i7\n\t"					\
 	"wrpr	%%g0, 0x94, %%pstate\n\t"					\
@@ -184,8 +174,8 @@
 	"wrpr	%%g0, 0x96, %%pstate\n\t"					\
 	"andcc	%%o7, 0x100, %%g0\n\t"						\
 	"bne,pn	%%icc, ret_from_syscall\n\t"					\
-	" nop\n\t"								\
-	: 									\
+	" mov	%%g5, %0\n\t"							\
+	: "=&r" (last)								\
 	: "r" (next),								\
 	  "i" ((const unsigned long)(&((struct task_struct *)0)->tss.wstate)),	\
 	  "i" ((const unsigned long)(&((struct task_struct *)0)->tss.ksp)),	\
diff -urN linux-2.2.8-pre7/include/asm-sparc64/uaccess.h linux/include/asm-sparc64/uaccess.h
--- linux-2.2.8-pre7/include/asm-sparc64/uaccess.h	Tue Oct 27 09:52:21 1998
+++ linux/include/asm-sparc64/uaccess.h	Mon Dec  3 18:46:55 2001
@@ -1,4 +1,4 @@
-/* $Id: uaccess.h,v 1.28 1998/10/11 06:58:34 davem Exp $ */
+/* $Id: uaccess.h,v 1.29 1999/05/08 03:03:25 davem Exp $ */
 #ifndef _ASM_UACCESS_H
 #define _ASM_UACCESS_H
 
@@ -41,12 +41,9 @@
 
 #define segment_eq(a,b)  ((a).seg == (b).seg)
 
-extern spinlock_t scheduler_lock;
-
 #define set_fs(val)								\
 do {										\
 	if (current->tss.current_ds.seg != val.seg) {				\
-		spin_lock(&scheduler_lock);					\
 		current->tss.current_ds = (val);				\
 		if (segment_eq((val), KERNEL_DS)) {				\
 			flushw_user ();						\
@@ -56,7 +53,6 @@
 		}								\
 		spitfire_set_secondary_context(current->tss.ctx); 		\
 		__asm__ __volatile__("flush %g6");				\
-		spin_unlock(&scheduler_lock);					\
 	}									\
 } while(0)
 
diff -urN linux-2.2.8-pre7/init/main.c linux/init/main.c
--- linux-2.2.8-pre7/init/main.c	Mon Dec  3 18:46:28 2001
+++ linux/init/main.c	Mon Dec  3 18:46:55 2001
@@ -46,6 +46,10 @@
 #include <linux/apm_bios.h>
 #endif
 
+#ifdef CONFIG_MAC
+extern void nubus_init(void);
+#endif
+
 /*
  * Versions of gcc older than that listed below may actually compile
  * and link okay, but the end product can have subtle run time bugs.
@@ -789,7 +793,8 @@
 #endif
 #if defined(CONFIG_A4000T_SCSI) || defined(CONFIG_WARPENGINE_SCSI) \
 	    || defined(CONFIG_A4091_SCSI) || defined(CONFIG_MVME16x_SCSI) \
-	    || defined(CONFIG_BVME6000_SCSI)
+	    || defined(CONFIG_BVME6000_SCSI) \
+	    || defined(CONFIG_BLZ603EPLUS_SCSI)
         { "53c7xx=", ncr53c7xx_setup },
 #endif
 #if defined(CONFIG_A3000_SCSI) || defined(CONFIG_A2091_SCSI) \
@@ -1276,6 +1281,9 @@
 #endif
 #ifdef CONFIG_DIO
 	dio_init();
+#endif
+#ifdef CONFIG_MAC
+	nubus_init();
 #endif
 
 	/* Networking initialization needs a process context */ 
diff -urN linux-2.2.8-pre7/mm/filemap.c linux/mm/filemap.c
--- linux-2.2.8-pre7/mm/filemap.c	Mon Dec  3 18:46:28 2001
+++ linux/mm/filemap.c	Mon Dec  3 18:46:55 2001
@@ -937,7 +937,7 @@
 	unsigned long old_page, new_page;
 
 	new_page = 0;
-	offset = (address - area->vm_start + area->vm_offset) & PAGE_MASK;
+	offset = (address & PAGE_MASK) - area->vm_start + area->vm_offset;
 	if (offset >= inode->i_size && (area->vm_flags & VM_SHARED) && area->vm_mm == current->mm)
 		goto no_page;
 
